Na forach poświęconych relacyjnym bazom danych wiele pytań dotyczy problemów, których rozwiązanie sprowadza się do przygotowania odpowiedniego kodu w języku SQL. Także na forum portalu WSS.pl w dziale SQL Server sporo wątków traktuje o problemach z językiem Transact-SQL (T-SQL), implementacją języka SQL w systemie SQL Server. Celem niniejszego artykułu jest przedstawienie zasad, jakimi należy się kierować podczas formułowania zadania do rozwiązania w języku T-SQL.
Na forach poświęconych relacyjnym bazom danych wiele pytań dotyczy problemów, których rozwiązaniem jest odpowiedni kod w języku SQL. Jest tak także w dziale SQL Server na forum portalu WSS.pl. Niestety, często na drodze do uzyskania odpowiedzi staje nieprecyzyjne przedstawienie problemu oraz brak przykładowych danych.
Celem niniejszego artykułu jest przedstawienie zasad, jakimi należy się kierować podczas formułowania problemu. Można go potraktować jako przewodnik dla odwiedzających dowolne forum portali technicznych. Jeśli chcesz zadawać pytania związane z językiem T-SQL (Transact-SQL, implementacją języka SQL w systemie MS SQL Server) i zwiększyć szanse na to, że ktoś udzieli Ci jednoznacznej odpowiedzi, czytaj dalej.
Po pierwsze - podaj informacje o wersji i edycji systemu
Im nowsza wersja, tym arsenał programisty T-SQL jest większy. Podając numer wersji i określając, z jaką edycją systemu SQL Server pracujesz, masz większe szanse na uzyskanie rozwiązania optymalnego dla Twojego środowiska. Jedną z metod uzyskania tych informacji jest uruchomienie zapytania wykorzystującego systemową funkcję @@VERSION na instancji SQL Server:
SELECT @@VERSION
Przykładowy wynik powyższego zapytania:
Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64)
Apr 2 2010 15:48:46
Copyright (c) Microsoft Corporation
Enterprise Edition (64-bit) on Windows NT 6.1 <X64> (Build 7600: )
Powyższe informacje pozwolą nie tylko na wykorzystanie najnowszych składni języka T-SQL zgodnej z podaną wersją, ale także będą pomocne, gdy dyskusja zejdzie na tematy związane z architekturą lub rozwiązywaniem problemów niekoniecznie dotyczących samego systemu zarządzania bazami danych.
Po drugie - podaj struktury tabel i przykładowe dane
Jeśli Twój problem dotyczy języka T-SQL, bez wątpienia tym, co będziesz mógł zaprezentować ewentualnym uczestnikom dyskusji, jest schemat tabel w bazie danych. Nie ograniczaj się do opisu w stylu:
Mam następującą tabelę:
IDZamowienia | IDPozycjiZamowienia | IDProduktu | Ilosc | Cena
--------------------------------------------------------------
1 | 1 | 1 | 10 | 20
1 | 2 | 2 | 1 | 25
2 | 1 | 3 | 5 | 10
2 | 2 | 2 | 2 | 5
3 | 1 | 4 | 10 | 2
Taki opis oczywiście przedstawia zawartość tabeli i jej strukturę, ale zwykle potrzebne są także inne informacje. Patrząc na powyższe dane czytający nie dowie się na przykład:
- Jakiego typu danych jest kolumna Cena?
- Które kolumny wchodzą w skład klucza głównego tabeli (o ile takowy istnieje)?
- Czy któraś z kolumn w tabeli dopuszcza wstawienie wartości NULL?
Odpowiedzi na takie pytania udzieli czytelnikom skrypt T-SQL, czyli zestaw poleceń definiujących tabelę i wypełniających ją danymi. Zatem zamiast mozolnie „rysować" tabelę, jak to pokazałem powyżej, lepiej zrobisz podając skrypt, który dla niej wyglądałby tak:
IF OBJECT_ID('tempdb.dbo.#Zamowienia') IS NOT NULL
DROP TABLE #Zamowienia
CREATE TABLE #Zamowienia (
IDZamowienia int NOT NULL,
IDPozycjiZamowienia int NOT NULL,
IDProduktu int NOT NULL,
Ilosc numeric(19,4) NOT NULL,
Cena smallmoney NOT NULL,
CONSTRAINT PK_Zamowienia
PRIMARY KEY (IDZamowienia, IDPozycjiZamowienia)
)
INSERT INTO #Zamowienia (IDZamowienia, IDPozycjiZamowienia, IDProduktu, Ilosc, Cena)
VALUES (1, 1, 1, 10, 20)
INSERT INTO #Zamowienia (IDZamowienia, IDPozycjiZamowienia, IDProduktu, Ilosc, Cena)
VALUES (1, 2, 2, 1, 25)
INSERT INTO #Zamowienia (IDZamowienia, IDPozycjiZamowienia, IDProduktu, Ilosc, Cena)
VALUES (2, 1, 3, 5, 10)
INSERT INTO #Zamowienia (IDZamowienia, IDPozycjiZamowienia, IDProduktu, Ilosc, Cena)
VALUES (2, 2, 2, 2, 5)
INSERT INTO #Zamowienia (IDZamowienia, IDPozycjiZamowienia, IDProduktu, Ilosc, Cena)
VALUES (3, 1, 4, 10, 2)
Zalety powyższego skryptu to, m.in.:
- schemat tabeli i dane - czytelnik otrzymuje informacje na temat struktury tabeli, a także przykładowe dane (dokładnie takie, jakimi dysponuje pytający),
- usunięcie tabeli (obiektu) na początku skryptu (IF OBJECT_ID... DROP TABLE...) - co pozwala uruchamiać cały skrypt dowolną ilość razy,
- użycie symbolu kratki (#) przed nazwą Twojej tabeli (czyli #Zamowienia zamiast Zamowienia) sprawia, że jest to tabela tymczasowa czyli ulotna, która w żaden sposób nie będzie powodem konfliktu z istniejącymi u czytelników tabelami o takich samych nazwach i nie "zaśmieci" im bazy danych.
Oczywiście, tworząc skrypty z przykładowymi danymi nie należy przesadzać. Jeśli zamierzasz umieścić na forum skrypt wstawiający tysiące wierszy jeden po drugim, dobrze to przemyśl. Wklejając w wątku kod-tasiemiec możesz zniechęcić czytelników i przez to zmniejszyć szanse na uzyskanie pomocy. W takiej sytuacji albo wymyśl jakiś sprytny mechanizm generowania danych w miarę krótkim fragmentem kodu T-SQL, albo umieść swój skrypt w internecie (np. na portalu SkyDrive) i udostępnij go do pobrania na forum publikując jedynie odnośnik do pliku skryptu.
Skrypt tworzący tabelę możesz wygenerować używając na przykład narzędzia SQL Server Management Studio (SSMS). Wystarczy, że w oknie Object Explorer klikniesz prawym przyciskiem myszy na nazwie tabeli i wybierzesz z menu kontekstowego opcję Script Table as - CREATE To, byś uzyskał skrypt zawierający definicję tabeli. Najnowsze wersje narzędzia SSMS umożliwiają także skryptowanie danych w postaci poleceń INSERT. Aby wygenerować skrypt zawierający zarówno definicję tabeli (lub wielu tabel) oraz polecenia generujące dane, w SSMS kliknij w oknie Object Explorer prawym przyciskiem myszy na bazie danych i wybierz opcję Tasks - Generate Scripts...

Wybierz te tabele, które chcesz zeskryptować i klikaj przyciski Next, dopóki nie zobaczysz ekranu z przyciskiem Advanced...

Kliknij na tym przycisku, by ujrzeć zaawansowaną konfigurację skryptowania. Znajdż opcję Types of data for script i ustaw jej wartość na Schema and data. Dzięki temu zeskryptowane zostaną zarówno definicje tabel, jak i polecenia wstawienia danych.

Przejrzyj wygenerowany skrypt i ewentualnie oczyść go ze zbędnych fragmentów kodu (nie rób tego, jeśli boisz się, że kod przestanie działać poprawnie). Koniecznie przetestuj skrypt przed udostępnieniem go innym osobom (np. utwórz pustą testową bazę danych i uruchom w jej kontekście skrypt kilka razy, by sprawdzić, czy wykonuje się on bezbłędnie).
Koniecznie zadbaj też, by dane przykładowe dobrze reprezentowały zagadnienie. Przykładowo, jeżeli masz problem typu: "Jak dla każdego produktu znaleźć ostatnią datę sprzedaży w każdym miesiącu, gdzie cena jest większa od 100?", zamieść dane dla wielu produktów, róznych dat z różnych miesięcy oraz prawidłowym zakresem cenowym ("prawidłowy zakres cenowy" oznacza w tym przypadku kilka cen poniżej wartości 100, kilka powyżej tej wartości i kilka dokładnie równych 100).
Po trzecie - precyzyjnie określ Twój problem
Nawet najlepsze skrypty nie pomogą, jeśli formułując zagadnienie nie będziesz w stanie czytelnie i precyzyjnie go opisać. Staraj się w kilku prostych zdaniach opisać cel, jaki chcesz osiągnąć. Dzięki temu osoby, które będą chciały Ci pomóc, zajmą się problemem, a nie dochodzeniem, „co autor miał na myśli". Przeczytaj swoje pytanie kilka razy przed opublikowaniem (użyj do tego przycisku "Podgląd wiadomości" edytora wiadomości i czytaj ją w oknie podglądu, a nie edytora). Jeśli nie masz pewności, czy Twoje sformułowania są właściwe lub czy udało Ci się dobrze zdefiniować problem, zapytaj kogoś o zdanie lub zaryzykuj i opublikuj pytanie, jednocześnie spodziewając się dodatkowych pytań.
Jeśli ktoś zada Ci dodatkowe pytania dotyczące problemu, przeczytaj je uważnie i - w miarę możliwości - udziel odpowiedzi. Czasem problem wymaga doprecyzowania, a czasem dyskusja schodzi na tematy bardziej ogólne (np. może okazać się, że już w schemacie bazy danych tkwi źródło potencjalnych problemów i dyskusja będzie oscylowała wokół normalizacji relacyjnych baz danych).
Po czwarte - doceniaj każdą pomoc
Staraj się doceniać pomoc, jakiej udzielają Ci inni. Nawet, jeśli odpowiedź nie rozwiązała w stu procentach Twojego problemu, ale - na przykład - czegoś nowego Cię nauczyła lub naprowadziła na właściwy ślad, podziękuj odpowiadającym za pomocą przycisku "Pomógł mi". Jeżeli odpowiedź (lub odpowiedzi) rozwiązała Twój problem, użyj przycisku "Rozwiązanie". Przycisk ten dodatkowo oznaczy wątek jako rozwiązany, co będzie istotną informacją o wartości wątku dla innych czytających.
Pamiętaj - większość osób, rozwiązując na tym forum cudze problemy, robi to bezinteresownie, z pasji lub innych, równie szlachetnych, pobudek. Doceń fakt, że ktoś poświęca swój wolny czas na rozwiązanie Twojego problemu.
Po piąte - pytaj, pytaj, pytaj...
Nie bój się zadawać pytań. Przed zadaniem pytania, spróbuj znaleźć odpowiedź na forum, na którym chcesz je zadać oraz w Internecie. Pamiętaj, że nie ma niemądrych pytań. Nikt nie wie wszystkiego. Zadając pytania i rozwiązując swoje i cudze problemy, uczymy się wszyscy. Często bywa tak, że odpowiadający korzysta na rozwiązaniu problemu bardziej niż pytający.
Do zobaczenia na forum portalu WSS.pl. Kto wie, może właśnie Ty odpowiesz na moje pytania i rozwiążesz moje problemy? A może będzie dokładnie odwrotnie? ;-)
Autor artykułu dziękuje Panom o pseudonimach PaSkol i OpenRowset, bywalcom forum na portalu WSS.pl, za pomoc w uzyskaniu ostatecznej treści i formy powyższego tekstu.
Autor:

Paweł Potasiński (C3PO)
MVP, MCT, MCITP, MCDBA
Doświadczony konsultant baz danych i Business Intelligence. Redaktor portalu WSS.pl. Założyciel i prezes Polskiej Grupy Użytkowników SQL Server (PLSSUG). Od lipca 2008 roku MVP w kategorii SQL Server.