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

Operadores T-SQL SET Parte 2:INTERSECT y EXCEPT

En mi artículo anterior, expliqué los conceptos básicos de los operadores de conjuntos, sus tipos y los requisitos previos para su uso. También hablé sobre los operadores UNION y UNION ALL, su uso y diferencias.

En este artículo, vamos a aprender lo siguiente:

  1. Operadores EXCEPT e INTERSECT.
  2. Diferencia entre INTERSECT e INNER JOIN.
  3. La explicación detallada de INTERSECT y EXCEPT con un ejemplo.

Los operadores EXCEPT e INTERSECT se introdujeron en SQL Server 2005. Ambos son operadores establecidos que se utilizan para combinar los conjuntos de resultados generados por dos consultas y recuperar el resultado deseado.

¿Qué es el operador INTERSECT

INTERSECT se utiliza para obtener registros comunes a todos los conjuntos de datos recuperados de varias consultas o tablas. Aquí hay una visualización de esto:

La sintaxis del operador INTERSECT es la siguiente:

SELECT COLUMN1, 
       COLUMN2, 
       COLUMN3, 
       COLUMN4..FROM TABLE1 
INTERSECT
SELECT COLUMN1, 
       COLUMN2, 
       COLUMN3, 
       COLUMN4..FROM TABLE2

¿Qué es el operador EXCEPTO

EXCEPT se utiliza para recuperar registros que se encuentran en una consulta pero no en otra consulta. En otras palabras, devuelve registros que son exclusivos de un conjunto de resultados. Así es como se ve visualizado:

La sintaxis del operador EXCEPT es la siguiente:

SELECT COLUMN1, 
       COLUMN2, 
       COLUMN3, 
       COLUMN4..FROM TABLE1 
EXCEPT
SELECT COLUMN1, 
       COLUMN2, 
       COLUMN3, 
       COLUMN4..FROM TABLE2

Vamos a crear una configuración de demostración para demostrar cómo se pueden usar estos operadores.

Configuración de demostración

Para demostrar INTERSECT y EXCEPT, creé dos tablas llamadas Employee y aprendiz .

Ejecute la siguiente consulta para crear estas tablas:

CREATE TABLE [DBO].[EMPLOYEE] 
  ( 
     [NAME]             [NVARCHAR](250) NOT NULL, 
     [BUSINESSENTITYID] [INT] NOT NULL, 
     [NATIONALIDNUMBER] [NVARCHAR](15) NOT NULL, 
     [LOGINID]          [NVARCHAR](256) NOT NULL, 
     [BIRTHDATE]        [DATE] NOT NULL, 
     [MARITALSTATUS]    [NCHAR](1) NOT NULL, 
     [GENDER]           [NCHAR](1) NOT NULL 
  ) 
ON [PRIMARY] 

CREATE TABLE [DBO].[TRAINEE] 
  ( 
     [NAME]             [NVARCHAR](250) NOT NULL, 
     [BUSINESSENTITYID] [INT] NOT NULL, 
     [NATIONALIDNUMBER] [NVARCHAR](15) NOT NULL, 
     [BIRTHDATE]        [DATE] NOT NULL, 
     [GENDER]           [NCHAR](1) NOT NULL 
  ) 
ON [PRIMARY]

Ahora, insertemos algunos datos ficticios en el Empleado table ejecutando la siguiente consulta:

INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'KEN SÁNCHEZ', 1, N'295847284', N'ADVENTURE-WORKS\KEN0', CAST(N'1969-01-29' AS DATE), N'S', N'M')
GO
INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'TERRI DUFFY', 2, N'245797967', N'ADVENTURE-WORKS\TERRI0', CAST(N'1971-08-01' AS DATE), N'S', N'F')
GO
INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'ROBERTO TAMBURELLO', 3, N'509647174', N'ADVENTURE-WORKS\ROBERTO0', CAST(N'1974-11-12' AS DATE), N'M', N'M')
GO
INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'ROB WALTERS', 4, N'112457891', N'ADVENTURE-WORKS\ROB0', CAST(N'1974-12-23' AS DATE), N'S', N'M')
GO
INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'GAIL ERICKSON', 5, N'695256908', N'ADVENTURE-WORKS\GAIL0', CAST(N'1952-09-27' AS DATE), N'M', N'F')
GO
INSERT [DBO].[EMPLOYEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [LOGINID], [BIRTHDATE], [MARITALSTATUS], [GENDER]) VALUES (N'JOSSEF GOLDBERG', 6, N'998320692', N'ADVENTURE-WORKS\JOSSEF0', CAST(N'1959-03-11' AS DATE), N'M', N'M')

A continuación, haremos lo mismo con el aprendiz tabla:

INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'JOHN WOOD', 18, N'222969461', CAST(N'1978-03-06' AS DATE), N'M')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'MARY DEMPSEY', 19, N'52541318', CAST(N'1978-01-29' AS DATE), N'F')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'WANIDA BENSHOOF', 20, N'323403273', CAST(N'1975-03-17' AS DATE), N'F')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'KEN SÁNCHEZ', 1, N'295847284', CAST(N'1969-01-29' AS DATE), N'M')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'TERRI DUFFY', 2, N'245797967', CAST(N'1971-08-01' AS DATE),  N'F')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'ROBERTO TAMBURELLO', 3, N'509647174', CAST(N'1974-11-12' AS DATE), N'M')
GO

Ahora, usemos INTERSECT para recuperar la lista de empleados que son comunes a ambas tablas. Para hacerlo, ejecute la siguiente consulta:

SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   EMPLOYEE 
INTERSECT 
SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   TRAINEE

El resultado de esta consulta debe ser el siguiente:

Como puede ver en la captura de pantalla anterior, la consulta solo ha devuelto registros que son comunes a ambas tablas.

UNIÓN INTERNA frente a INTERSECCIÓN

En la mayoría de los casos, INTERSECT e INNER JOIN devuelven el mismo resultado, pero hay algunas excepciones. Un ejemplo simple nos ayudará a entender esto.

Agreguemos algunos registros duplicados a la tabla Trainee. Ejecute la siguiente consulta:

INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'TERRI DUFFY', 2, N'245797967', CAST(N'1971-08-01' AS DATE),  N'F')
GO
INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (N'ROBERTO TAMBURELLO', 3, N'509647174', CAST(N'1974-11-12' AS DATE), N'M')
GO

Ahora, intentaremos generar el resultado deseado usando INTERSECT.

SELECT NAME,BUSINESSENTITYID,NATIONALIDNUMBER,BIRTHDATE,GENDER FROM EMPLOYEE
INTERSECT
SELECT NAME,BUSINESSENTITYID,NATIONALIDNUMBER,BIRTHDATE,GENDER FROM TRAINEE

Este es el resultado que obtenemos:

Ahora, intentemos usar INNER JOIN.

SELECT A.NAME, 
       A.BUSINESSENTITYID, 
       A.NATIONALIDNUMBER, 
       A.BIRTHDATE, 
       A.GENDER 
FROM   EMPLOYEE A 
       INNER JOIN TRAINEE B 
               ON A.NAME = B.NAME

El resultado que obtenemos en este caso es el siguiente:

Ahora, como puede ver en la captura de pantalla anterior, INNER JOIN recupera registros que son comunes a ambas tablas. Rellena todos los registros de la tabla de la derecha. Por lo tanto, puede ver registros duplicados.

Ahora, agreguemos la palabra clave DISTINCT a la consulta INNER JOIN y veamos lo que hace:

SELECT DISTINCT A.NAME, 
                A.BUSINESSENTITYID, 
                A.NATIONALIDNUMBER, 
                A.BIRTHDATE, 
                A.GENDER 
FROM   EMPLOYEE A 
       INNER JOIN TRAINEE B 
               ON A.NAME = B.NAME

La salida debería verse así:

Como puede ver en la captura de pantalla anterior, se han eliminado los registros duplicados.

INTERSECT e INNER JOIN tratan los valores NULL de manera diferente. Para INNER JOIN, dos valores NULL son diferentes, por lo que hay posibilidades de que los omita al unir dos tablas.

Por otro lado, INTERSECT trata dos valores NULL como si fueran iguales, por lo que los registros que tienen valores NULL no serán eliminados. Para entenderlo mejor, veamos un ejemplo.

Primero, agreguemos algunos valores NULL al Aprendiz y empleado tablas ejecutando la siguiente consulta:

INSERT [DBO].[TRAINEE] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER], [BIRTHDATE], [GENDER]) VALUES (NULL, 3, N'509647174', CAST(N'1974-11-12' AS DATE), N'M')
GO

INSERT [DBO].[Employee] ([NAME], [BUSINESSENTITYID], [NATIONALIDNUMBER],[LOGINID], [BIRTHDATE],[MARITALSTATUS], [GENDER]) VALUES (NULL, 3, N'509647174','ADVENTURE-WORKS\TERRI0', CAST(N'1974-11-12' AS DATE),  N'M',N'M')
GO

Ahora intentemos recuperar registros comunes a las dos tablas usando INTERSECT e INNER JOIN. Deberá ejecutar la siguiente consulta:

/*QUERY WITH INTERSECT*/ 
SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   EMPLOYEE 
INTERSECT 
SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   TRAINEE 

/*QUERY WITH INNER JOIN*/ 
SELECT A.NAME, 
       A.BUSINESSENTITYID, 
       A.NATIONALIDNUMBER, 
       A.BIRTHDATE, 
       A.GENDER 
FROM   EMPLOYEE A 
       INNER JOIN TRAINEE B 
               ON A.NAME = B.NAME

Esta es la salida que deberíamos obtener como resultado:

Como puede ver arriba, el conjunto de resultados generado por INTERSECT contiene valores NULL, mientras que INNER JOIN omitió los registros que tienen valores NULL.

El operador EXCEPTO

Para demostrar el operador EXCEPT en acción, veamos un caso de uso. Por ejemplo, quiero completar los detalles de las empleadas de la tabla Empleado. La siguiente consulta nos ayudará a hacer precisamente eso:

SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   EMPLOYEE 
WHERE  GENDER = 'F' 
EXCEPT 
SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   EMPLOYEE 
WHERE  GENDER = 'M'

Este es el resultado que obtenemos:

Como puede ver arriba, la consulta llenó solo los detalles de las empleadas.

También puede completar el conjunto de resultados mediante una subconsulta:

SELECT NAME, 
       BUSINESSENTITYID, 
       NATIONALIDNUMBER, 
       BIRTHDATE, 
       GENDER 
FROM   EMPLOYEE AS M 
WHERE  GENDER = 'F' 
       AND GENDER NOT IN (SELECT GENDER 
                          FROM   EMPLOYEE AS F 
                          WHERE  GENDER = 'M')

Limitaciones de INTERSECT y EXCEPT

  1. No podemos usar EXCEPT e INTERSECT en definiciones de vistas particionadas distribuidas con cláusulas COMPUTE y COMPUTE BY.
  2. EXCEPT e INTERSECT se pueden usar en cursores estáticos y de solo avance rápido.
  3. EXCEPT e INTERSECT se pueden usar en consultas distribuidas, pero solo se pueden ejecutar en el servidor local. No puede ejecutarlos en un servidor remoto.

Resumen

En este artículo, he cubierto:

  1. Los operadores EXCEPT e INTERSECT.
  2. La diferencia entre INTERSECT e INNER JOIN.
  3. Una explicación detallada de los operadores INTERSECT y EXCEPT con un ejemplo.