Kiedy powinienem używać średników w SQL Server?

221

Podczas sprawdzania kodu w Internecie i skryptów generowanych przez SQL Server Management Studio zauważyłem, że niektóre instrukcje są zakończone średnikiem.

Więc kiedy powinienem go użyć?

Anwar Pinto
źródło
23
SQL Server 2008 R2 msdn.microsoft.com/en-us/library/ms177563.aspx „Konwencje składni Transact-SQL (Transact-SQL)” ; == Terminator instrukcji Transact-SQL. Chociaż średnik nie jest wymagany w przypadku większości instrukcji w tej wersji programu SQL Server, będzie on wymagany w przyszłej wersji .
gerryLowry
2
Chociaż twierdzą, że w przyszłej wersji wymagany będzie średnik, to nigdy się nie spełni. Nie mogą tego wymagać ze względu na kompatybilność. Uszkodziłoby to około 100% aplikacji.
usr
1
Jest teraz w 2019 roku i w najnowszej wersji SQL Server nadal nie jest akceptowany żaden średnik. Jak mówi @usr, chyba że Microsoft chce zrobić 100% czystą przerwę, nie ma sposobu, aby to wymusić.
Ian Kemp,

Odpowiedzi:

152

Z artykułu SQLServerCentral.Com autorstwa Kena Powersa:

Średnik

Średnik jest zakończeniem instrukcji. Jest częścią standardu ANSI SQL-92, ale nigdy nie był używany w Transact-SQL. Rzeczywiście, możliwe było kodowanie T-SQL przez lata bez żadnego średnika.

Stosowanie

Istnieją dwie sytuacje, w których musisz użyć średnika. Pierwszą sytuacją jest użycie wspólnego wyrażenia tabelowego (CTE), a CTE nie jest pierwszą instrukcją w partii. Drugi to miejsce, w którym wydaje się instrukcję Service Broker, a instrukcja Service Broker nie jest pierwszą instrukcją w partii.

TheTXI
źródło
9
Czy THROWoświadczenie brokera usług? W tym przykładzie musimy uwzględnić średnik przed rzutem:BEGIN ;THROW @Error, 'Invalid FundingID', 2; RETURN END
Chris Walsh
1
Wydaje się, że zasadniczo zachęcają one do używania średnika w ogóle, wymagając go przed wszystkimi nowymi typami instrukcji, które zostały wprowadzone w ostatnich latach. ( MERGEteż na przykład). Jak wspomniano w innych odpowiedziach, są one wymagane w standardzie ANSI
Mark Sowul
2
@maurocam Myślę, że źle przeczytałeś dokument. Jeśli spojrzysz na ten link, napisane jest: „ Nie kończenie instrukcji Transact-SQL średnikiem”. jest przestarzałe.
Caltor,
Moim zdaniem tak naprawdę nie dotyczy to pytania, kiedy należy (w przeciwieństwie do must ) użyć średnika.
Stewart,
81

Domyślnie instrukcje SQL są zakończone średnikami. Do zakończenia instrukcji używasz średnika, chyba że (rzadko) ustawiłeś nowy terminator instrukcji.

Jeśli wysyłasz tylko jedno oświadczenie, technicznie możesz zrezygnować z terminatora wyciągu; w skrypcie, ponieważ wysyłasz więcej niż jedną instrukcję, potrzebujesz jej.

W praktyce zawsze dołączaj terminator, nawet jeśli wysyłasz tylko jedną instrukcję do bazy danych.

Edycja: w odpowiedzi na te stwierdzenia, terminatory instrukcji nie są wymagane przez [konkretny RDBMS], chociaż może to być prawda, są wymagane przez ANSI SQL Standard. We wszystkich programach, jeśli możemy przestrzegać Standardu bez utraty funkcjonalności, powinniśmy, ponieważ wtedy ani nasz kod, ani nasze nawyki nie są powiązane z jednym zastrzeżonym dostawcą.

W przypadku niektórych kompilatorów C możliwe jest, że główny zwrot jest nieważny, nawet jeśli Standard wymaga, aby zwracał int. Ale dzięki temu nasz kod i my sami jesteśmy mniej przenośni.

Największą trudnością w programowaniu skutecznie nie jest uczenie się nowych rzeczy, to uczenie się złych nawyków. W zakresie, w jakim możemy przede wszystkim uniknąć nabywania złych nawyków, jest to wygrana dla nas, dla naszego kodu i dla każdego, kto czyta lub używa naszego kodu.

tpdi
źródło
25

Państwo musi go używać.

Praktyka używania średnika do kończenia instrukcji jest standardowa i faktycznie jest wymagana na kilku innych platformach baz danych. SQL Server wymaga średnika tylko w szczególnych przypadkach - ale w przypadkach, gdy średnik nie jest wymagany, użycie go nie powoduje problemów. Zdecydowanie zalecam przyjęcie praktyki kończenia wszystkich instrukcji średnikiem. To nie tylko poprawi czytelność twojego kodu, ale w niektórych przypadkach może zaoszczędzić ci trochę smutku. (Gdy wymagany jest średnik i nie jest określony, komunikat o błędzie, który generuje SQL Server, nie zawsze jest bardzo wyraźny).

I najważniejsze:

Dokumentacja programu SQL Server wskazuje, że nie kończenie instrukcji T-SQL średnikiem jest przestarzałą funkcją. Oznacza to, że długoterminowym celem jest wymuszenie użycia średnika w przyszłej wersji produktu. To jeszcze jeden powód, aby nabrać nawyku kończenia wszystkich swoich oświadczeń, nawet jeśli nie jest to obecnie wymagane.

Źródło: Microsoft SQL Server 2012 Podstawy języka T-SQL autorstwa Itzika Ben-Gana.


Przykładem tego, dlaczego zawsze musisz używać, ;są następujące dwa zapytania (skopiowane z tego postu ):

BEGIN TRY
    BEGIN TRAN
    SELECT 1/0 AS CauseAnException
    COMMIT
END TRY
BEGIN CATCH
    SELECT ERROR_MESSAGE()
    THROW
END CATCH

wprowadź opis zdjęcia tutaj

BEGIN TRY
    BEGIN TRAN
    SELECT 1/0 AS CauseAnException;
    COMMIT
END TRY
BEGIN CATCH
    SELECT ERROR_MESSAGE();
    THROW
END CATCH

wprowadź opis zdjęcia tutaj

gotqn
źródło
7
Wydaje się, że jest to mocny argument, że należy używać średników (popartych cudzysłowami), ale tylko jednego przypadku, w którym istnieje konieczność .
Gregor Thomas
3
@Gregor, jeśli zostanie ogłoszone, że używanie średników jest koniecznością i not using themjest przestarzałą techniką, powinieneś ich użyć. Jeśli nie, istnieje ryzyko, że ucierpi w przyszłości. Jeśli nie planujesz uaktualnić / zmienić zadania i zawsze zamierzasz pracować z SQL Server 2000, jesteś bezpieczny :-)
gotqn
5
Racja, powinienem się zgodzić. Ale w pierwszej linii twojej odpowiedzi podkreśla konieczność , co nie jest prawdą - przynajmniej jeszcze nie.
Gregor Thomas
2
Przykład z średnikami Incorrect syntax near 'THROW'.pokazuje SQL Server 2008 (10.0.6241.0), czyli wersję, z którą mam do czynienia w pracy. Działa tak, jak pokazano w 2012 roku. Przekonałem się, że zacząłem używać średników z powodu wycofania. Nie spodziewam się, że będzie to problem w 2008 roku przez większość czasu.
Pilot_51
1
Twoja odpowiedź jest jak dotąd najlepsza! Zasługuje na znacznie więcej głosów poparcia.
Stewart,
11

Osobista opinia: używaj ich tylko tam, gdzie są wymagane. (Zobacz powyższą odpowiedź TheTXI, aby uzyskać wymaganą listę).

Ponieważ kompilator nie wymaga od nich, to można je wszędzie, ale dlaczego? Kompilator nie powie ci, gdzie go zapomniałeś, więc skończysz z niespójnym użyciem.

[Niniejsza opinia dotyczy SQL Server. Inne bazy danych mogą mieć bardziej rygorystyczne wymagania. Jeśli piszesz SQL, aby uruchamiać go w wielu bazach danych, Twoje wymagania mogą się różnić.]

tpdi stwierdził powyżej: „w skrypcie, ponieważ wysyłasz więcej niż jedną instrukcję, potrzebujesz jej”. To właściwie nie jest poprawne. Nie potrzebujesz ich.

PRINT 'Semicolons are optional'
PRINT 'Semicolons are optional'
PRINT 'Semicolons are optional';
PRINT 'Semicolons are optional';

Wynik:

Semicolons are optional
Semicolons are optional
Semicolons are optional
Semicolons are optional
Rob Garrison
źródło
1
Co sądzisz o tej dyskusji? sqlservercentral.com/Forums/Topic636549-8-1.aspx (Yoy może użyć [email protected]: bugmenot, jeśli nie masz konta)
Anwar Pinto
2
Doceniam to, że jasno powiedziałeś, że to tylko twoja opinia, jednak nie sądzę, że jest to dobra odpowiedź, ponieważ jest sprzeczna zarówno z dokumentacją Microsoft, jak i standardem ANSI. Myślę, że ta opinia byłaby lepsza w komentarzu. (Nie próbując cię
zranić
4

Nadal muszę się wiele nauczyć o języku T-SQL, ale pracując nad kodem dla transakcji (i opierając kod na przykładach z stackoverflow i innych witryn) znalazłem przypadek, w którym wydaje się, że wymagany jest średnik, a jeśli go brakuje, instrukcja wydaje się wcale nie działać i nie pojawia się żaden błąd. Nie wydaje się, aby było to uwzględnione w żadnej z powyższych odpowiedzi. (To było za pomocą MS SQL Server 2012.)

Gdy transakcja działała tak, jak chciałem, postanowiłem ją wypróbować, aby w razie wystąpienia błędów wycofać transakcję. Dopiero po wykonaniu tej transakcji transakcja nie została zatwierdzona (SSMS potwierdza to przy próbie zamknięcia okna ładnym komunikatem ostrzegającym o fakcie, że transakcja nie została zatwierdzona.

Więc to

COMMIT TRANSACTION 

poza BEGIN TRY / END TRY blok działał dobrze, aby zatwierdzić transakcję, ale wewnątrz bloku musiał być

COMMIT TRANSACTION;

Uwaga: nie podano błędu ani ostrzeżenia ani żadnej informacji, że transakcja jest nadal niezatwierdzona do momentu próby zamknięcia karty zapytania.

Na szczęście powoduje to tak duży problem, że od razu widać, że jest problem. Niestety, ponieważ nie zgłoszono żadnego błędu (składniowego lub innego), nie było od razu oczywiste, na czym polega problem.

Przeciwnie, ROLLBACK TRANSACTION wydaje się działać równie dobrze w bloku BEGIN CATCH z lub bez średnika.

Może być w tym trochę logiki, ale wydaje się to arbitralne i Alice-in-Wonderland-ish.

Matthew Davidian
źródło
Jedną z możliwych przyczyn tego jest COMMIT TRANSACTIONzaakceptowanie opcjonalnej nazwy transakcji / punktu zapisu (który zignoruje). Bez średnika kończącego COMMIT TRANSACTIONmoże jeść następny symbol, jeśli analizuje jako identyfikator, co może radykalnie zmienić semantykę kodu. Jeśli spowoduje to błąd, CATCHmoże zadziałać bez COMMITwykonania. I odwrotnie, chociaż ROLLBACK TRANSACTIONakceptuje także opcjonalny identyfikator taki jak ten, błąd w jego analizie najprawdopodobniej spowoduje wycofanie transakcji.
Jeroen Mostert,
3

Wydaje się, że średniki nie powinien być stosowany w połączeniu z operacjami kursora: OPEN, FETCH, CLOSEi DEALLOCATE. Właśnie zmarnowałem kilka godzin z tym. Przyjrzałem się bliżej BOL i zauważyłem, że [;] nie jest pokazane w składni tych instrukcji kursora !!

Więc miałem:

OPEN mycursor;

i to dało mi błąd 16916.

Ale:

OPEN mycursor

pracował

rab
źródło
2
Nie sądzę, żeby to było poprawne. BOL nie bardzo konsekwentnie wspomina średnik w składni instrukcji, spójrz na przykład na SELECT. Plus byłem świadkiem OPEN someCursor; działa dobrze, tak samo dla FETCH, CLOSE i DEALLOCATE ...
Valentino Vranken
To sugeruje błąd w parserze. Jakiej wersji programu SQL Server używasz?
Stewart
2

Zgodnie z konwencjami składni Transact-SQL (Transact-SQL) (MSDN)

Terminator instrukcji Transact-SQL. Chociaż średnik nie jest wymagany w przypadku większości instrukcji w tej wersji programu SQL Server, będzie on wymagany w przyszłej wersji.

(zobacz także komentarz @gerryLowry)

Alan B.
źródło
0

W przypadku użycia instrukcji DISABLE lub ENABLE TRIGGER w partii zawierającej inne instrukcje, instrukcja tuż przed nią musi kończyć się średnikiem. W przeciwnym razie pojawi się błąd składniowy. Zerwałem włosy tym ... A potem natknąłem się na ten przedmiot MS Connect o to samo. Jest zamknięty, ponieważ nie można go naprawić.

patrz tutaj

Nick V.
źródło
0

Uwaga: To odpowiada na pytanie, jak napisano, ale nie na problem, jak stwierdzono. Dodanie go tutaj, ponieważ ludzie będą go szukać

Średnik jest również używany wcześniej WITHw rekurencyjnych instrukcjach CTE:

;WITH Numbers AS
(
    SELECT n = 1
    UNION ALL
    SELECT n + 1
    FROM Numbers
    WHERE n+1 <= 10
)
SELECT n
FROM Numbers

To zapytanie wygeneruje CTE o nazwie Liczby, które składa się z liczb całkowitych [1..10]. Odbywa się to poprzez utworzenie tabeli o wartości tylko 1, a następnie rekurencję aż do osiągnięcia 10.

v010dya
źródło
8
Technicznie nie „wcześniej z”, ale po tym, co nastąpi wcześniej. Jeśli with jest pierwszą instrukcją w partii, średnik nie jest wymagany.
Tor Haugen
Nie jest też wcześniej używany Z. To tylko średnik, który kończy poprzednią instrukcję. Wydaje się, że niektórzy zdecydowali, że średnik powinien być tutaj, ponieważ jest to scenariusz, w którym wspomniany średnik jest wymagany. Dlaczego ci ludzie zdecydowali, że jest to lepsze niż zawsze kończące instrukcje średnikami, nie mam pojęcia.
Stewart
0

Jeśli lubisz dostawać losowe błędy przekroczenia limitu czasu poleceń w SQLServer, zostaw średnik na końcu ciągów CommandText.

Nie wiem, czy jest to gdzieś udokumentowane, czy jest to błąd, ale tak się dzieje i nauczyłem się tego z gorzkich doświadczeń.

Mam weryfikowalne i odtwarzalne przykłady przy użyciu SQLServer 2008.

aka -> W praktyce zawsze dołączaj terminator, nawet jeśli wysyłasz tylko jedną instrukcję do bazy danych.

Allan Maher
źródło
Jeśli otrzymujesz limity czasu dla zapytania opartego wyłącznie na tym, czy na końcu jest średnik, prawie na pewno jest to spowodowane różnymi planami wykonania, ponieważ są one buforowane przez dopasowanie dokładnego tekstu zapytania, w tym w przeciwnym razie semantycznie nieistotne rzeczy takie jak spacja, komentarze i kończący średnik. Jednak sam średnik będzie całkowicie niewinny powodowania jakichkolwiek problemów z czasem.
Jeroen Mostert,
-2

Średniki nie zawsze działają w złożonych instrukcjach SELECT.

Porównaj te dwie różne wersje trywialnej złożonej instrukcji SELECT.

Kod

DECLARE @Test varchar(35); 
SELECT @Test=
    (SELECT 
        (SELECT 
            (SELECT 'Semicolons do not always work fine.';););); 
SELECT @Test Test;

zwroty

Msg 102, Level 15, State 1, Line 5
Incorrect syntax near ';'.

Jednak kod

DECLARE @Test varchar(35)
SELECT @Test=
    (SELECT 
        (SELECT 
            (SELECT 'Semicolons do not always work fine.'))) 
SELECT @Test Test

zwroty

Test
-----------------------------------
Semicolons do not always work fine.

(1 row(s) affected)
John Feild
źródło
11
[Rok później]: Wow, jestem zaskoczony, nikt jeszcze nie skomentował tej odpowiedzi! Oczywiście, że to nie zadziała, średniki są separatorami instrukcji, więc Twój kod z średnikami to: 1- SELECT @ Test = (SELECT (SELECT (SELECT 'Średniki nie zawsze działają dobrze.' '; - to nie jest poprawne stwierdzenie 2-); - nie jest to 3-); - ani to 4-); - ani tego średnika nie powinno być po 3 nawiasach
PhpLou,
1
Do kończenia instrukcji używasz tylko średników . Podzapytanie nie jest instrukcją. Instrukcje to rzeczy wykonywane sekwencyjnie. W twoim przykładzie są trzy instrukcje: 1. DEKLARUJ @ Test varchar (35) 2. SELECT @ Test = (SELECT (SELECT (SELECT 'Średniki nie zawsze działają dobrze.'))) 3. SELECT @ Test Test
Stewart