wtorek, 31 grudnia 2013

Kalendarz w oracle

Z racji tego, że nowy rok się zbliża, postanowiłem napisać zapytanie, które zwraca dni w bieżącym miesiącu - taki kalendarzyk dla danego miesiąca. Poniżej jest przedstawiony kod. Proszę zauważyć, że pierwszy dzień tygodnia zaczyna się w niedzielę. Dla innej kultury będzie inne zapytanie.

with x
      as (
    select *
      from (
    select to_char(trunc(sysdate,'mm')+level-1,'iw') wk,
           to_char(trunc(sysdate,'mm')+level-1,'dd') dm,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'d')) dw,
           to_char(trunc(sysdate,'mm')+level-1,'mm') curr_mth,
           to_char(sysdate,'mm') mth
      from dual
     connect by level <= 31
           )
     where curr_mth = mth
    )
    select max(case dw when 2 then dm end) Mo,
           max(case dw when 3 then dm end) Tu,
           max(case dw when 4 then dm end) We,
           max(case dw when 5 then dm end) Th,
           max(case dw when 6 then dm end) Fr,
           max(case dw when 7 then dm end) Sa,
           max(case dw when 1 then dm end) Su
      from x
     group by wk
     order by wk
;
Dla miesiąca grudzień mamy taki wynik:
Niestety dla ostatnich dni roku (30 i 31 grudnia) mamy problem ze standaryzacją numerów miesiąca w roku. Dla tych dwóch ostatnich dni, numer tygodnia w roku jest 1 dla parametru IW (więcej o parametrach daty znajdują się w funkcji to_char). Będziemy musieli skorzystać z parametru WW.
select *
      from (
    select to_char(trunc(sysdate,'mm')+level-1,'iw') wk,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'ww')) wn,
           to_char(trunc(sysdate,'mm')+level-1,'dd') dm,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'d')) dw,
           to_char(trunc(sysdate,'mm')+level-1,'mm') curr_mth,
           to_char(sysdate,'mm') mth
      from dual
     connect by level <= 31
           )
     where curr_mth = mth
;
I na końcu wystarczy zgrupować
with x
      as (
    select *
      from (
    select to_char(trunc(sysdate,'mm')+level-1,'iw') wk,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'ww')) wn,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'dd')) dm,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'d')) dw,
           to_char(trunc(sysdate,'mm')+level-1,'mm') curr_mth,
           to_char(sysdate,'mm') mth
      from dual
     connect by level <= 31
           )
     where curr_mth = mth
    )
    select 
           --wk,
           --max(wn) wna,
           max(case dw when 2 then dm end) Mo,
           max(case dw when 3 then dm end) Tu,
           max(case dw when 4 then dm end) We,
           max(case dw when 5 then dm end) Th,
           max(case dw when 6 then dm end) Fr,
           max(case dw when 7 then dm end) Sa,
           max(case dw when 1 then dm end) Su
      from x
     group by wk
     order by max(wn)
;
A rezultat takiego zapytania wygląda następująco:

poniedziałek, 30 grudnia 2013

Kowale 2.0

Ostatnio oglądałem filmik przedstawiający modelowanie w stali. Ze stalą zawsze kojarzyły mi się wielkie i ciężkie konstrukcie mostów jak Golden Gate Bridge ( zwany również Mostem Samobójców). Ale konstrukcje stalowe mogą być na tyle lekkie i elastyczne, że mogą być modelowane poprzez ciśnienie. Prezenter 'nowej stali' przedstawia nie tylko technologię, ale również sposób projektowania mebli ze stali. Jednym z mebli przyszłości jest Polski Ludowy Obiekt Pompowany Powietrzem:


Zapraszam do obejrzenia filmiku:


sobota, 28 grudnia 2013

Odliczanie do Nowego Roku w PowerShell

Skoro już wcześniej zrobiłem odliczacz do świąt Bożego Narodzenia, to teraz będzie odliczacz do Nowego Roku.
function  Countdown-NewYear
{
    $dateNow = [DateTime]::Now
    $dateNewYear = [DateTime]::ParseExact( [string]
($dateNow.Year+1) + "-01-01-00-00-01", "yyyy-MM-dd-hh-mm-ss", $null) 
 
    return $dateNewYear - $dateNow
}

$newYearCounter = Countdown-NewYear
Write-Host "There are $($newYearCounter.Days) days and $($newYearCounter.Hours) hours until New Year"

Kod jest prawie identyczny jak w poprzednim odliczaczu. Tylko teraz dokładność czasu będzie uzależniona od odległości. Jeżeli do Nowego Roku będzie więcej niż 1 dzień to odliczacz przedstawi wartość w jednostkach dni, jeżeli będzie mniej niż jedna godzina, ale więcej niż jedna minuta to będzie w minutach, itp.
function ToCountdownString
{
    param
    (
        [timespan] $timeSpan
    )
    if($timeSpan.Days -gt 1)
    {
        return "$($timeSpan.Days) days"
    }
    if($timeSpan.Hours -gt 1)
    {
        $timeRemains = $timeSpan.Days * 24 + $timeSpan.Hours
        return "$timeRemains hours"
    }

    if($timeSpan.Minutes -gt 1)
    {
        $timeRemains = $timeSpan.Hours * 60 + $timeSpan.Minutes
         return "$timeRemains minutes"
    }

    if($timeSpan.Seconds -gt 1)
    {
        $timeRemains = $timeSpan.Minutes * 60 + $timeSpan.Seconds
         return "$timeRemains seconds"
    }

    $timeRemains = $timeSpan.Seconds * 1000 + $timeSpan.Milliseconds
    return "$timeRemains milliseconds"
}
Kod wywołania wygląda następująco:
$newYearCounter = Countdown-NewYear
$countdown = ToCountdownString -timeSpan $newYearCounter 
Write-Host "There are $countdown until New Year"
Nie przesadzajmy, nie musisz sprawdzać tego kodu w Sylwestra:) Idź i spędź ten czas z przyjaciółmi, ukochaną osobą albo z rodziną.

piątek, 20 grudnia 2013

Base64 z pliku

Raz na jakiś czas fajnie jest napisać jakiegoś jednolinijkowca :)
To tym razem proste przedstawię Ci pobieranie zawartości pliku zapisanego w formacie Base64 w PowerShellu:
function Get-Base64FromFile($Path)
{
    return [Convert]::ToBase64String((Get-Content $Path -Encoding Byte))
}
Wywołanie jest następujące:
Get-Base64FromFile file 
Możemy sprawdzić czy za pomocą funkcji odwrotnej można uzyskać zawartość pliku. Pomocne będą nam dwie funkcje:
function Get-ContentFromBase64($base64Str)
{
    return [Convert]::FromBase64String($base64Str)
}

[Reflection.Assembly]::LoadWithPartialName("System.Text")
function Get-StringFromContent( [byte[]] $content)
{

    return [System.Text.Encoding]::UTF8.GetString($content)
}
i sprawdzamy zawartość w następujący sposób:
Get-StringFromContent( Get-ContentFromBase64( Get-Base64FromFile file ))

sobota, 14 grudnia 2013

Czas do świąt w PowerShell

Święta coraz szybciej się zbliżają, ale za ile dni będą te święta? Z pomocą (jak zawsze) na odpowiedzenie przychodzi mi powershell :)

function  Countdown-Xmas
{
    $dateNow = [DateTime]::Now
    $dateXmas = [DateTime]::ParseExact( 
[string]($dateNow.Year) + "/12/25", "yyyy/MM/dd", $null) 
    
    if($dateNow -gt $dateXmas)
    {
        $dateXmas = $dateXmas.AddYears(1)
    }   
    
    return $dateXmas - $dateNow
}

A wywołanie wygląda następująco:

$xmasCounter = Countdown-Xmas
Write-Host "There are $($xmasCounter.Days) days and $($xmasCounter.Hours) hours until Xmas"


Enkapsulacja widoku raportu ETL

I znów post z cyklu wstęp do ETL. Tym razem opowiem Ci o końcówce procesu, która jest tą przyjemniejszą częścią. Wartość procesu ETL można ocenić na podstawie jego wizualizacji wyników. Na ogół cały proces ETL jest niewidoczny dla użytkownika. Wygenerowany raport z procesu ETL jest jedynym etapem w cyklu ETL, gdzie managerowie wyższego szczebla mogą dokonać oceny tego cyklu. Aby dane mogły być odpowiednio przedstawione w raporcie to wygląd tych danych musi być wielokrotnie przekształcany.

Na początku dane były w źródłach, a następnie dzięki procesowi ETL, dane te zostają przekształcone i załadowane do miejsca docelowego. Z wygenerowanych danych tworzony jest model raportu, w którym przedstawiamy jakie dane są potrzebne do wyświetlenia. Oczywiście nie wszystkie informacje powinny być przedstawiane. Widok raportu (report view) składa się z modelu raportów oraz formy przedstawiania tego raportu. Do wyglądu formy zaliczają się takie modyfikacje wyświetlanych danych jak :
- sortowanie
- filtrowanie
- grupowanie
- format wyświetlania wartości (np. dla daty)

Poniższy rysunek przedstawia przejście z surowych danych do wyglądu raportu:

niedziela, 8 grudnia 2013

Ostatnie posty w PowerShellu

Skoro już siedzę troszkę w PS to pomyślałem sobie, że napiszę skrypt do pobierania postów z bloga. Skorzystałe z feedburner jako zasób wpisów.
function Get-ArekOnSoftwarePosts
{
    $url  = "http://feeds.feedburner.com/ArekOnSoftware"
    $webClient =  New-Object Net.WebClient
    $webClient.Proxy = [System.Net.WebRequest]::DefaultWebProxy
    $webClient.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
    $webClient.Encoding = [System.Text.Encoding]::UTF8;
    $feed = $webClient.DownloadString($url)
    ([xml]$feed).rss.channel.item | Select title, pubDate, origLink, category, description
}

Możemy wziąć 3 ostatnie wpisy o powershellu:
$posts = Get-ArekOnSoftwarePosts 
$posts | ?{$_. category -icontains "PowerShell" } 
| select title,  origLink -first 3

A rezultat z działania skryptu jest następujący:

Oczywiście w miejsce zmiennej $url możesz zmienić adres na RSS feed z innego bloga.

sobota, 7 grudnia 2013

Monitorowanie procesu ETL

Jak przy każdym projekcie, wcześniej czy później zespół dochodzi do wniosku, że potrzebne jest narzędzie/metody/procesy do monitorowania działania projektu. Chciałbym Ci przedstawić przykład monitorowania procesu ETL.


Proces ETL może być bardzo skomplikowany i niektóre zadania mogą nie działać poprawie. W tym celu dokonuje się logowania błędów. Logowanie pozwala na szybszą diagnozę, aby wywnioskować, co mogło wywołać błąd. Im więcej loguje się zdarzeń występujących w procesie ETL tym diagnoza jest dokładniejsza, ale każde logowanie wymaga dodatkowej przestrzeni pamięci. Same logowanie błędów nie wystarcza.

Oprócz logowania zdarzeń wymaga się narzędzia, które mogłoby sprawdzać różne części całego procesu ETL. Sprawdzenie połączenia do różnych zasobów jest dokonywana za pomocą mechanizmu pulsacji (heartbeat), które co dany interwał czasowy sprawdza zasób. Jeżeli dany zasób nie jest dostępny to wywoływany jest alarm (alert). Niektóre zasoby procesu ETL nie muszą być sprawdzane za każdym razem, a wystarcza, że zostaną sprawdzone raz przy uruchomieniu monitora (single alert). Monitor może sprawdzać czy istnieje połączenie do danych źródłowych. Na przykład, monitor sprawdza czy jest połączenie z bazą danych. Czasami samo sprawdzenie schematu bazy danych nie wystarcza i należy sprawdzić format zapisanych danych. W projektach rozproszonej odpowiedzialności, dane w bazie danych są zmieniane i zmiana formatu może spowodować nie wyekstraktowanie wszystkich danych lub co jest gorsze – ekstraktownie błędnych danych. Takie sprawdzenie ostrzeże nas przed uruchomieniem proces ETL. Dodatkowo możemy sprawdzić czy mamy dostęp do wymaganych plików oraz czy jest możliwość dostępu do sieci wewnętrznej. Sprawdzenie dostępu do sieci wewnętrznej nie tylko pozwoli nam na dostęp do danych referencyjnych, ale mamy możliwość sprawdzenia czy nie mamy problemów z połączeniem sieciowym. Czasami baza danych lub pliki są dostępne z jednego komputera (z danej podsieci), ale ten zasób może być niedostępny dla servera (z innej podsieci). Oprócz monitorowania danych wejściowych to dane wyjściowe (targets) również są monitorowane. Sprawdza się czy jest możliwość połączenia się do hurtowni danych (lub innego docelowego miejsca przechowywania danych).

Można monitorować komunikację w procesie ETL. Poszczególne komponenty ETL mogą komunikować się ze sobą za pomocą kolejki komunikatów (message queues) (lub przez Interprocess Communications). Każda kolejka jest wypełniana (produkcja) informacjami z jednego komponenty, a następny komponent wykorzystuje (konsumpcja) te informacje do dalszego działania. Jeżeli kolejka nie jest konsumowana to wiadomo, że następny komponent nie został wystartowany. Oprócz konsumpcji komunikatów sprawdzana jest ilość tych komunikatów. Jeżeli ilość jest za mała lub za duża to jeden z komponentów musiał wygenerować błąd lub istnieją duplikaty informacji.


Poniżej jest zawarty rysunek z przykładowym schematem monitorowania procesu ETL:


niedziela, 1 grudnia 2013

Kopiowanie nazw plików

Bardzo nie lubię pisać skryptu dwa razy tego samego - tak było z dzisiejszym skryptem. Postanowiłem na przyszłość zamieścić prosty skrypt, który kopiuje nazwy plików z jednej lokalizacji do drugiej. Pliki mają 0B - idę na ilość plików, a nie na ich wielkość :)

function Copy-File-By_FileName {
Param(
    [string] $sourceLocation,
    [string] $destinationClocation
)
$files = gci -force   $sourceLocation  -recurse

$files | foreach {
        $fileEnding = $_.FullName.Replace($sourceLocation, "");
        $secondItem = $destinationClocation  + $fileEnding ;
        
        if(Test-Path $secondItem)
        {
            write-host "File $secondItem exist";
        }
        else
        {
            Write-Host "Creating empty file at location: $secondItem";   
            New-Item $secondItem -type file       
        }
    }
}


Przykład użycia kopiowania nazw plików:
$elapsed = [System.Diagnostics.Stopwatch]::StartNew()
Copy-File-By_FileName -sourceLocation "C:\Files\" -destinationClocation "C:\EmptyFiles\"
write-host "Time: $($elapsed.Elapsed.ToString())"