0
Neki od vas znaju šta su korelacioni podupiti (correlated subqueries) i možda ih i koristite. Neki ne znaju i mogu da žive i bez njih. Problem, i to veliki, i jednim i drugim, može da nastane kada upotrebe takve podupite, a da toga nisu ni svesni.
Za primer uzećemo tabelu CrtaniFilmovi iz Kefalo baze, koja kao primarni ključ ima kolonu CrtacID i kao drugu pomoćnu tabelu kreiraćemo temp tabelu #OdabraniCrtaci koja će imati samo jednu kolonu ID.
CREATE TABLE #OdabraniCrtaci (ID INT); INSERT INTO #OdabraniCrtaci (ID) VALUES (1),(3);
Dodaćemo vrednosti 1 i 3 u tabelu #OdabraniCrtaci, i sadržaj obe tabele će izgledati ovako:
Probaćemo jednostavnim upitom da selektujemo sve crtaće koji se nalaze u sporednoj tabeli:
SELECT * FROM dbo.CrtaniFilmovi WHERE CrtacID IN (SELECT CrtacID FROM #OdabraniCrtaci);
Na prvi pogled možda vam odmah deluje da nešto nije u redu sa ovim upitom. Kolona CrtacID ne postoji u sporednoj tabeli i možda očekujete da ovo pukne sa greškom. Ako biste izvršili samo taj podupit odvojeno, to bi se i desilo. Međutim, ako probate da izvršite ceo upit, videćete da će proći i da se dobijaju rezultati koji možda nisu očekivani. Upit će vratiti sve iz prve tabele, a ono što se desilo je da ste upravo upotrebili correlated subquery, a da to verovatno niste planirali. Problem je ako niste ni primetili.
Ono što se desilo je da je SQL Server upotrebio kolonu CrtacID iz prve tabele, pošto je potpuno legitimno da se u podupitu koriste kolone iz spoljnjeg upita. Ovaj upit bi, ukoliko tabela #OdabraniCrtaci nije prazna, bio ekvivalentan bilo kome od sledećih:
SELECT * FROM dbo.CrtaniFilmovi WHERE CrtacID IN (SELECT CrtacID); SELECT * FROM dbo.CrtaniFilmovi WHERE CrtacID = CrtacID; SELECT * FROM dbo.CrtaniFilmovi WHERE 1=1; SELECT * FROM dbo.CrtaniFilmovi;
ili na primer:
SELECT * FROM dbo.CrtaniFilmovi cf WHERE cf.CrtacID IN (SELECT cf.CrtacID FROM #OdabraniCrtaci oc);
Međutim, da su odmah korišćeni alijasi ispred naziva kolona, verovatno biste stavili:
SELECT * FROM dbo.CrtaniFilmovi cf WHERE cf.CrtacID IN (SELECT oc.CrtacID FROM #OdabraniCrtaci oc);
što bi očekivano puklo i uvedili biste grešku da ste u podupitu naveli oc.CrtacID umesto oc.ID
Ovo se može lako potkrasti i kod svakog podupita treba paziti oko naziva kolona i koristiti alijase ili nazive tabela ispred. Zamislite još da umesto SELECT imate DELETE naredbu – realan scenario gde je sporedna tabela stage sa ID-evima spremnim za brisanje. Okinete to preko noći i ujutru vam nedostaje 600 000 redova iz produkcione baze (Istinita priča).