sql >> Base de Datos >  >> RDS >> Database

Cómo usar cursores SQL para propósitos especiales

Este artículo describe los cursores SQL y cómo usarlos para algunos propósitos especiales. Resalta la importancia de los cursores SQL junto con sus desventajas.

No siempre se usa el cursor SQL en la programación de bases de datos, pero su comprensión conceptual y aprender a usarlos ayuda mucho a comprender cómo realizar tareas excepcionales en la programación T-SQL.

Descripción general de los cursores SQL

Repasemos algunos conceptos básicos de los cursores SQL si no está familiarizado con ellos.

Definición sencilla

Un cursor SQL brinda acceso a los datos una fila a la vez, lo que le brinda más control (fila por fila) sobre el conjunto de resultados.

Definición de Microsoft

De acuerdo con la documentación de Microsoft, las declaraciones de Microsoft SQL Server producen un conjunto de resultados completo, pero hay momentos en que los resultados se procesan mejor una fila a la vez. Abrir un cursor en un conjunto de resultados permite procesar el conjunto de resultados una fila a la vez.

T-SQL y conjunto de resultados

Dado que tanto las definiciones simples como las de Microsoft del cursor SQL mencionan un conjunto de resultados, intentemos comprender qué es exactamente el conjunto de resultados en el contexto de la programación de bases de datos. Vamos a crear y llenar rápidamente la tabla de Estudiantes en una base de datos de muestra UniversityV3 de la siguiente manera:

CREATE TABLE [dbo].[Student] (
    [StudentId] INT           IDENTITY (1, 1) NOT NULL,
    [Name]      VARCHAR (30)  NULL,
    [Course]    VARCHAR (30)  NULL,
    [Marks]     INT           NULL,
    [ExamDate]  DATETIME2 (7) NULL,
    CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED ([StudentId] ASC)
);

-- (5) Populate Student table
SET IDENTITY_INSERT [dbo].[Student] ON
INSERT INTO [dbo].[Student] ([StudentId], [Name], [Course], [Marks], [ExamDate]) VALUES (1, N'Asif', N'Database Management System', 80, N'2016-01-01 00:00:00')
INSERT INTO [dbo].[Student] ([StudentId], [Name], [Course], [Marks], [ExamDate]) VALUES (2, N'Peter', N'Database Management System', 85, N'2016-01-01 00:00:00')
INSERT INTO [dbo].[Student] ([StudentId], [Name], [Course], [Marks], [ExamDate]) VALUES (3, N'Sam', N'Database Management System', 85, N'2016-01-01 00:00:00')
INSERT INTO [dbo].[Student] ([StudentId], [Name], [Course], [Marks], [ExamDate]) VALUES (4, N'Adil', N'Database Management System', 85, N'2016-01-01 00:00:00')
INSERT INTO [dbo].[Student] ([StudentId], [Name], [Course], [Marks], [ExamDate]) VALUES (5, N'Naveed', N'Database Management System', 90, N'2016-01-01 00:00:00')
SET IDENTITY_INSERT [dbo].[Student] OFF

Ahora, seleccione todas las filas del Estudiante tabla:

-- View Student table data
SELECT [StudentId], [Name], [Course], [Marks], [ExamDate] FROM dbo.Student

Este es el conjunto de resultados que se devuelve como resultado de seleccionar todos los registros del Estudiante mesa.

T-SQL y teoría de conjuntos

T-SQL se basa puramente en los siguientes dos conceptos matemáticos:

  1. Teoría de conjuntos
  2. Lógica de predicados

La teoría de conjuntos, como su nombre lo indica, es una rama de las matemáticas sobre conjuntos que también pueden llamarse colecciones de objetos distintos definidos.

En resumen, en la teoría de conjuntos, pensamos en cosas u objetos como un todo de la misma manera que pensamos en un elemento individual.

Por ejemplo, el estudiante es un conjunto de todos los estudiantes distintos definidos, por lo que tomamos un estudiante como un todo, lo cual es suficiente para obtener detalles de todos los estudiantes en ese conjunto (tabla).

Consulte mi artículo The Art of Aggregating Data in SQL from Simple to Sliding Aggregations para obtener más detalles.

Cursores y operaciones basadas en filas

T-SQL está diseñado principalmente para realizar operaciones basadas en conjuntos, como seleccionar todos los registros de una tabla o eliminar todas las filas de una tabla.

En resumen, T-SQL está especialmente diseñado para trabajar con tablas en forma de conjuntos, lo que significa que pensamos en una tabla como un todo, y cualquier operación como seleccionar, actualizar o eliminar se aplica como un todo a la tabla o a ciertos filas que cumplen los criterios.

Sin embargo, hay casos en los que es necesario acceder a las tablas fila por fila en lugar de como un solo conjunto de resultados, y aquí es cuando los cursores entran en acción.

Según Vaidehi Pandere, a veces la lógica de la aplicación necesita trabajar con una fila a la vez en lugar de todas las filas a la vez, lo que es lo mismo que hacer un bucle (uso de bucles para iterar) a través de todo el conjunto de resultados.

Conceptos básicos de los cursores SQL con ejemplos

Hablemos ahora más sobre los cursores SQL.

En primer lugar, aprendamos o revisemos (aquellos que ya están familiarizados con el uso de cursores en T-SQL) cómo usar el cursor en T-SQL.

El uso del cursor SQL es un proceso de cinco pasos expresado de la siguiente manera:

  1. Declarar Cursor
  2. Cursor abierto
  3. Obtener filas
  4. Cerrar cursor
  5. Desasignar cursor

Paso 1:Declarar Cursor

El primer paso es declarar el cursor SQL para que pueda usarse después.

El cursor SQL se puede declarar de la siguiente manera:

DECLARE Cursor <Cursor_Name> for <SQL statement>

Paso 2:Abrir cursor

El siguiente paso después de la declaración es abrir el cursor, lo que significa llenar el cursor con el conjunto de resultados que se expresa de la siguiente manera:

Open <Cursor_Name>

Paso 3:obtener filas

Una vez que se declara y abre el cursor, el siguiente paso es comenzar a recuperar las filas del cursor SQL una por una para que busque las filas y obtenga la siguiente fila disponible del cursor SQL:

Fetch Next from <Cursor_Name>

Paso 4:Cerrar el cursor

Una vez que las filas se recuperan una por una y se manipulan según los requisitos, el siguiente paso es cerrar el cursor SQL.

Cerrar el cursor SQL realiza tres tareas:

  1. Libera el conjunto de resultados que tiene actualmente el cursor
  2. Libera cualquier bloqueo de cursor en las filas por el cursor
  3. Cierra el cursor abierto

La sintaxis simple para cerrar el cursor es la siguiente:

Close <Cursor_Name>

Paso 5:desasignar cursor

El último paso en este sentido es desasignar el cursor, lo que elimina la referencia del cursor.

La sintaxis es la siguiente:

DEALLOCATE <Cursor_Name>

Compatibilidad de cursores SQL

Según la documentación de Microsoft, los cursores SQL son compatibles con las siguientes versiones:

  1. SQL Server 2008 y versiones posteriores
  2. Base de datos Azure SQL

Cursor SQL Ejemplo 1:

Ahora que estamos familiarizados con los pasos necesarios para implementar el cursor SQL, veamos un ejemplo simple del uso del cursor SQL:

-- Declare Student cursor example 1
USE UniversityV3
GO

DECLARE Student_Cursor CURSOR FOR SELECT
  StudentId
 ,[Name]
FROM dbo.Student;
OPEN Student_Cursor
FETCH NEXT FROM Student_Cursor
WHILE @@FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM Student_Cursor
END
CLOSE Student_Cursor
DEALLOCATE Student_Cursor

La salida es la siguiente:

Cursor SQL Ejemplo 2:

En este ejemplo, vamos a usar dos variables para almacenar los datos retenidos por el cursor a medida que se mueve de una fila a otra para que podamos mostrar el conjunto de resultados una fila a la vez mostrando los valores de las variables.

-- Declare Student cursor with variables example 2
USE UniversityV3
GO

DECLARE @StudentId INT
       ,@StudentName VARCHAR(40) -- Declare variables to hold row data held by cursor
DECLARE Student_Cursor CURSOR FOR SELECT 
  StudentId
 ,[Name]
FROM dbo.Student;
OPEN Student_Cursor
FETCH NEXT FROM Student_Cursor INTO @StudentId, @StudentName -- Fetch first row and store it into variables
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT CONCAT(@StudentId,'--', @StudentName) -- Show variables data
FETCH NEXT FROM Student_Cursor -- Get next row data into cursor and store it into variables
INTO @StudentId, @StudentName
END
CLOSE Student_Cursor -- Close cursor locks on the rows
DEALLOCATE Student_Cursor -- Release cursor reference

El resultado del código SQL anterior es el siguiente:

Se podría argumentar que podemos lograr el mismo resultado usando un script SQL simple de la siguiente manera:

-- Viewing student id and name without SQL cursor
SELECT StudentId,Name FROM dbo.Student
order by StudentId

De hecho, hay bastantes tareas que requieren el uso de cursores SQL a pesar de que se desaconseja usar cursores SQL debido a su impacto directo en la memoria.

Nota importante

Tenga en cuenta que, según Vaidehi Pandere, los cursores son un conjunto de punteros residentes en la memoria, por lo que ocupan la memoria del sistema que, de lo contrario, sería utilizada por otros procesos importantes; es por eso que recorrer un gran conjunto de resultados a través de cursores nunca es una buena idea a menos que haya una razón legítima para ello.

Uso de cursores SQL para propósitos especiales

Veremos algunos propósitos especiales para los que se pueden usar los cursores SQL.

Pruebas de memoria del servidor de base de datos

Dado que los cursores SQL tienen un gran impacto en la memoria del sistema, son buenos candidatos para replicar escenarios en los que es necesario investigar el uso excesivo de memoria por parte de diferentes procedimientos almacenados o secuencias de comandos SQL ad-hoc.

Una forma sencilla de entender esto es hacer clic en el botón de estadísticas del cliente en la barra de herramientas (o presionar Shift+Alt+S) en SSMS (SQL Server Management Studio) y ejecutar una consulta simple sin cursor:

Ahora ejecute la consulta con el cursor usando variables (SQL Cursor Example 2):

Ahora anote las diferencias:

Número de sentencias SELECT sin cursor:1

Número de declaraciones SELECT con cursor:7

Número de viajes de ida y vuelta al servidor sin cursor:1

Número de viajes de ida y vuelta al servidor con el cursor:2

Tiempo de procesamiento del cliente sin cursor:1

Tiempo de procesamiento del cliente con el cursor:8

Tiempo total de ejecución sin cursor:1

Tiempo total de ejecución con cursor:38

Tiempo de espera en las respuestas del servidor sin cursor:0

Tiempo de espera en las respuestas del servidor con el cursor:30

En resumen, ejecutar la consulta sin el cursor que devuelve solo 5 filas es ejecutar la misma consulta 6 o 7 veces con el cursor.

Ahora puede imaginar lo fácil que es replicar el impacto de la memoria usando cursores, sin embargo, esto no siempre es lo mejor que se puede hacer.

Tareas de manipulación masiva de objetos de base de datos

Hay otra área donde los cursores SQL pueden ser útiles y es cuando tenemos que realizar una operación masiva en bases de datos u objetos de bases de datos.

Para entender esto, primero, necesitamos crear la tabla del curso y completarla en UniversityV3 base de datos de la siguiente manera:

-- Create Course table
CREATE TABLE [dbo].[Course] (
    [CourseId] INT           IDENTITY (1, 1) NOT NULL,
    [Name]     VARCHAR (30)  NOT NULL,
    [Detail]   VARCHAR (200) NULL,
    CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED ([CourseId] ASC)
);

-- Populate Course table
SET IDENTITY_INSERT [dbo].[Course] ON
INSERT INTO [dbo].[Course] ([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].[Course] ([CourseId], [Name], [Detail]) VALUES (5, N'Analysis Services Fundamentals', N'This is about Analysis Services Fundamentals')
SET IDENTITY_INSERT [dbo].[Course] OFF

Ahora supongamos que queremos cambiar el nombre de todas las tablas existentes en UniversityV3 base de datos como tablas ANTIGUAS.

Esto requiere la iteración del cursor sobre todas las tablas una por una para que se les pueda cambiar el nombre.

El siguiente código hace el trabajo:

-- Declare Student cursor to rename all the tables as old
USE UniversityV3
GO

DECLARE @TableName VARCHAR(50) -- Existing table name
       ,@NewTableName VARCHAR(50) -- New table name

DECLARE Student_Cursor CURSOR FOR SELECT T.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES T;
OPEN Student_Cursor
FETCH NEXT FROM Student_Cursor INTO @TableName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @[email protected]+'_OLD' -- Add _OLD to exsiting name of the table
EXEC sp_rename @TableName,@NewTableName -- Rename table as OLD table
FETCH NEXT FROM Student_Cursor -- Get next row data into cursor and store it into variables
INTO @TableName
END
CLOSE Student_Cursor -- Close cursor locks on the rows
DEALLOCATE Student_Cursor -- Release cursor reference

Enhorabuena, ha cambiado correctamente el nombre de todas las tablas existentes con el cursor SQL.

Cosas que hacer

Ahora que está familiarizado con el uso del cursor SQL, intente lo siguiente:

  1. Intente crear y cambiar el nombre de los índices de todas las tablas de una base de datos de ejemplo con el cursor.
  2. Intente revertir las tablas renombradas en este artículo a los nombres originales usando el cursor.
  3. Intente completar las tablas con muchas filas y mida las estadísticas y el tiempo de las consultas con y sin el cursor.