GO vagy nem GO

A go egy sokak által kedvelt japán stratégiai táblajáték, erről szeretnék most néhány gondolatot megosztani a nagyérdeművel, de mivel ennek semmi köze az SQL-hez, ezért inkább a T-SQL-ben található GO-ról fogok írni.
A GO – mint azt definíciójából is megtudhatjuk – a batch separator. Ennyi. Mi is az a batch separator? Szoktuk látni SQL scriptekben, hogy tele van szórva az egész GO-val, minden második-harmadik utasítás előtt ott ül egy GO, és már mi magunk is betesszük mindenhova, hiszen bajt nem okoz, nélküle viszont néha nem fut le a lefutnivaló.
Mivel még mindig nem tudtunk meg semmi hasznosat, fordítsuk le a definíciót: a GO elválasztja a feldolgozási egységeket. Na, most már tudjuk, mire való! Adjunk oda az SQL Servernek egy scriptet:

/* elofeltetel1:
create table tabla1 (a int identity(1,1), b int, c int)
create table tabla2 (a int, b int, c int)
*/
/* elofeltetel2:
create procedure spTablaolvaso
as select a,b,c from tabla1
*/

select a, b, c from tabla1
select a, b, c from tabla2
spTablaolvaso

Ez a script látványosan el fog bukni, mondván, hogy a spTablaolvaso egy ismeretlen dolog számára. Írjuk át a scriptet:

select a, b, c from tabla1
GO
select a, b, c from tabla2
GO
spTablaolvaso

Ez már le fog futni (feltéve, hogy léteznek az objektumok). Mi a különbség? A GO-nak köszönhetően az SQL Server a második scriptet három részben dolgozza fel, gyakorlatilag úgy, mintha az SSMS-ben soronként kijelölve futtatnánk le az első scriptet (ami abban az esetben szintén működik). Mivel a spTablaolvaso egy tárolt eljárás, vagy az első utasításnak kell lennie a batchben, vagy meg kell, hogy előzze az exec(ute) utasítás. Azaz az első script GO nélkül is kiválóan futna így:

select a, b, c from tabla1
select a, b, c from tabla2
exec spTablaolvaso

Ez eddig leginkább kultúrtörténeti érdekességnek tűnik, amivel lehet villantani a kockakocsmában, de van némi gyakorlati folyománya is. Vegyünk egy másik scriptet:

update tabla1
set azonosito = NULL
delete from tabla where a = 1
insert into tabla2 values(1, 2, 3)

Az update el fog bukni, mert az azonosito oszlop egy identity mező, ami nem nullázható. A delete és insert így meg sem történik, hiszen az első hibánknál megáll a végrehajtás. Tegyünk ide is egy GO-t:

update tabla1
set azonosito = NULL
delete from tabla where a = 1
GO
insert into tabla2 values(1, 2, 3)

Ebben az esetben az update pont ugyanakkora hátast fog dobni, el sem jutunk a delete-ig megint, de az insert megtörténik, mivel az első hibánál megállt a végrehajtás – az adott batchen belül. És aztán fogta a következő batchet, amiben egy insert volt, és azt lefuttatta. Így lehet nagy scriptekben sok hibát generálni, amiket utána nehéz helyrerakni, mert minden batchet külön kell ellenőrizni. Az efféle problémákat egyébként általában ki tudjuk védeni explicit tranzakció használatával.
A másik érdekes eredmény, hogy nem lehet változókat használni GO-kon át:

declare @a int
select @a = 1
GO
print @a

Ez is pirosat ír. De ezen nem lepődtünk meg. Ez pont az a történet, mintha az utolsó sort magában lefuttatnánk: nem ismeri a batch a @a változót, mert nem benne lett deklarálva.
Vannak olyan helyzetek tehát, ahol lehet használni GO-t, és vannak, ahol nem. És vannak, ahol muszáj. Vannak olyan utasítások például, amelyeknek elsőként kell szerepelniük a batchben. Ekkor hasznos elé tenni egy GO-t, hiszen így azt a kulimunkát, hogy kijelöljünk és üssük az F5-öt, megteszi helyettünk a szerver. Ilyen például a CREATE TRIGGER.
Legközelebb talán írok a japán stratégiai játékról is.

Leave a comment