pirmdiena, 2011. gada 14. marts

SQL Server kursors bez kursora

Interesanti, kā tad tas ir- kursors bez kursora? Kursori man nepatīk (lai arī to ienaidnieks gluži neesmu), tādēļ, kad vien iespējams, mēģinu panākt līdzvērtīgu rezultātu neizmantojot kursoru.

Nesen uzdūros rakstam, kas lika padomāt par lietām, ko iepriekš nebiju pārdomājis.
Apskatīsim piemēru:
Create Table #t
(
    skaitlis int
)
Go
Insert Into #t(skaitlis) values (1)
Insert Into #t(skaitlis) values (2)
Insert Into #t(skaitlis) values (3)
Insert Into #t(skaitlis) values (4)
Lai parametram piešķirtu vērtību, mēs varētu izmantot šādu vaicājumu (tātad- mainīgajam @i tiek piešķirta vērtība no #t temporālās tabulas):
Declare @i int
Select @i = Skaitlis from #t
Select @i
Bet kāda vērtība tad tika piešķirta parametram? Patiesībā tam tika piešķirtas visas vērtības pēc kārtas. Beigās gan nolasot @i vērtību, tā būs pēdējā piešķirtā. šajā gadījumā "4".
Piemēram, šādā gadījumā:
Declare @i int
Select @i = Skaitlis from #t Order By Skaitlis DESC
Select @i
Salīdzinoši ar iepriekšējo vaicājumu parametra vērtībā būs "1", jo rezultāti ir sakārtoti pretējā secībā.

Un tā interesantā lieta: parametra piešķiršana notiek katrai rezultātu rindiņai, tātad šo īpašību var izmantot kā kursora aizvietotāju. Piemēram, sasummēsim visas vērtības:
Declare @i int
Set @i = 0
Select @i = @i + IsNull(Skaitlis,0) from #t
Select @i
Jā! Šajā gadījumā tas ir gluži kā izpildīt vaicājumu:
Select Sum(Skaitlis) from #t
Piekrītu, summas iegūšanai aprakstītais veids nav laba alternatīva. Bet citos gadījumos aprakstītais varētu būt pavisam veiksmīga alternatīva, piemēram:
Declare @i nvarchar(max)
Set @i = ''
Select @i = @i + Cast(Skaitlis as nvarchar) + ';' from #t
Select @i
Iegūst rezultātu "1;2;3;4;"

* Šī lieta man arī tieši ieinteresēja teksta virknes veidošanas kontekstā. Jau iepriekš emuārā bija raksts, kā šādu virkni iegūt pēc iespējas efektīvākā veidā, neizmantojot kursoru (risinājums ar CLR agregātfunkciju: CLR agregātfunkcijas piemērs). Šajā sakarā, domājams, būs vēl viens raksts, kurā apvienošu visus variantus (padomā veseli 4).
** Runājot par šī raksta sākumā pieminēto rakstu- tajā kā piemērs dots skripts, kas atsist visus lietotājus (lai atjaunotu datu bāzi no rezerves kopijas). Man šāds variants liktos labāks:
Use Master
ALTER DATABASE TDatuBaze SET SINGLE_USER WITH ROLLBACK IMMEDIATE
RESTORE DATABASE ...
ALTER DATABASE TDatuBaze SET MULTI_USER WITH ROLLBACK IMMEDIATE

Nav komentāru:

Ierakstīt komentāru