Tento článek popisuje kurzory SQL a jak je používat pro některé speciální účely. Zdůrazňuje důležitost kurzorů SQL spolu s jejich nevýhodami.
Ne vždy se stává, že při programování databází používáte kurzor SQL, ale jejich koncepční porozumění a učení se, jak je používat, hodně pomáhá pochopit, jak provádět výjimečné úkoly v programování T-SQL.
Přehled kurzorů SQL
Pojďme si projít některé základy SQL kurzorů, pokud je neznáte.
Jednoduchá definice
Kurzor SQL poskytuje přístup k datům jeden řádek po druhém, čímž vám poskytuje větší kontrolu (řádek po řádku) nad sadou výsledků.
Definice společnosti Microsoft
Podle dokumentace společnosti Microsoft produkují příkazy Microsoft SQL Server úplnou sadu výsledků, ale jsou chvíle, kdy je nejlepší zpracovat výsledky po jednom řádku. Otevření kurzoru na sadě výsledků umožňuje zpracování sady výsledků po jednom řádku.
T-SQL a sada výsledků
Protože jak jednoduchá, tak i Microsoft definice kurzoru SQL zmiňují sadu výsledků, pokusme se porozumět tomu, co přesně je sada výsledků v kontextu programování databáze. Pojďme rychle vytvořit a naplnit tabulku Studenti ve vzorové databázi UniversityV3 následovně:
CREATE TABLE [dbo].[Student] ( [StudentId] INT IDENTITY (1, 1) NOT NULL, [Jméno] VARCHAR (30) NULL, [Kurz] VARCHAR (30) NULL, [Značky] INT NULL, [Datum zkoušky] DATUM ČASU 2 (7) NULL, OMEZENÍ [PK_Student] PRIMÁRNÍ KLÍČ SE SLUSTROVANÝ ([StudentId] ASC));-- (5) Naplnit studentskou tabulkuSET IDENTITY_INSERT [dbo].[Student] ONINSERT DO [dbo].[Student] ( [StudentId], [Name], [Course], [Marks], [Datum zkoušky]) VALUES (1, N'Asif', N'Database Management System', 80, N'2016-01-01 00:00:00 ')INSERT INTO [dbo].[Student] ([StudentId], [Jméno], [kurz], [známky], [Datum zkoušky]) VALUES (2, N'Peter', N'Database Management System', 85, N'2016-01-01 00:00:00')INSERT INTO [dbo].[Student] ([StudentId], [Jméno], [Kurz], [Marks], [Datum zkoušky]) VALUES (3, N' Sam', N'Database Management System', 85, N'2016-01-01 00:00:00')INSERT INTO [dbo].[Student] ([StudentId], [Name], [Course], [Marks ], [Datum zkoušky]) VALUES (4, N'Adil', N'Database Management System', 85, N'2016-01-01 00:00:00 ')INSERT INTO [dbo].[Student] ([StudentId], [Jméno], [kurz], [známky], [Datum zkoušky]) VALUES (5, N'Naveed', N'Database Management System', 90, N'2016-01-01 00:00:00')SET IDENTITY_INSERT [dbo].[Student] OFF
Nyní vyberte všechny řádky z Student tabulka:
-- Zobrazit data tabulky studentů SELECT [StudentId], [Jméno], [Kurz], [Značky], [Datum zkoušky] FROM dbo.Student
Toto je sada výsledků, která je vrácena jako výsledek výběru všech záznamů z Student tabulka.
T-SQL a teorie množin
T-SQL je čistě založeno na následujících dvou matematických konceptech:
- Teorie množin
- Predikátová logika
Teorie množin, jak název napovídá, je odvětvím matematiky o množinách, které lze také nazvat kolekcemi určitých odlišných objektů.
Stručně řečeno, v teorii množin uvažujeme o věcech nebo předmětech jako o celku stejným způsobem, jakým uvažujeme o jednotlivém předmětu.
Například student je množina všech jednoznačně odlišných studentů, takže studenta bereme jako celek, což stačí k tomu, abychom získali podrobnosti o všech studentech v této sadě (tabulce).
Další podrobnosti naleznete v mém článku Umění agregace dat v SQL od jednoduchých po posuvné agregace.
Kurzory a operace založené na řádcích
T-SQL je primárně navržen k provádění operací založených na množinách, jako je výběr všech záznamů z tabulky nebo odstranění všech řádků z tabulky.
Stručně řečeno, T-SQL je speciálně navržen pro práci s tabulkami způsobem založeným na množinách, což znamená, že uvažujeme o tabulce jako o celku a jakákoli operace, jako je výběr, aktualizace nebo odstranění, je aplikována jako celek na tabulku nebo určité řádky, které splňují kritéria.
Existují však případy, kdy je potřeba přistupovat k tabulkám řádek po řádku spíše než jako jednu sadu výsledků, a to je okamžik, kdy se kurzory aktivují.
Podle Vaidehi Pandere někdy aplikační logika potřebuje pracovat s jedním řádkem najednou a ne se všemi řádky najednou, což je stejné jako opakování (použití smyček k iteraci) přes celou sadu výsledků.
Základy SQL kurzorů s příklady
Pojďme nyní diskutovat více o kurzorech SQL.
Nejprve se naučíme nebo zopakujeme (ti, kteří již znají používání kurzorů v T-SQL), jak používat kurzor v T-SQL.
Použití kurzoru SQL je pětikrokový proces vyjádřený následovně:
- Deklarovat kurzor
- Otevřít kurzor
- Načíst řádky
- Zavřít kurzor
- Přidělit kurzor
Krok 1:Deklarace kurzoru
Prvním krokem je deklarace kurzoru SQL, aby jej bylo možné později použít.
Kurzor SQL lze deklarovat následovně:
DECLARE Cursorpro
Krok 2:Otevřete kurzor
Dalším krokem po deklaraci je otevření kurzoru, což znamená naplnění kurzoru sadou výsledků, která je vyjádřena následovně:
Otevřete
Krok 3:Načtení řádků
Jakmile je kurzor deklarován a otevřen, dalším krokem je začít načítat řádky z kurzoru SQL jeden po druhém, aby řádky získaly další dostupný řádek z kurzoru SQL:
Načíst další z
Krok 4:Zavřete kurzor
Jakmile jsou řádky načteny jeden po druhém a manipulováno podle požadavků, dalším krokem je zavřít kurzor SQL.
Zavření kurzoru SQL provede tři úkoly:
- Uvolní sadu výsledků aktuálně drženou kurzorem
- Uvolní všechny zámky kurzoru na řádcích vedle kurzoru
- Zavře otevřený kurzor
Jednoduchá syntaxe pro zavření kurzoru je následující:
Zavřete
Krok 5:Přidělte kurzor
Posledním krokem v tomto ohledu je uvolnit kurzor, čímž se odstraní reference kurzoru.
Syntaxe je následující:
DEALOCATE
Kompatibilita kurzoru SQL
Podle dokumentace společnosti Microsoft jsou kurzory SQL kompatibilní s následujícími verzemi:
- SQL Server 2008 a novější verze
- Azure SQL Database
Příklad SQL kurzoru 1:
Nyní, když jsme obeznámeni s kroky implementace SQL kurzoru, podívejme se na jednoduchý příklad použití SQL kurzoru:
-- Příklad deklarování studentského kurzoru 1USE UniversityV3GODECLARE Student_Cursor CURSOR FOR SELECT StudentId ,[Name]FROM dbo.Student;OPEN Student_CursorFETCH NEXT FROM Student_CursorWHILE @@FETCH_STATUS StudentOCOCROMSstudentCursCLOSECROMsENDCursorFET_BEGINFETCH NEXTCHORSVýstup je následující:
Příklad SQL kurzoru 2:
V tomto příkladu použijeme dvě proměnné k uložení dat držených kurzorem, když se pohybuje z řádku na řádek, abychom mohli zobrazit sadu výsledků jeden řádek po druhém zobrazením hodnot proměnných.
-- Příklad deklarování studentského kurzoru s proměnnými 2USE UniversityV3GODECLARE @StudentId INT ,@StudentName VARCHAR(40) -- Deklarování proměnných pro uložení řádkových dat držených kurzoremDECLARE Student_Cursor CURSOR FOR SELECT StudentId ,[Jméno]FROM dbo.StudentStudent neboOPEN; NEXT FROM Student_Cursor DO @StudentId, @StudentName -- Načtěte první řádek a uložte jej do proměnnýchWHILE @@FETCH_STATUS =0BEGINPRINT CONCAT(@StudentId,'--', @StudentName) -- Zobrazit proměnné dataFETCH NEXT FROM -- Získat další řádek data do kurzoru a uložte je do proměnnýchINTO @StudentId, @StudentNameENDCLOSE Student_Cursor -- Zavřete zámky kurzoru na řádcíchDEALLOCATE Student_Cursor -- Uvolněte odkaz na kurzorVýsledek výše uvedeného kódu SQL je následující:
Někdo by namítl, že stejného výstupu můžeme dosáhnout použitím jednoduchého SQL skriptu takto:
-- Zobrazení ID a jména studenta bez kurzoru SQLSELECT StudentId,Name FROM dbo.Studentorder by StudentId
Ve skutečnosti existuje několik úloh, které vyžadují použití kurzorů SQL, přestože se nedoporučuje používat kurzory SQL kvůli jejich přímému dopadu na paměť.
Důležitá poznámka
Mějte prosím na paměti, že podle Vaidehi Pandere jsou kurzory rezidentní sadou ukazatelů v paměti, takže zabírají systémovou paměť, kterou by jinak využívaly jiné důležité procesy; to je důvod, proč procházení velké sady výsledků pomocí kurzorů není nikdy dobrý nápad, pokud pro to neexistuje legitimní důvod.
Použití SQL kurzorů pro speciální účely
Projdeme si některé speciální účely, pro které lze SQL kurzory použít.
Testování paměti databázového serveru
Vzhledem k tomu, že kurzory SQL mají velký dopad na systémovou paměť, jsou dobrými kandidáty pro replikaci scénářů, kde je třeba prozkoumat nadměrné využití paměti různými uloženými procedurami nebo ad-hoc skripty SQL.
Jedním jednoduchým způsobem, jak to pochopit, je kliknout na tlačítko statistiky klienta na panelu nástrojů (nebo stisknout Shift+Alt+S) v SSMS (SQL Server Management Studio) a spustit jednoduchý dotaz bez kurzoru:
Nyní spusťte dotaz s kurzorem pomocí proměnných (příklad SQL Cursor 2):
Nyní si prosím poznamenejte rozdíly:
Počet příkazů SELECT bez kurzoru:1
Počet příkazů SELECT s kurzorem:7
Počet zpátečních cest serveru bez kurzoru:1
Počet zpátečních cest na server s kurzorem:2
Doba zpracování klienta bez kurzoru:1
Doba zpracování klienta s kurzorem:8
Celková doba provádění bez kurzoru:1
Celková doba provádění s kurzorem:38
Čekací doba na odpovědi serveru bez kurzoru:0
Doba čekání na odpovědi serveru s kurzorem:30
Stručně řečeno, spuštění dotazu bez kurzoru, který vrátí pouze 5 řádků, spustí stejný dotaz 6–7krát s kurzorem.
Nyní si dokážete představit, jak snadné je replikovat dopad paměti pomocí kurzorů, nicméně to není vždy to nejlepší.
Hromadné úlohy manipulace s databázovými objekty
Existuje další oblast, kde mohou být kurzory SQL užitečné, a to je, když musíme provádět hromadné operace s databázemi nebo databázovými objekty.
Abychom tomu porozuměli, musíme nejprve vytvořit tabulku kurzů a naplnit ji v UniversityV3 databázi takto:
-- Vytvořit tabulku kurzuCREATE TABLE [dbo].[Kurz] ( [CourseId] INT IDENTITA (1, 1) NOT NULL, [Název] VARCHAR (30) NOT NULL, [Detail] VARCHAR (200) NULL, CONSTRAINT [PK_Course] PRIMÁRNÍ KLÍČ V CLUSTERED ([CourseId] ASC));-- Naplnit tabulku kurzuSET IDENTITY_INSERT [dbo].[Kurz] ONINSERT DO [dbo].[Kurz] ([CourseId], [Name], [Detail]) VALUES (1, N'DevOps for Databases', N'This is about DevOps for Databases')INSERT INTO [dbo].[Course] ([CourseId], [Name], [Detail]) VALUES (2, N'Power BI Fundamentals', N'This is about Power BI Fundamentals')INSERT INTO [dbo].[Course] ([CourseId], [Name], [Detail]) VALUES (3, N'T-SQL Programming', N'About T-SQL Programming')INSERT INTO [dbo].[Course] ([CourseId], [Name], [Detail]) VALUES (4, N'Tabular Data Modeling', N'This is about Tabular Data Modeling')INSERT INTO [dbo].[Kurz] ([CourseId], [Name], [Detail]) VALUES (5, N'Analysis Services Fundamentals', N'This is about Analysis Services Fundamentals')SET IDENTITY_INSERT [dbo].[Kurz] VYPNyní předpokládejme, že chceme přejmenovat všechny existující tabulky na UniversityV3 databáze jako STARÉ tabulky.
To vyžaduje iteraci kurzoru přes všechny tabulky jednu po druhé, aby bylo možné je přejmenovat.
Úlohu provede následující kód:
-- Deklarujte Studentský kurzor pro přejmenování všech tabulek jako oldUSE UniversityV3GODECLARE @TableName VARCHAR(50) -- Název existující tabulky ,@NewTableName VARCHAR(50) -- Název nové tabulkyDECLARE Student_Cursor CURSOR FOR SELECT T.TABLE_NAME Z INFORMAČNÍHO SCHÉMATU.TABLE. T;OPEN Student_CursorFETCH NEXT FROM Student_Cursor INTO @TableNameWHILE @@FETCH_STATUS =0BEGINSET @[email protected]+'_OLD' -- Přidejte _OLD k existujícímu názvu tabulkyEXEC sp_rename @TableName,@FETCHET StudentName --neboTROMET Table NCOLDs -- Získejte data dalšího řádku do kurzoru a uložte je do proměnnýchINTO @TableNameENDCLOSE Student_Cursor -- Zavřete zámky kurzoru na řádcíchDEALLOCATE Student_Cursor -- Uvolněte odkaz na kurzor
Gratulujeme, úspěšně jste přejmenovali všechny existující tabulky pomocí SQL kurzoru.
Co dělat
Nyní, když jste obeznámeni s používáním kurzoru SQL, zkuste následující věci:
- Zkuste prosím vytvořit a přejmenovat indexy všech tabulek ukázkové databáze pomocí kurzoru.
- Zkuste prosím vrátit přejmenované tabulky v tomto článku zpět na původní názvy pomocí kurzoru.
- Zkuste zaplnit tabulky velkým množstvím řádků a měřte statistiky a čas pro dotazy s kurzorem a bez něj.