2017-02-21
Kiedy wysyłasz wynik zapytania jako załącznik do maila korzystając z procedury sp_send_db_mail dzieją się dwie brzydkie rzeczy:
- do wygenerowanego pliku dołaczany jest tekst np 3 row(s) affected
- między nagłówkiem a danymi pojawia się kreska rozdzielająca te dwa elementy ———————————–
Z pierwszym problemem dosyć łatwo sobie można poradzić. W przekazywanym parametrze @query zamiast samego zapytania, np.:
SELECT id, name FROM database.dbo.table
zapisz
SET NOCOUNT ON;
SELECT id, name FROM database.dbo.table
Gorzej jednak z pomijaniem kreseczek… trzeba użyć sztuczki. Po pierwsze rezygnujemy z generowania nagówka dodając do sp_send_db_mail parametr: @query_result_header = 0
A jak teraz dodać warunek? Zapytanie zmień na UNION dwóch zapytań. Pierwsze z nich wygeneruje to co ma być w załączniku, a drugie zwróci właściwe dane. W efekcie mamy więc:
SET NOCOUNT ON;
SELECT 'id' AS id, 'name' AS name
UNION ALL
SELECT id, name FROM database.dbo.table
2017-02-21
Podczas wysyłania maila z załącznikiem (który jest wynikiem zapytania) pojawiał się bład:
Failed to initialize sqlcmd library with error number -2147024809
O co chodzi? Otóż polecenie wysyłające maila:
EXEC msdb..sp_send_dbmail @profile_name='SQLProfile'
, @recipients = @EmailRecipient
, @subject = @EmailSubject
, @body = @EmailContent
, @body_format = 'HTML'
, @query=@EmailQuery
, @attach_query_result_as_file=1
, @query_attachment_filename = 'Results.csv'
, @query_result_separator = ','
, @from_address = 'sql-team@company.com'
, @reply_to = 'sql-team@company.com'
wykonywało query zdefiniowane tak:
SELECT name from dbo.table
sęk w tym, że w czasie wysyłania maila wcale nie jest to takie jasne w jakiej bazie danych jesteśmy… Wystarczyło zmienić zapytanie na następującą postać żeby zadziałało:
SELECT name from mydatabase.dbo.table
2017-02-20
Zazwyczaj, konta w AD nie mają przypadkowych nazw. Nazwy muszą być nadawane zgodnie z przyjętą polityką. Np nazwy użytkowników mogą zawierać pierwsze litery nazwiska, a nazwy kont serwisowych mogą określać środowiska w jakich są wykorzystywane, jakie usługi będą z nich korzystać, na jakich serwerach itp.
W takim przypadku dość łatwo przeprowadzić inwentaryzację kont wykorzysywanych przez daną aplikację na danym serwerze lub w danym środowisku. Wystarczy do tego takie polecenie:
Get-ADUser -Filter "name -like 'sys*sql*p'" | Select name| Sort name
Zakładając, że konwencja nazewnicza
- kontom wykorzystywanym przez usługi określa nazwy rozpoczynające się od SYS
- kontom wykorzystywanym przez SQL określa występowanie w nazwie liter SQL
- kontom wykorzystywanym w środowisku produkcyjnym nadaje nazwy kończące się na P
powyższe polecenie wyświetli najprawdopodobniej właśnie konta usług SQL w środowisku produkcyjnym. Filtry mogą być oczywiście o wiele bardziej złożone!
2017-02-19
Dawno dawno temu kiedy chciałeś uruchomić usługę w systemie Linux dodawałeś plik o nazwie
S<XY><Name> oraz K<XY>Name
w katalogu /etc/init.d a potem w folderach /etc/rc[12345].d tworzyłeś link do odpowiednich plików. Pliki S* były uruchamiane podczas przechodzenia systemu do danego, określonego przez numer katalogu tzw. run-level, w celu uruchomienia usługi a pliki K miały za zadanie kończyć pracę tych usług. Liczby <XY> określały natomiast kolejność w jakiej usługi będą uruchamiane. Proste i logiczne.
W miarę ewolucji RedHat/Fedory, postanowiono jednak skorzystać z mechanizmów charakterystycznych dla systemd. Generalnie init.d ani rc2.d, rc3.d itd. nie są wykorzystywane.
Podczas definiowania nowej usługi należy korzystać z plików o nazwach
<ServiceName>.service
znajdujących się w
/etc/systemd/system
Jeśli instalujesz nowy serwis to należy w tym folderze utworzyć nowy plik, którego zawartość może wyglądać np. tak (przykład dla usługi Sybase): Czytaj dalej »
2017-02-09
Obiekty WMI mają złą sławę. Można z nich na prawdę dużo wyciągnąć, ale akurat ten kawałek platformy windows mógłby być trochę lepiej udokumentowany. Jednym z najbardziej tajemniczych tematów w pracy z WMI jest wywoływanie metod dla obiektów. Bez zbędnego rozwlekania tematu zobaczmy, jak to zrobić na 2 sposoby. Naszym zadaniem jest uruchomienie metodyDefragAnalysis na rzecz pierwszego dysku:
Metoda 1 – administacyjna
Polecenie Get-WMIObject zwraca obiekt klasy WMI. Wynik tego polecenia można więc potokiem przesłać do Select-Object aby wybrać właściwy dysk (tutaj pierwszy lepszy). Mając już tylko jeden obiekt wywołujemy dla tego obiektu metodę WMI korzystając z polecenia Invoke-WMIMethod. Istnieje również możliwość przekazania argumentów, ale DefragAnalysis nie wymaga żadnego. Oto te trzy polecenia połaczone w potok:
Get-WmiObject -Class win32_volume | select -First 1 | Invoke-WmiMethod -Name DefragAnalysis
Metoda 2 – programistyczna
Zaczynamy znowu od polecenia Get-WMIObject, ale tym razem zapominamy o zabawie potokiem. Aby wybrać właściwy wolumen (u nas pierwszy lepszy) znowu posługujemy się poleceniem Select-Object -Firs 1. Wynik tego potoku zapisujemy w zmiennej $volume. To czym jest teraz $volume? Ano obiektem WMI, ze wszystkimi jego właściwościami i metodami! Żeby wywołać metodę obiektu, po zmiennej napisz kropkę, potem nazwę metody do wywołania i w nawiasach ewentualnie umieść parametry:
$volume = Get-WmiObject -Class win32_volume | select -First 1
$volume.DefragAnalysis()
Podsumowanie:
Zależy jak wolisz, możesz korzystać i z jednej i z drugiej metody. Ja wybieram metodę 2, bo tam łatwiej jest przekazywać parametry i na dodatek, będąc programistą preferuję właśnie taki styl kodu… ale to moja prywatna opinia.
2017-01-28
Już od wersji SQL 2005 można w tabelach przechowywać dane w kolumnach o typie XML. Dane tam umieszczone mogą być krótkim fragmentem XML, ale równie dobrze może się tam znajdować obszerny dokument sięgający rozmiarem do 2 GB. To sporo! I co tu zrobić jeśli użytkownik chce wyświetlić tylko te rekordy które w polu XML mają okeśloną wartość? Bez dodatkowych indeksów trzebaby było po prostu przejrzeć wszystkie rekordy i dla każdego z nich oddzielnie analizować XML czy spełnia warunki czy nie. W przypadku dużych dokumentów będzie to ekstremalnie nieefektywne i dlatego właśnie wymyślono indeksy na kolumnach typu XML.
Istnieją dwa rodzaje indeksów XML:
PRIMARY indeks to miejsce w którym składowany jest XML w już przetworzonej postaci. Zauważ, że przechowywanie XML w kolumnie tabeli powoduje, że dane te są nadal podzielone na rekordy. Jeśli więc stworzysz zapytanie, które będzie miało pobrać tylko niektóre rekordy, spełniające określone warunki, to trzeba by było przetwarzać wszystkie dane z wszystkich rekordów, a tego chcemy uniknąć. Dlatego indeks PRIMARY to właśnie miejsce, którym składowany jest sparsowany i przetworzony XML. XML jest już tutaj podzielony na tagi (znaczniki), wartości wyrażone w elementach i atrybutach, ścieżki opisujące jak te wartości były zagnieżdżone w XML. Jeśli pewne pozycje tego PRIMARY indeksu zostaną w jakiś sposób odnalezione (a o tym już za chwilę), to w indeksie PRIMARY znajdzie się klucz podstawowy do podstawowej tabeli, czyli już do właściwego szukanego rekordu. Aby zacząć tworzyć kolejne indeksy SECONDARY musi najpierw istnieć indeks PRIMARY a tabela musi posiadać klucz podstawowy. Mając indeks PRIMARY można już lokalizować obiekty odpowiadające np. następującym wyrażeniom:
- //ContactRecord/PhoneNumber
- /Book/*/Title
Czytaj dalej »
2017-01-09
W Powershell wersji 5 pojawił się bug powodujący, że polecenie Get-Help about* zwraca tylko kilka wyników, podczas gdy tych plików z dokumentacją języka powinno być o wiele więcej…
Przyczyną była zła nazwa przypisywana plikom pomocy i można ten problem naprawić uruchamiając następujące polecenie:
Get-ChildItem -Path $pshome -Filter about*.txt -Recurse |
Where-Object { $_.Name -notlike '*.help.txt' } |
Rename-Item -NewName { $_.Name -replace '\.txt$', '.help.txt'}
Rozwiązanie skopiowane z http://community.idera.com/powershell/powertips/b/tips/posts/fixing-powershell-5-help-bug
Na szczęście w najnowszych wersjach, błąd wygląda już na poprawiony!