Archive for October, 2010
[PL] Only the good die young…
Oct 28th
Niestety, po raz kolejny okazało się, że nie znamy dnia ni godziny. W dniu dzisiejszym dotarła do mnie szokująca wiadomość. Zmarł Piotr Dobrowolski, założyciel i jeden z liderów Krakowskiej Grupy Deweloperów .NET, swego czasu Microsoft MVP, pierwszy polski Mistrz .NET (2004), ekspert w dziedzinie programowania, prelegent na licznych konferencjach o tematyce programistycznej, prywatnie mąż, ojciec i dobry człowiek. Piotr zmarł po ciężkiej walce z chorobą nowotworową. Trudno znaleźć słowa, gdy odchodzi ktoś, kogo miało się okazję poznać osobiście, zwłaszcza ktoś tak młody (Piotr przeżył nieco ponad 30 lat). Dlatego po prostu uczczę odejście Piotra tym wpisem, chwilą modlitwy i minutą ciszy. Na zawsze pozostanie w mojej pamięci.
PS. O nierównej walce Piotra z chorobą można poczytać na blogu: http://itsyouormenow.blogspot.com.
[PL] SQL Server–Obejście problemu z xp_cmdshell
Oct 27th
Procedura rozszerzona xp_cmdshell dostępna w SQL Server bywa przedmiotem dyskusji na temat bezpieczeństwa i tego, czy system zarządzania bazami danych powinien mocno integrować się z systemem operacyjnym. Domyślnie procedura ta jest wyłączona dzięki jednej z opcji serwera, ale często jest włączana i wykorzystywana, głównie do uruchamiania zewnętrznych aplikacji z poziomu kodu T-SQL.
Ostatnio natknąłem się na problem, którego rozwiązanie zajęło mi chwilę. I postanowiłem, że swoim rozwiązaniem się podzielę.
Na początek włączamy xp_cmdshell na instancji SQL Servera:
EXEC sp_configure 'show advanced options', 1; RECONFIGURE; GO EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE; GO
Próba uruchomienia xp_cmdshell:
EXEC master.dbo.xp_cmdshell 'dir "C:\Program Files"'; GO
Wynikiem jest lista katalogów i plików z folderu Program Files na dysku C:. Warto tu zwrócić uwagę na fakt, że parametr polecenia dir (listowanie plików i katalogów w systemie Windows) został otoczony cudzysłowami, ponieważ zawierał spację (gdyby cudzysłowów nie dać, napis zostałby potraktowany jako dwa parametry).
Problem pojawia się, gdy chcemy uruchomić zewnętrzną aplikację / wsad (.bat lub .cmd), do której ścieżka zawiera spacje z parametrem, w którym spacje również występują. Przykład:
EXEC master.dbo.xp_cmdshell '"D:\SQL Server\ProcessCube.bat" "My DB" "My Cube"'; GO
Próba wykonania powyższego kodu, przy założeniu, że wsad ProcessCube.bat naprawdę istnieje w lokalizacji D:\SQL Server, zakończy się komunikatem:
Nazwa ‘D:\SQL’ nie jest rozpoznawana jako polecenie wewnętrzne lub zewnętrzne, program wykonywalny lub plik wsadowy.
Szczerze mówiąc, nie wiem, jaka jest przyczyna problemu, ale obstawiam jakiś błąd w xp_cmdshell.
Obejście problemu jest dość proste:
EXEC master.dbo.xp_cmdshell 'call "D:\SQL Server\ProcessCube.bat" "My DB" "My Cube"'; GO
Trzeba zapewnić, że pierwsze w ciągu znaków podawanym jako parametr procedury xp_cmdshell będzie polecenie systemowe (do którego nie potrzeba podawać pełnej ścieżki). Może to być, jak powyżej, polecenie CALL (uruchamianie wsadu z innego wsadu – tak naprawdę można w ten sposób uruchamiać także wsady z konsoli).
Ot, czym czasem musi zajmować się konsultant Business Intelligence ;-)
[PL] Wydarzenie – O mitach na spotkaniu PLSSUG
Oct 26th
Z wielką przyjemnością zapraszam na moją prezentację poświęconą mitom w SQL Server. Prezentacja będzie jedną z dwóch sesji w ramach 49. spotkania warszawskiego oddziału Polskiej Grupy Użytkowników SQL Server (PLSSUG). Spotkanie odbędzie się 4 listopada (czwartek) w warszawskiej siedzibie firmy Microsoft (Al. Jerozolimskie 195A). Rozpocznie się o godzinie 18:00. Wstęp na spotkanie wolny (link do rejestracji na stronie wydarzenia).
Moja sesja będzie bazowała na dokumencie przygotowanym przez znanego eksperta – Paula S. Randala. Drugą prezentację w czasie spotkania poprowadzi Mariusz Koprowski (temat – VS nie tylko dla programistów .NET).
Zapraszam!
[PL] SQL Server – Migracja usługi Database Mail
Oct 25th
Jakiś czas temu na forum portalu WSS.pl padło pytanie, czy można przenieść konfigurację usługi Database Mail na SQL Server 2005 / 2008 / 2008 R2. Odpowiedziałem wówczas, że pewnie można to zrobić skryptując dane z tabel w bazie msdb. Postanowiłem, że napiszę kod do takiego skryptowania. Oto on:
set nocount on; print '-- *** Enabling DBMail *** '; print 'EXEC sp_configure ''show advanced options'', 1; RECONFIGURE; GO EXEC sp_configure ''Database Mail XPs'', 1; RECONFIGURE; GO '; print '-- *** Configuration ***'; select 'EXEC msdb.dbo.sysmail_configure_sp @parameter_name = ' + QUOTENAME(paramname, '''') + ', @parameter_value = ' + QUOTENAME(paramvalue, '''') + ', @description = ' + ISNULL(QUOTENAME(description, ''''),'NULL') + ';' from msdb.dbo.sysmail_configuration; print '-- *** Profiles ***'; select 'EXEC msdb.dbo.sysmail_add_profile_sp @profile_name = ' + QUOTENAME(name, '''') + ', @description = ' + ISNULL(QUOTENAME(description, ''''),'NULL') + ';' from msdb.dbo.sysmail_profile; print '-- *** Accounts ***'; select 'EXEC msdb.dbo.sysmail_add_account_sp @account_name = ' + QUOTENAME(a.name, '''') + ', @description = ' + ISNULL(QUOTENAME(a.description, ''''),'NULL') + ', @email_address = ' + QUOTENAME(a.email_address, '''') + ', @replyto_address = ' + ISNULL(QUOTENAME(a.replyto_address, ''''),'NULL') + ', @display_name = ' + ISNULL(QUOTENAME(a.display_name, ''''),'NULL') + ', @mailserver_name = ' + QUOTENAME(s.servername, '''') + ', @mailserver_type = ' + QUOTENAME(s.servertype, '''') + ', @port = ' + CONVERT(varchar(20), s.port) + ', @username = ''<ACCOUNT ' + a.name + ' - USERNAME,,>'', @password = ''<ACCOUNT ' + a.name + ' - PASSWORD,,>'', @use_default_credentials = ' + CONVERT(char(1), s.use_default_credentials) + ', @enable_ssl = ' + CONVERT(char(1), s.enable_ssl) + ', @account_id = ' + CONVERT(char(1), s.account_id) + ';' from msdb.dbo.sysmail_account a inner join msdb.dbo.sysmail_server s on a.account_id = s.account_id; print '-- *** Add accounts to profiles ***'; select 'EXECUTE msdb.dbo.sysmail_add_profileaccount_sp @profile_name = ' + QUOTENAME(p.name, '''') + ', @account_name = ' + QUOTENAME(a.name, '''') + ', @sequence_number = ' + CONVERT(varchar(20), pa.sequence_number) + ';' from msdb.dbo.sysmail_profileaccount pa inner join msdb.dbo.sysmail_account a on pa.account_id = a.account_id inner join msdb.dbo.sysmail_profile p on pa.profile_id = p.profile_id print '-- *** Grant access to the profile to the DBMailUsers role ***'; select 'EXECUTE msdb.dbo.sysmail_add_principalprofile_sp @profile_name = ' + QUOTENAME(pr.name, '''') + ', @principal_id = ' + CONVERT(varchar(20), p.principal_id) + ', @is_default = ' + CONVERT(char(1), s.is_default) + ';' from msdb.dbo.sysmail_principalprofile s inner join msdb.sys.database_principals p on s.principal_sid = p.sid inner join msdb.dbo.sysmail_profile pr on s.profile_id = pr.profile_id;
Po kolei:
- na początek skryptuję wywołanie procedury sp_configure i włączenie samej usługi Database Mail,
- następnie skryptuję serię wywołań procedury msdb.dbo.sysmail_configure_sp, która ustawia opcje Database Mail’a,
- w kolejnym kroku skryptowane są kolejno: profile (wywołania msdb.dbo.sysmail_add_profile_sp), konta (msdb.dbo.sysmail_add_account_sp) oraz przypisania kont do profili (wywołania msdb.dbo.sysmail_add_profileaccount_sp),
- na sam koniec skryptowane jest dodawanie odpowiednich użytkowników do roli DBMailUsers (wywołania msdb.dbo.sysmail_add_principalprofile_sp).
Użycie kodu wygląda następująco:
- Używając Management Studio uruchom kod na instancji, z której ustawienia Database Mail chcesz zeskryptować. Wynik zapisuj do tekstu.
- Skopiuj wynik zapytania do nowego okna skryptu w Management Studio.
- Zastąp niezbędne parametry (wciskając Ctrl+Shift+M i wypełniając kolumnę Value) odpowiednimi nazwami użytkowników oraz hasłami (danych wrażliwych, takich jak hasła, oczywiście nie trzymamy w skryptach).
- Uruchom uzupełniony kod na instancji docelowej.
- Sprawdź, czy działa wysyłanie wiadomości e-mail z wykorzystaniem usługi Database Mail.
Jak dotąd powyższy kod się sprawdzał. Od jakiegoś czasu używam go produkcyjnie. W razie problemów, proszę o kontakt.
[PL] Moim zdaniem – Certyfikaty zawodowe w branży IT
Oct 20th
Tytułem wstępu
Po sporym powodzeniu wpisu dotyczącego pracy i licznych głosach nakłaniających mnie do pisania na temat moich przemyśleń niekoniecznie związanych z technologiami postanowiłem, że na stałe zawita na moim blogu nowa seria pod zbiorczym tytułem “Moim zdaniem”. Tytuł serii najlepiej oddaje, jak powinny być traktowane wpisy w jej ramach publikowane – jako moje własne, niekoniecznie obiektywne, przemyślenia.
Certyfikaty – i o co tyle hałasu?
MCSE, MCP, CCNA i tym podobne trzy- i czteroliterowe skróty istnieją od dawna. Początkowo nie zaistniały w świadomości ludzi z branży IT, ale dzisiaj stały się nieodłącznym elementem naszego życia. Certyfikaty w IT zdobywamy na ogół po zdaniu jednego lub więcej egzaminów przy komputerze. Na ogół egzaminy te mają formę testu z ograniczoną liczbą gotowych odpowiedzi, a zadaniem zdającego jest wskazanie odpowiedzi poprawnych. Brzmi banalnie i czasem jest dość łatwo taki egzamin zdać. Z tego powodu i kilku jeszcze innych padają liczne pytania o sens zdobywania certyfikatów. Ale o tym później.
Po co producenci oprogramowania, jak na przykład firma Microsoft, przeznaczają pokaźne budżety na rozwój ścieżek certyfikacyjnych (ktoś musi opracować pytania, ktoś inny musi je zweryfikować, jeszcze ktoś musi do tego wszystkiego dorobić ideologię i marketing…)? Przecież na pewno jedynym powodem nie jest chęć wyłuskania z rzeszy specjalistów IT tych osób, które biegle posługują się danym systemem czy narzędziem. Odpowiedź wydaje się oczywista. Odpowiednio “nakręcony” rynek certyfikatów to jeszcze jeden sposób zwiększenia sprzedaży oprogramowania. Na przykład, większa liczba specjalistów w zakresie systemu SQL Server może przełożyć się na popularność tegoż produktu w firmach.
To pass or not to pass…
Podstawowe pytania, jakie zadaje sobie specjalista IT, brzmią: “Czy powinienem/powinnam zdawać egzaminy certyfikacyjne?” oraz “Jakie certyfikaty powinny znaleźć się w mojej ścieżce rozwoju?”.
Z jednej strony można przeczytać o spektakularnych karierach ludzi, których CV są naszpikowane “papierami”. Z drugiej strony padają głosy, że certyfikat może dzisiaj zdobyć każdy, bo większość egzaminów nie jest trudna do zdania, a w sieci aż roi się od wszelkich “pomocy”, nie zawsze legalnych, które jeszcze zwiększają szanse zdającego. A więc? Warto, czy nie?
Moim zdaniem, warto. Być może jest to pójście z prądem (“bo zdają inni”), być może egzaminy nie są trudne, być może dzisiaj każdy może zostać MCSE. Ale… to samo można powiedzieć o klasycznej edukacji wyższej. Teoretycznie każdy może iść na studia i zostać dyplomowanym informatykiem, elektrykiem czy socjologiem. Studia wymagają oczywiście nakładów finansowych i czasu poświęconego na naukę przedmiotów niekoniecznie przydatnych w życiu zawodowym. A zatem studia to swoista inwestycja w siebie. Poza tym, na studiach człowiek nabywa pewne cenne umiejętności (zdolność negocjacji z wykładowcami ;-), asertywność – imprezować z kumplami czy uczyć się do egzaminu?). I podobnie jest z certyfikatami w IT. Trzeba zainwestować pieniądze w egzaminy i poświęcić czas na naukę wiedząc, że nie wszystko, czego uczymy się do egzaminów, przyda nam się w pracy (w zasadzie można śmiało założyć, że przyda nam się marny procent…). Natomiast trzeba pamiętać, że tak, jak często na rozmowach o pracę kandydat jest eliminowany z dalszych etapów na skutek braków w wykształceniu (tak, tak, czasem ten nieszczęsny magister w CV może robić dużą różnicę), tak samo w pewnych sytuacjach czy środowiskach może się zdarzyć, że to właśnie certyfikat zawodowy, a właściwie jego brak, będzie przyczyną fiaska naszych starań o pracę. Widziałem już polskie firmy, które nie rozmawiały z kandydatami bez stosownego certyfikatu. Papierek był przepustką do rozmowy kwalifikacyjnej. Co ciekawe, zdarzają się na krajowym rynku firmy i organizacje, które w przetargach na grube miliony wymagają od firm w nich startujących, by w zespole miały osoby z konkretnymi certyfikatami.
Oczywiście, sam certyfikat nie jest gwarancją tego, że dana osoba posiada niezbędną wiedzę i doświadczenie. Znam przypadki, gdy delikwent na rozmowie kwalifikacyjnej świecił w CV listą certyfikatów, a brakowało mu podstawowej wiedzy. Życie brutalnie weryfikuje, kto w jaki sposób i po co zdobywa papierowe potwierdzenie swoich kwalifikacji. I niestety, certyfikowany po takiej wpadce zalicza zawsze większego “buraka” niż ten, kto certyfikatów w resume nie ma :-)
Jakie certyfikaty są dla Ciebie? Na to pytanie ja odpowiedzi Ci nie udzielę. Każdy producent, który ma swój program certyfikacyjny, na ogół w dość czytelny sposób informuje o tym, dla kogo przeznaczone są poszczególne certyfikaty. Ja na przykład skupiam się obecnie na certyfikatach dokumentujących moją wiedzę z zakresu systemu Microsoft SQL Server. Z tym systemem pracuję, w nim się specjalizuję. I zdecydowanie najlepiej właśnie w ten sposób wyznaczać swoje cele w zakresie certyfikacji zawodowej – idź za swoją specjalizacją. Odradzam zdawanie “wszystkiego, co się rusza”. Niezręcznie potem tłumaczy się komuś w czasie rozmowy kwalifikacyjnej, że ten i tamten certyfikat mamy, bo… jakoś tak wyszło. Sam to przerabiałem, ponieważ w ośrodkach szkoleniowych (pracowałem dawniej jako szkoleniowiec) często nowe kompetencje firmy są uzależnione od uzyskanych przez pracowników certyfikatów, więc trenerzy są zobligowani do zdawania egzaminów nieco odbiegających tematycznie od ich zainteresowań.
Sumienie a sprawa certyfikatów
Wspomniałem o tym, że niektórzy zdają egzaminy certyfikacyjne korzystając z nielegalnych pomocy (pytania są wynoszone z sal egzaminacyjnych i powstaje z nich kompilacja, tzw. braindump). Często czytam na różnych forach, jak bardzo ludzie są oburzeni tym faktem. Ale nikt jakoś nie jest oburzony faktem, że co roku uczelnie wyższe opuszcza duże X tysięcy absolwentów, z których zapewne pokaźny procent “przejechał” przez studia na sporym szczęściu i dobrze wykorzystanych ściągawkach :-) Nie pochwalam rzecz jasna nielegalnych pomocy. Uważam, że zdane przy ich pomocy egzaminy to prosta droga do obniżenia wartości certyfikatów. Natomiast koniec końców to sprawa sumienia zdających. Oszukujesz na egzaminach? Najbardziej oszukujesz samego siebie. Jaki z Ciebie będzie specjalista po zdaniu tych paru egzaminów? Być może przydałby się w zestawie certyfikatów Microsoftu (najpopularniejsze egzaminy, więc do nich jest najwięcej nielegalnych pomocy) jeszcze jeden certyfikat – MCBDM (Microsoft Certified Braindump Memorizer) ;-) Inna sprawa, że czasem mam wrażenie, że firmy IT, które prowadzą swoje własne systemy certyfikacji, nie dokładają wszelkich możliwych starań do tego, by zdanie egzaminu wyłącznie na “braindumpach” było niemożliwe (przecież wystarczy duża losowość pytań i odpowiedzi czy stosownie duża pula pytań). Czyżby obawa, że im trudniejsze do zdania egzaminy, tym mniejsze z nich wpływy? :-)
Certyfikat a wiedza ekspercka
Czasem spotykam się ze stwierdzeniem, że certyfikaty są dla ludzi, którzy w danej technologii posiedli “czarny pas”. Nic bardziej mylnego. Przecież nie da się sprawdzić w kilkudziesięciu pytaniach, czy osoba zdająca egzamin ma produkt czy technologię w małym palcu. Nie czarujmy się, egzaminy są dla ludzi! Zdawać może każdy i faktycznie pobudki zdających są bardzo różne. A to zdają dlatego, bo “w firmie kazali”, a to dlatego, bo znalazł się darmowy voucher ze zniżką 100%. Szczerze? Żaden powód nie jest zły. Byleby uczciwie podejść do tematu i zapoznać się z zagadnieniami wymaganymi na egzaminie. Tak zdobyta wiedza (laby, książki, szkolenia) różni się od tej, którą zdobywamy na projektach / wdrożeniach. To prawda. Ale trzeba też pamiętać, że najczęściej zakres wiedzy wymagany na egzaminie jest tak szeroki, że praktycznie nie sposób wszystkich rzeczy “dotknąć” w życiu zawodowym. Stąd nie należy z politowaniem patrzeć na osoby, które idą na egzamin po przetrenowaniu nowego systemu na maszynie wirtualnej. Taka osoba, o ile poważnie podeszła do sprawy i “przeklikała” porządnie system, dysponuje teoretyczną wiedzą, która może okazać się nieoceniona w rzeczywistych problemach stawianych “na produkcji”. A więc certyfikat a wiedza ekspercka to dwie różne sprawy. Oczywiście, wyjątek stanowią te certyfikaty, do których wymagania stawiane są na naprawdę wysokim poziomie, a egzaminy przypominają bardziej pranie mózgu (np. Microsoft Certified Master).
Społeczności osób certyfikowanych
Nie bez znaczenia dla popularności certyfikatów są z pewnością wszelkie społeczności, które powstają wśród osób legitymujących się tym samym certyfikatem. Przykładami takich społeczności są chociażby nie tak żywy już dzisiaj SEClub czy świeżo powstały twór – MCT Europe. Takie inicjatywy znakomicie komponują się z programami certyfikacyjnymi i powinny być solidnie wspierane przez firmy prowadzące owe programy. Ludzie należący do takich społeczności upatrują w tego typu zrzeszeniach wielu szans – czy to na zdobycie cennych kontaktów, czy – być może w dalszej perspektywie – na ciekawą pracę. Ja właśnie zgłosiłem chęć przynależenia do grupy MCT Europe, która zrzesza certyfikowanych trenerów Microsoft ze starego kontynentu. Grupa daje wiele w kontaktach z wieloma instytucjami i firmami. Na przykład założycielom MCT Europe udało się porozumieć z siecią hoteli, dzięki czemu trenerzy należący do organizacji otrzymują zniżki na noclegi. Takich “marchewek” w społecznościach powstałych wokół certyfikatów może być dowolnie wiele – wszystko zależy od osób tworzących daną grupę.
Certyfikat certyfikatem…
… a w pracy i tak liczą się najczęściej zupełnie inne umiejętności. Na przykład umiejętności interpersonalne, zdolności miękkie (negocjacje z klientem – tu raczej nie przyda Ci się żaden papier…). I – najważniejsze – profesjonalizm. A profesjonalizmu nie zapiszesz w CV i nie zdobędziesz na szkoleniach. To po prostu Twoje podejście do pracy i ludzi, z którymi przyszło Ci pracować / współpracować. A certyfikaty? Mogą się przydać i na pewno trzeba rozważyć ich uzyskanie, jeżeli nie chcesz, by Twoje CV decydowało za Ciebie o Twojej przyszłości ;-)
PS. A co do moich planów a propos certyfikatów – szykuję się właśnie do zdania pierwszego z dwóch egzaminów wymaganych do uzyskania tytułu Microsoft Certified IT Professional: Business Intelligence Developer 2008. Trzymajcie kciuki ;-)
[PL] SQL Server – Migracja loginów
Oct 18th
Jednym z kroków migracji instancji SQL Servera (np. do nowszej wersji) jest transfer loginów. Często pada pytanie, jak tego dokonać. Skąd to pytanie? Problemem jest takie przeniesienie, by zmigrowane loginy SQL Servera miały identyczne SID-y oraz hasła, jak loginy na instancji migrowanej. Zazwyczaj odpowiadam pytającemu podając odnośnik do jednego z artykułów z bazy wiedzy Microsoftu:
http://support.microsoft.com/kb/246133 (w przypadku migracji z SQL Server 7.0/2000 do SQL Server 2005 i nowszych)
http://support.microsoft.com/kb/918992 (w przypadku przenoszenia loginów pomiędzy instancjami SQL Server 2005 lub nowszymi)
Ostatnio przejrzałem nieco bardziej wnikliwie ten drugi artykuł i stwierdziłem, że przydałoby się w nim parę rzeczy zmienić. Stąd ten wpis, którego celem jest dostarczenie kodu poprawiającego pewne niedociągnięcia KB 918992.
Co jest do poprawienia?
- Kod niekoniecznie powinien zakładać procedury składowane (często chcemy wykonywać takie operacje “bezinwazyjnie”).
- Zupełnie niepotrzebnie tworzona jest procedura sp_hexadecimal, ponieważ już wersja SQL Server 2005 dysponuje funkcją skalarną fn_varbintohexstr, która robi to, co potrzeba (zamienia binaria wprost na tekst), a bodaj od SQL Server 2008 można taką operację wykonać także używając funkcji systemowej CONVERT.
- Brakuje przeniesienia przypisań loginów do ról na poziomie serwera.
A zatem, poprawiony kod wygląda tak:
DECLARE @login_name sysname SET @login_name = NULL DECLARE @name sysname DECLARE @type varchar (1) DECLARE @hasaccess int DECLARE @denylogin int DECLARE @is_disabled int DECLARE @PWD_varbinary varbinary (256) DECLARE @PWD_string varchar (514) DECLARE @SID_varbinary varbinary (85) DECLARE @SID_string varchar (514) DECLARE @tmpstr varchar (1024) DECLARE @is_policy_checked varchar (3) DECLARE @is_expiration_checked varchar (3) DECLARE @defaultdb sysname IF (@login_name IS NULL) DECLARE login_curs CURSOR FOR SELECT p.sid, p.name, p.type, p.is_disabled, p.default_database_name, l.hasaccess, l.denylogin FROM sys.server_principals p LEFT JOIN sys.syslogins l ON ( l.name = p.name ) WHERE p.type IN ( 'S', 'G', 'U' ) AND p.name <> 'sa' ELSE DECLARE login_curs CURSOR FOR SELECT p.sid, p.name, p.type, p.is_disabled, p.default_database_name, l.hasaccess, l.denylogin FROM sys.server_principals p LEFT JOIN sys.syslogins l ON ( l.name = p.name ) WHERE p.type IN ( 'S', 'G', 'U' ) AND p.name = @login_name OPEN login_curs FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin IF (@@fetch_status = -1) BEGIN PRINT 'No login(s) found.' CLOSE login_curs DEALLOCATE login_curs END SET @tmpstr = '/* sp_help_revlogin script ' PRINT @tmpstr SET @tmpstr = '** Generated ' + CONVERT (varchar, GETDATE()) + ' on ' + @@SERVERNAME + ' */' PRINT @tmpstr PRINT '' WHILE (@@fetch_status <> -1) BEGIN IF (@@fetch_status <> -2) BEGIN PRINT '' SET @tmpstr = '-- Login: ' + @name PRINT @tmpstr IF (@type IN ( 'G', 'U')) BEGIN -- NT authenticated account/group SET @tmpstr = 'CREATE LOGIN ' + QUOTENAME( @name ) + ' FROM WINDOWS WITH DEFAULT_DATABASE = [' + @defaultdb + ']' END ELSE BEGIN -- SQL Server authentication -- obtain password and sid SET @PWD_varbinary = CAST( LOGINPROPERTY( @name, 'PasswordHash' ) AS varbinary (256) ) SELECT @PWD_string = sys.fn_varbintohexstr(@PWD_varbinary), @SID_string = sys.fn_varbintohexstr(@SID_varbinary) -- obtain password policy state SELECT @is_policy_checked = CASE is_policy_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' ELSE NULL END FROM sys.sql_logins WHERE name = @name SELECT @is_expiration_checked = CASE is_expiration_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' ELSE NULL END FROM sys.sql_logins WHERE name = @name SET @tmpstr = 'CREATE LOGIN ' + QUOTENAME( @name ) + ' WITH PASSWORD = ' + @PWD_string + ' HASHED, SID = ' + @SID_string + ', DEFAULT_DATABASE = [' + @defaultdb + ']' IF ( @is_policy_checked IS NOT NULL ) BEGIN SET @tmpstr = @tmpstr + ', CHECK_POLICY = ' + @is_policy_checked END IF ( @is_expiration_checked IS NOT NULL ) BEGIN SET @tmpstr = @tmpstr + ', CHECK_EXPIRATION = ' + @is_expiration_checked END END IF (@denylogin = 1) BEGIN -- login is denied access SET @tmpstr = @tmpstr + '; DENY CONNECT SQL TO ' + QUOTENAME( @name ) END ELSE IF (@hasaccess = 0) BEGIN -- login exists but does not have access SET @tmpstr = @tmpstr + '; REVOKE CONNECT SQL TO ' + QUOTENAME( @name ) END IF (@is_disabled = 1) BEGIN -- login is disabled SET @tmpstr = @tmpstr + '; ALTER LOGIN ' + QUOTENAME( @name ) + ' DISABLE' END SELECT @tmpstr = @tmpstr + ISNULL(CHAR(13) + CHAR(10) + 'EXEC sp_addsrvrolemember ' + QUOTENAME(@name,'''') + ', ' + QUOTENAME(r.name,'''') + ';','') FROM sys.server_principals AS r INNER JOIN sys.server_role_members AS m ON r.principal_id = m.role_principal_id INNER JOIN sys.server_principals AS p ON p.principal_id = m.member_principal_id WHERE (p.type IN ('G', 'U', 'S') AND p.sid <> 0x01) AND p.name = @name SET @tmpstr = @tmpstr + CHAR(13) + CHAR(10) + 'GO' PRINT @tmpstr END FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin END CLOSE login_curs DEALLOCATE login_curs
Kod uruchamiamy na instancji, z której chcemy migrować loginy. Wynik w Management Studio zwracamy do tekstu (kod zwraca dane za pomocą kombinacji zapytań SELECT i poleceń PRINT). Wynik kopiujemy i uruchamiamy na instancji docelowej. W razie potrzeby kod można na powrót zamknąć w procedurze składowanej.
[PL] Konkurs T-SQL – Wyniki
Oct 6th

Po długich testach pora na ogłoszenie wyników konkursu T-SQL “Liga piłkarska”. W konkursie wzięło udział 17 osób, które nadesłały ponad 60 rozwiązań. Rekordzista – Leszek Gniadkowski – nadesłał 15 rozwiązań. Ale zdarzały się też osoby, które nadesłały jedno, ale za to całkiem nieźle wypadające w testach zapytanie.
Na początek słowo o teście finałowym skierowane głównie do finalistów. Polegał on na uruchamianiu Waszych skryptów na trzech zestawach danych – 20, 50 i 100 drużyn. Dwa z finałowych rozwiązań musiałem wykluczyć z testów już po pierwszym podejściu do zestawu 20 drużyn, ponieważ nie mogłem doczekać się wyników… Pozostałe zostały poddane testom wielokrotnym (na każdym zestawie puszczałem skrypty w pętli po 10 razy, a same pętle były puszczone po 5 razy – czyli w sumie każdy skrypt był uruchomiony 50 razy na każdym zestawie danych). Przed każdym uruchomieniem skryptu czyściłem bufor danych i plan cache, żeby uniknąć przypadkowości. Całość testu przeprowadziłem na laptopie o parametrach: Core 2 Duo (ale tylko jeden procesor używany przez SQL Server) + 4 GB RAM (1 GB przydzielony na bufor danych). Zapytania były monitorowane przez SQL Trace, z którego następnie wyciągałem średnie wartości czterech kryteriów (duration, CPU, reads, writes) dla poszczególnych testów (“20”, “50” i “100”). Dla każdego testu robiłem osobną tabelę. Oto owe tabele:
Test “20”
| Lp | Rozwiązanie | D | C | R | W | RD | RC | RR | RW | T |
| 1 | Gniadkowski_Leszek_v15.sql | 42602 | 41 | 22 | 0 | 1 | 1 | 1 | 1 | 4 |
| 2 | Gniadkowski_Leszek_v10.sql | 52062 | 45,2 | 25 | 0 | 2 | 2 | 2 | 1 | 7 |
| 3 | Gniadkowski_Leszek_v12.sql | 52642 | 45,8 | 25 | 0 | 3 | 3 | 2 | 1 | 9 |
| 4 | Nowakowski_Marcin_v04.sql | 121766 | 108,4 | 161 | 0 | 4 | 4 | 9 | 1 | 18 |
| 5 | Powichrowski_Marek_v12.sql | 177409,4 | 146,8 | 37 | 0 | 7 | 7 | 4 | 1 | 19 |
| 6 | Przeliorz_Tomek_v02.sql | 156648,2 | 135,6 | 325 | 0 | 6 | 6 | 11 | 1 | 24 |
| 7 | Zmuda_Katarzyna_v01.sql | 125126,2 | 113,6 | 633 | 0 | 5 | 5 | 14 | 1 | 25 |
| 8 | Nowakowski_Marcin_v03.sql | 255193,6 | 226,8 | 314 | 0 | 8 | 11 | 10 | 1 | 30 |
| 8 | Sliwa_Krzysiek_v02.sql | 262054 | 223,6 | 126 | 0 | 11 | 10 | 8 | 1 | 30 |
| 10 | Pater_Rafal_v03.sql | 278655,4 | 251,6 | 84 | 0 | 12 | 13 | 5 | 1 | 31 |
| 11 | Poniatowski_Aleksander_v01.sql | 282295,2 | 241,4 | 120 | 0 | 13 | 12 | 7 | 1 | 33 |
| 12 | Pater_Rafal_v04.sql | 300416,4 | 257,8 | 84 | 0 | 14 | 14 | 5 | 1 | 34 |
| 13 | Powichrowski_Marek_v13.sql | 261114 | 213,2 | 1123 | 0 | 10 | 9 | 17 | 1 | 37 |
| 14 | Przeliorz_Tomek_v01.sql | 258753,8 | 212,6 | 4771 | 0 | 9 | 8 | 20 | 1 | 38 |
| 15 | Gailard_Pawel_v02.sql | 423823,2 | 389,8 | 581 | 0 | 15 | 15 | 13 | 1 | 44 |
| 16 | Pakulski_Maciej_v03.sql | 1207088,2 | 998,2 | 578 | 0 | 17 | 18 | 12 | 1 | 48 |
| 17 | Kulczynski_Przemyslaw_v04.sql | 1109802,6 | 942,6 | 3066 | 0 | 16 | 16 | 18 | 1 | 51 |
| 18 | Kulczynski_Przemyslaw_v01.sql | 1225069,2 | 983 | 3120 | 0 | 18 | 17 | 19 | 1 | 55 |
| 19 | Grabowska_Katarzyna_v04.sql | 1680515,2 | 1327,6 | 1092 | 0 | 20 | 19 | 16 | 1 | 56 |
| 20 | Pakulski_Maciej_v02.sql | 3367231,6 | 2823,8 | 694 | 0 | 22 | 22 | 15 | 1 | 60 |
| 21 | Sowa_Piotr_v10.sql | 1901548 | 1603 | 6652 | 0 | 21 | 21 | 21 | 1 | 64 |
| 22 | Cerekwicki_Cezary_v01.sql | 1677855 | 1425 | 64485,8 | 2,8 | 19 | 20 | 22 | 22 | 83 |
| 23 | Waluszko_Bartlomiej_v02.sql | - | - | - | - | - | - | - | - | - |
| 24 | Jacewicz_Lukasz_v02.sql | - | - | - | - | - | - | - | - | - |
Legenda:
D – średnie duration
C – średnie CPU
R – średnie reads
W – średnie writes
RD – miejsce w kryterium duration
RC – miejsce w kryterium CPU
RR – miejsce w kryterium reads
RW – miejsce w kryterium writes
T – suma miejsc z wszystkich kryteriów (im mniejsza, tym lepiej)
Test “50”
| Lp | Rozwiązanie | D | C | R | W | RD | RC | RR | RW | T |
| 1 | Gniadkowski_Leszek_v15.sql | 71823,2 | 64,2 | 40 | 0 | 1 | 1 | 1 | 1 | 4 |
| 2 | Gniadkowski_Leszek_v10.sql | 78343,8 | 69,8 | 49 | 0 | 2 | 2 | 2 | 1 | 7 |
| 3 | Gniadkowski_Leszek_v12.sql | 78464 | 73,8 | 49 | 0 | 3 | 3 | 2 | 1 | 9 |
| 4 | Nowakowski_Marcin_v04.sql | 179449,6 | 160,4 | 85 | 0 | 4 | 4 | 4 | 1 | 13 |
| 5 | Sliwa_Krzysiek_v02.sql | 317637,4 | 293,2 | 121 | 0 | 6 | 6 | 6 | 1 | 19 |
| 6 | Poniatowski_Aleksander_v01.sql | 332818,2 | 295,4 | 103 | 0 | 7 | 7 | 5 | 1 | 20 |
| 7 | Przeliorz_Tomek_v02.sql | 201770,8 | 181,4 | 925 | 0 | 5 | 5 | 13 | 1 | 24 |
| 8 | Zmuda_Katarzyna_v01.sql | 414422,8 | 386,2 | 135 | 0 | 8 | 8 | 9 | 1 | 26 |
| 9 | Pater_Rafal_v03.sql | 604693,6 | 544,2 | 132 | 0 | 11 | 11 | 7 | 1 | 30 |
| 10 | Nowakowski_Marcin_v03.sql | 450784,6 | 404,4 | 733 | 0 | 9 | 9 | 12 | 1 | 31 |
| 11 | Gailard_Pawel_v02.sql | 499387,8 | 459 | 366 | 0 | 10 | 10 | 11 | 1 | 32 |
| 11 | Pater_Rafal_v04.sql | 605213,6 | 570,2 | 132 | 0 | 12 | 12 | 7 | 1 | 32 |
| 13 | Grabowska_Katarzyna_v04.sql | 2113640 | 1714,6 | 254,2 | 0 | 15 | 15 | 10 | 1 | 41 |
| 13 | Powichrowski_Marek_v12.sql | 753222 | 589,4 | 1597 | 0 | 13 | 13 | 14 | 1 | 41 |
| 15 | Powichrowski_Marek_v13.sql | 1063860 | 877 | 5019 | 0 | 14 | 14 | 15 | 1 | 44 |
| 16 | Przeliorz_Tomek_v01.sql | 2205305 | 1838,8 | 34441 | 0 | 16 | 16 | 17 | 1 | 50 |
| 17 | Pakulski_Maciej_v03.sql | 7804265,2 | 6686,8 | 27196 | 0 | 19 | 19 | 16 | 1 | 55 |
| 18 | Pakulski_Maciej_v02.sql | 39569582,4 | 36671,4 | 199326 | 0 | 22 | 22 | 21 | 1 | 66 |
| 19 | Sowa_Piotr_v10.sql | 6398825 | 5377,8 | 56028 | 39,8 | 17 | 17 | 18 | 20 | 72 |
| 20 | Kulczynski_Przemyslaw_v01.sql | 11576081,4 | 10360 | 133432 | 29,6 | 20 | 20 | 19 | 19 | 78 |
| 21 | Cerekwicki_Cezary_v01.sql | 7629655,6 | 6561,2 | 598566,4 | 409,6 | 18 | 18 | 22 | 22 | 80 |
| 22 | Kulczynski_Przemyslaw_v04.sql | 11873518,2 | 10476 | 152408 | 41,8 | 21 | 21 | 20 | 21 | 83 |
| 23 | Waluszko_Bartlomiej_v02.sql | - | - | - | - | - | - | - | - | - |
| 24 | Jacewicz_Lukasz_v02.sql | - | - | - | - | - | - | - | - | - |
Test “100”
| Lp | Rozwiązanie | D | C | R | W | RD | RC | RR | RW | T |
| 1 | Gniadkowski_Leszek_v15.sql | 169068,6 | 153,4 | 112 | 0 | 1 | 1 | 1 | 1 | 4 |
| 2 | Gniadkowski_Leszek_v10.sql | 192850,2 | 158,8 | 145 | 0 | 2 | 2 | 2 | 1 | 7 |
| 3 | Gniadkowski_Leszek_v12.sql | 202850,6 | 165,4 | 145 | 0 | 3 | 3 | 2 | 1 | 9 |
| 4 | Nowakowski_Marcin_v04.sql | 364540 | 316,8 | 277 | 0 | 4 | 4 | 4 | 1 | 13 |
| 5 | Poniatowski_Aleksander_v01.sql | 548570,2 | 446,6 | 343 | 0 | 7 | 6 | 7 | 1 | 21 |
| 6 | Sliwa_Krzysiek_v02.sql | 497087,6 | 456,4 | 409 | 0 | 6 | 7 | 8 | 1 | 22 |
| 7 | Przeliorz_Tomek_v02.sql | 411842,6 | 368,2 | 3165 | 0 | 5 | 5 | 14 | 1 | 25 |
| 8 | Pater_Rafal_v03.sql | 1078200,8 | 928,2 | 324 | 0 | 11 | 11 | 5 | 1 | 28 |
| 9 | Gailard_Pawel_v02.sql | 834646,8 | 767,4 | 673 | 0 | 9 | 9 | 11 | 1 | 30 |
| 9 | Pater_Rafal_v04.sql | 1123663,2 | 949,6 | 324 | 0 | 12 | 12 | 5 | 1 | 30 |
| 9 | Zmuda_Katarzyna_v01.sql | 909931 | 813,6 | 423 | 0 | 10 | 10 | 9 | 1 | 30 |
| 12 | Nowakowski_Marcin_v03.sql | 804165 | 530,4 | 464,2 | 0,2 | 8 | 8 | 10 | 13 | 39 |
| 13 | Grabowska_Katarzyna_v04.sql | 3773755 | 3151,2 | 734,4 | 0 | 16 | 16 | 12 | 1 | 45 |
| 14 | Pakulski_Maciej_v03.sql | 1716357,2 | 1425,4 | 736,8 | 0,6 | 13 | 13 | 13 | 14 | 53 |
| 15 | Powichrowski_Marek_v12.sql | 1990753 | 1704,4 | 23022 | 32 | 14 | 15 | 15 | 15 | 59 |
| 16 | Powichrowski_Marek_v13.sql | 2326372,4 | 1690,6 | 23814,6 | 32 | 15 | 14 | 16 | 15 | 60 |
| 17 | Przeliorz_Tomek_v01.sql | 12467972,4 | 11131,4 | 266163 | 78 | 17 | 17 | 18 | 18 | 70 |
| 18 | Sowa_Piotr_v10.sql | 27219956 | 25120,2 | 304784 | 411,8 | 18 | 18 | 19 | 20 | 75 |
| 19 | Pakulski_Maciej_v02.sql | 72426161,8 | 68060,4 | 522223 | 52 | 20 | 20 | 21 | 17 | 78 |
| 20 | Kulczynski_Przemyslaw_v01.sql | 73221107 | 68773,2 | 239710,4 | 308,2 | 22 | 22 | 17 | 19 | 80 |
| 21 | Cerekwicki_Cezary_v01.sql | 40562959,2 | 37802,4 | 2496637,8 | 3024 | 19 | 19 | 22 | 22 | 82 |
| 22 | Kulczynski_Przemyslaw_v04.sql | 73103680,2 | 68496,4 | 322134,4 | 458,6 | 21 | 21 | 20 | 21 | 83 |
| 23 | Waluszko_Bartlomiej_v02.sql | - | - | - | - | - | - | - | - | - |
| 24 | Jacewicz_Lukasz_v02.sql | - | - | - | - | - | - | - | - | - |
Dla każdego rozwiązania przy każdym teście uzyskałem sumę pozycji w poszczególnych kryteriach (ostatnia kolumna wg której ustalałem kolejność rozwiązań w powyższych tabelach wynikowych dla poszczególnych testów). Do uzyskania pozycji w końcowej tabeli wynikowej zsumowałem te wartości ze wszystkich trzech testów i tak wyszła mi tabela końcowa konkursu:
| Lp | Rozwiązanie | T20 | T50 | T100 | Total |
| 1 | Gniadkowski_Leszek_v15.sql | 4 | 4 | 4 | 12 |
| 2 | Gniadkowski_Leszek_v10.sql | 7 | 7 | 7 | 21 |
| 3 | Gniadkowski_Leszek_v12.sql | 9 | 9 | 9 | 27 |
| 4 | Nowakowski_Marcin_v04.sql | 18 | 13 | 13 | 44 |
| 5 | Sliwa_Krzysiek_v02.sql | 30 | 19 | 22 | 71 |
| 6 | Przeliorz_Tomek_v02.sql | 24 | 24 | 25 | 73 |
| 7 | Poniatowski_Aleksander_v01.sql | 33 | 20 | 21 | 74 |
| 8 | Zmuda_Katarzyna_v01.sql | 25 | 26 | 30 | 81 |
| 9 | Pater_Rafal_v03.sql | 31 | 30 | 28 | 89 |
| 10 | Pater_Rafal_v04.sql | 34 | 32 | 30 | 96 |
| 11 | Nowakowski_Marcin_v03.sql | 30 | 31 | 39 | 100 |
| 12 | Gailard_Pawel_v02.sql | 44 | 32 | 30 | 106 |
| 13 | Powichrowski_Marek_v12.sql | 19 | 41 | 59 | 119 |
| 14 | Powichrowski_Marek_v13.sql | 37 | 44 | 60 | 141 |
| 15 | Grabowska_Katarzyna_v04.sql | 56 | 41 | 45 | 142 |
| 16 | Pakulski_Maciej_v03.sql | 48 | 55 | 53 | 156 |
| 17 | Przeliorz_Tomek_v01.sql | 38 | 50 | 70 | 158 |
| 18 | Pakulski_Maciej_v02.sql | 60 | 66 | 78 | 204 |
| 19 | Sowa_Piotr_v10.sql | 64 | 72 | 75 | 211 |
| 20 | Kulczynski_Przemyslaw_v01.sql | 55 | 78 | 80 | 213 |
| 21 | Kulczynski_Przemyslaw_v04.sql | 51 | 83 | 83 | 217 |
| 22 | Cerekwicki_Cezary_v01.sql | 83 | 80 | 82 | 245 |
| 23 | Waluszko_Bartlomiej_v02.sql | - | - | - | - |
| 24 | Jacewicz_Lukasz_v02.sql | - | - | - | - |
Legenda:
T20 – suma miejsc z testu “20”
T50 – suma miejsc z testu “50”
T100 – suma miejsc z testu “100”
Total – suma miejsc ze wszystkich testów
A zatem… Jednogłośnym zwycięzcą konkursu ogłaszam Leszka Gniadkowskiego. Drugie miejsce wśród uczestników (choć Leszek zdominował konkurs totalnie) zajął Marcin Nowakowski, a trzecie – Krzysztof Śliwa. Postanowiłem też nagrodzić miejsca 4. i 5. – a więc Tomka Przeliorza oraz Aleksandra Poniatowskiego. Ze zwycięzcami będę kontaktował się indywidualnie drogą mailową.
Dziękuję wszystkim, którzy wzięli udział w moim konkursie. Wszyscy, którzy zakwalifikowali się do finału oprócz słów uznania otrzymają ode mnie mały prezent (szczegóły niebawem w mailu). Szczególnie gratuluję zwycięzcom. Dobra SQL-owa robota :-)
Tym samym konkurs uznaję za zamknięty. Dla wytrwałych i ciekawskich publikuję pełen zestaw rozwiązań finałowych w pliku ZIP.
[PL] SQL Server – Debugowanie z użyciem RAISERROR
Oct 4th
Ostatnio na forum portalu CodeGuru.pl brałem udział w dyskusji na temat metod prostego debugowania kodu T-SQL z wykorzystaniem polecenia PRINT. W wątku użytkownik szogun.krepa podał metodę obejścia problemu z poleceniem PRINT, które wysyła komunikat informacyjny (w przypadku aplikacji SQL Server Management Studio komunikat ten pojawia się w zakładce Messages) z opóźnieniami wynikającymi z długich czasów wykonania poleceń znajdujących się w tym samym wsadzie T-SQL.
Czy jest zatem PRINT działający bez opóźnień? Tak, takim odpowiednikiem jest odpowiednio wywołane polecenie RAISERROR. Odpowiednio to znaczy – z poziomem błędu ustawionym na 10 (poziomy od 1 do 9 też oznaczają informację, ale oprócz komunikatu pojawia się nagłówek błędu i już nie jest to działanie analogiczne z PRINT) oraz z przełącznikiem WITH NOWAIT. Porównajmy dwa wsady:
PRINT 'test 1'; WAITFOR DELAY '00:00:05'; GO RAISERROR('test 2',10,1) WITH NOWAIT; WAITFOR DELAY '00:00:05'; GO
W pierwszym przypadku komunikat “test 1” pojawia się po 5 sekundach i nie jest to efekt pożądany. W drugim przypadku komunikat “test 2” pojawia się natychmiast.
Ok, wszystko pięknie. Czy są zatem jakiekolwiek problemy, które możemy napotkać używając RAISERROR(…, 10, …) WITH NOWAIT? Zobaczmy taki kod:
DECLARE @zmienna varchar(10); SET @zmienna = 'jakiś błąd'; RAISERROR('Komunikat: ' + @zmienna,10,1) WITH NOWAIT; WAITFOR DELAY '00:00:05'; GO -- Msg 102, Level 15, State 1, Line 3 -- Incorrect syntax near '+'. -- Msg 319, Level 15, State 1, Line 3 -- Incorrect syntax near the keyword 'with'. If this statement is a common table -- expression, an xmlnamespaces clause or a change tracking context clause, -- the previous statement must be terminated with a semicolon.
Tak, w RAISERROR nie można generować komunikatu błędu wyrażeniem (albo literał, albo zmienna, ale nie wyrażenie). A zatem, zamiast powyższego można wykorzystać jeden z poniższych wariantów:
DECLARE @zmienna varchar(10), @komunikat varchar(255); SET @zmienna = 'jakiś błąd'; SET @komunikat = 'Komunikat: ' + @zmienna; RAISERROR(@komunikat,10,1) WITH NOWAIT; WAITFOR DELAY '00:00:05'; GO DECLARE @zmienna varchar(10); SET @zmienna = 'jakiś błąd'; RAISERROR('Komunikat: %s',10,1, @zmienna) WITH NOWAIT; WAITFOR DELAY '00:00:05'; GO
W pierwszym przypadku budujemy komunikat i zapisujemy go do jednej zmiennej (@komunikat), którą podstawiamy w wywołaniu polecenia RAISERROR jako pierwszy parametr.
W drugim przypadku korzystamy z parametryzowanego komunikatu (%s oznacza parametr tekstowy, wartości parametru pojawiają się kolejno jako czwarty i następne parametry polecenia RAISERRROR; więcej o parametryzowaniu RAISERROR do poczytania w Books Online).
Jak widać RAISERROR nadaje się do takiego natychmiastowego zwracania komunikatów, ale pod warunkiem, że będziemy pamiętać o wspomnianym powyżej ograniczeniu.
[PL] Konkurs T-SQL – Lista finalistów
Oct 4th

Parę minut temu zamknąłem listę finalistów konkursu T-SQL “Liga piłkarska”. Do finału dostały się poniższe rozwiązania:
Cerekwicki_Cezary_v01.sql
Gailard_Pawel_v02.sql
Gniadkowski_Leszek_v10.sql
Gniadkowski_Leszek_v12.sql
Gniadkowski_Leszek_v15.sql
Grabowska_Katarzyna_v04.sql
Jacewicz_Lukasz_v02.sql
Kulczynski_Przemyslaw_v01.sql
Kulczynski_Przemyslaw_v04.sql
Nowakowski_Marcin_v03.sql
Nowakowski_Marcin_v04.sql
Pakulski_Maciej_v02.sql
Pakulski_Maciej_v03.sql
Pater_Rafal_v03.sql
Pater_Rafal_v04.sql
Poniatowski_Aleksander_v01.sql
Powichrowski_Marek_v12.sql
Powichrowski_Marek_v13.sql
Przeliorz_Tomek_v01.sql
Przeliorz_Tomek_v02.sql
Sliwa_Krzysiek_v02.sql
Sowa_Piotr_v10.sql
Waluszko_Bartlomiej_v02.sql
Zmuda_Katarzyna_v01.sql
Gratuluję finalistom i dziękuję wszystkim osobom, które wzięły udział w konkursie. Najdalej w środę wieczór powinny ukazać się wyniki konkursu, o czym poinformuję też uczestników drogą mailową.
[PL] SQL Server – Pierwsza impresja na temat SQL Server 2008 SP2
Oct 1st
Dzisiaj ukazała się aktualizacja Service Pack 2 dla SQL Servera 2008. Rzuciłem się na nią wygłodzony :-) Powód był dość oczywisty. Otóż pracując w poprzedniej firmie (Asseco Business Solutions S.A.) zgłaszałem w ramach swojej pracy błąd, który bardzo przeszkadzał w implementacji mechanizmu wprowadzania zmian we własnych typach danych (patrz wpis na moim blogu: http://sqlgeek.pl/2010/01/04/en-call-for-voting-alter-type-in-sql-server/). Zatem pierwsze kroki w nowym buildzie (SQL Server 2008 SP2 otrzymał okrągły numerek 10.0.4000) skierowałem właśnie ku sprawdzeniu, czy nie występuje błąd opisany tu: Deadlock occurs when creating user-defined data type and objects that use it.
Okazało się, że prawie to naprawiono… A że prawie robi wielką różnicę, postanowiłem opisać, na czym polega owo “prawie”.
Co działa?
begin tran create type a from int null go create function b () returns int as begin declare @t table (c a null) return 1 end go commit
Przed SP2 taki kod zwracał komunikat mówiący o wystąpieniu zakleszczenia (deadlocka).
Świetnie! Good work, Microsoft! Niestety, moja euforia zgasła chwilę po tym, jak uruchomiłem powyższy kod. Marek Adamczuk podesłał mi informację, że u niego po zainstalowaniu SP2 błąd nadal występuje. Cytując klasyka, ale o so chosi?
Ano, rozchodzi się o to, że istnieje cała klasa podobnych problemów i nie o wszystkich przypadkach pomyślano w Redmond :-) Zobaczmy taki kod:
begin tran create type a from int null go declare @t table (c a null) go commit
Wstawienie do transakcji zmiennej tabelarycznej wykorzystującej typ danych tworzony w tej samej transakcji spowoduje dokładnie ten sam błąd, co w opisywanym powyżej przypadku. Do przetestowania jest jeszcze kilka innych problemów, ale już teraz widać, jak trudno naprawić wszystkie problemy z transakcyjnością, jeżeli już pojawią się takowe w silniku bazodanowym (naprawienie takich błędów może implikować powstanie następnych, jako że są to zmiany wprowadzane niskopoziomowo w samym silniku).
Wypada jedynie testować dokładnie swój kod i liczyć, że Microsoft nadal będzie reagował na nasze zgłoszenia. W tym przypadku należy się cieszyć, bo jednak reakcja jest prawidłowa (wyeliminowano błąd opisany przeze mnie w zgłoszeniu). Nie wyeliminowano błędu analogicznego, ale nie zgłoszonego na portalu connect.microsoft.com. No cóż, trzeba zakasać rękawy i opisać i ten przypadek, by programiści mogli pogłówkować, czy warto ów błąd naprawiać i, ewentualnie, jak to zrobić :-)

Nazywam się Paweł Potasiński i pracuję w polskim oddziale Microsoft w dziale Small and Midmarket Solutions & Partners (SMS&P) jako Partner Technology Advisor.



