T-SQL
soporta tres cláusulas de consulta que permiten filtrar los datos basados en los
predicados. Estas son las cláusulas ON, WHERE y HAVING. Este post se centra en
los datos de filtrado con la cláusula WHERE.
Predicados, Lógica de Tres Valores, y Argumentos de Búsqueda
En las primeras
consultas SQL que alguna vez escribió, es muy probable que haya comenzado
utilizando la cláusula WHERE para filtrar los datos basados en los predicados. Inicialmente,
parece un concepto muy simple y directo. Pero con el tiempo, a medida que
adquiera una comprensión más profunda de T-SQL, probablemente se dará cuenta de
que hay aspectos del filtrado que no son tan evidentes. Por ejemplo, necesita
entender cómo interactúan los predicados con los NULLs, y cómo filtra basados
en tales predicados. También es necesario entender cómo formar sus predicados
para maximizar la eficiencia de sus consultas, y para ello, necesita estar
familiarizado con el concepto de argumento
de búsqueda.
Algunos de los ejemplos en
este post utilizan la tabla HR.Employees de la base de datos de muestra
TSQL2012.
Para comenzar con un ejemplo simple, considere la
siguiente consulta, que filtra sólo a los empleados de los Estados Unidos.
SELECT
empid, firstname,
lastname, country,
region, city
FROM
HR.Employees
WHERE
country = N'USA';
Recuerde que un predicado es una expresión lógica. Cuando
los NULLs no son posibles en los datos (en este caso, la columna country es
definida para no permitir NULLs), el predicado puede ser evaluado a Verdadero o
Falso. El tipo de lógica utilizada en tal caso es conocida como lógica de dos valores. El filtro WHERE
retorna solo las filas para el cual el predicado se evalúa a Verdadero. Aquí
está el resultado de esta consulta.
empid firstname
lastname country region
city
------ ---------- ---------
-------- ------- ---------
1 Sara Davis USA WA
Seattle
2 Don Funk USA WA
Tacoma
3 Judy Lew USA WA
Kirkland
4 Yael Peled USA WA
Redmond
8 Maria Cameron
USA WA Seattle
Sin embargo, cuando los NULLs son posibles en los datos,
las cosas se vuelven más complicadas. Considere las columnas de localización de
clientes, país, región y ciudad en la tabla Sales.Customers. Suponga que estas
columnas reflejan la jerarquía de localización basada en la organización de
ventas. Para algunos lugares en el mundo, como en los Estados Unidos, las tres
columnas de ubicación son aplicables; por ejemplo:
Country: USA
Region: WA
City: Seattle
Pero en otros lugares, como el Reino Unido, sólo tienen
dos partes aplicables: el país y la ciudad. En tales casos, la columna región es
establecida a NULL; por ejemplo:
Country: UK
Region: NULL
City: London
Considere entonces una consulta que filtra sólo los
empleados del estado de Washington.
SELECT
empid, firstname,
lastname, country,
region, city
FROM
HR.Employees
WHERE
region = N'WA';
Recordemos que cuando los NULLs son posibles en los
datos, un predicado puede evaluarse a Verdadero, Falso, y Desconocido. Este
tipo de lógica es conocida como la lógica
de tres valores. Cuando se utiliza un operador de igualdad en el predicado
como en la consulta anterior, se obtiene Verdadero cuando ambos operandos no
son NULL e iguales; por ejemplo, WA y WA. Obtiene Falso cuando ambos no son
NULL y diferentes; por ejemplo, OR y WA. Hasta ahora, es sencillo. La parte
difícil es cuando las marcas NULL están involucradas. Obtiene un Desconocido
cuando al menos un operando es NULL; por ejemplo, NULL y WA, o incluso NULL y
NULL.
Como se mencionó, el filtro WHERE retorna las filas para el
cual el predicado se evalúa a Verdadero, significando que descarta ambos casos Falso
y Desconocido. Por lo tanto, la consulta retorna sólo los empleados donde la
región es no NULL e igual a WA, como se muestra en la siguiente.
empid firstname lastname country region city
------ ---------- ---------
-------- ------- ---------
1 Sara Davis USA WA
Seattle
2 Don Funk USA WA
Tacoma
3 Judy Lew USA WA
Kirkland
4 Yael Peled USA WA
Redmond
8 Maria Cameron
USA WA Seattle
Podría considerar este comportamiento como intuitivo,
pero considere una solicitud para retornar sólo los empleados que no son del
estado de Washington.
Escribir la
siguiente consulta:
SELECT
empid, firstname,
lastname, country,
region, city
FROM
HR.Employees
WHERE
region <> N'WA';
Ejecute la consulta y obtiene un conjunto vacío de
vuelta:
empid firstname lastname country region city
------
---------- --------- -------- ------- ---------
¿Puede tener sentido el resultado?
Como
resultado, todos los empleados que no son del estado de Washington, son de UK; recordamos
que la región de lugares en UK es establecida a NULL para indicar que es
inaplicable. Aunque puede serle claro que alguien de UK no es del estado de
Washington, no le es claro a T-SQL. Para T-SQL, un NULL representa un valor faltante
que podría ser aplicable, y podría ser WA como podría ser algo más. Por lo
tanto, no puede concluir con certeza que la región es diferente de WA. En otras
palabras, cuando la región es NULL, el predicado region <> 'WA' es evaluado
a Desconocido, y la fila es descartada. Así como un predicado podría retornar
sólo los casos que no son NULL y es conocido que son diferentes de WA. Por
ejemplo, si tenía un empleado en la tabla con una región NY, tal empleado
debería ser retornado.
Sabiendo que en la tabla Employees una región NULL
representa una región faltante e inaplicable, ¿Cómo hacemos que T-SQL retorne tales
empleados cuando busca lugares donde la región es diferente de WA?
Si está considerando un
predicado tal como region <> N'WA' OR region = NULL, necesita recordar
que dos NULLs no son considerados igual a otro. El resultado de la expresión
NULL = NULL es, de hecho, Desconocido, no es Verdadero. T-SQL proporciona el
predicado IS NULL para retornar Verdadero cuando el operando evaluado es NULL.
Del mismo modo, el predicado IS NOT NULL retorna Verdadero cuando el operando evaluado
no es NULL. Así que la solución a este problema es utilizar la siguiente forma.
SELECT
empid, firstname,
lastname, country,
region, city
FROM
HR.Employees
WHERE
region <> N'WA'
OR region IS NULL;
Aquí está el resultado de esta consulta.
empid firstname lastname country
region city
------ ---------- -------------
-------- ------- -------
5 Sven Buck UK
NULL London
6 Paul Suurs UK NULL London
7 Russell King UK
NULL London
9 Zoya Dolgopyatova UK NULL London
Los filtros de consulta tienen un rendimiento importante
a su lado. Por un lado, por filtrar las filas en la consulta (en lugar de
hacerlo en el cliente), se reduce el tráfico de red. Además, basados en los
filtros de consulta que aparecen en la consulta, SQL Server puede evaluar la
opción para utilizar índices, para obtener los datos eficientemente, sin
requerir una exploración completa de la tabla. Es importante señalar, sin
embargo, que el predicado necesita ser de una forma conocida, como un argumento de búsqueda (SARG) para
permitir el uso eficiente del índice. Aquí, se describirá brevemente el
concepto y se proporciona ejemplos sencillos.
Un
predicado en la forma de columna operador
valor o valor operador columna
puede ser un argumento de búsqueda. Por ejemplo, los predicados como col1=10, y
col1>10 son argumentos de búsqueda. Aplicar la manipulación a la columna
filtrada en la mayoría de los casos, impide al predicado que sea un argumento
de búsqueda. Un ejemplo para la manipulación de la columna filtrada es aplicarle
una función, como en F(col1)=10, donde F es alguna función. Hay algunas
excepciones a esta regla, pero no son muy comunes.
Por ejemplo, suponga que tiene un procedimiento
almacenado que acepta un parámetro de entrada @dt
representando una fecha de envío de entrada. El procedimiento supuestamente retorna
pedidos que fueron enviados en la fecha de entrada. Si la columna shippeddate
no permite NULLs, puede utilizar la siguiente consulta para dirigir esta tarea.
SELECT
orderid, orderdate,
empid
FROM
Sales.Orders
WHERE shippeddate = @dt;
Sin embargo, la columna shippeddate permite NULLs; estos
representan pedidos que no fueron enviados todavía. Cuando los usuarios necesitaran
todos los pedidos que aún no fueron enviados, los usuarios proporcionarán un
NULL como la fecha de envío de entrada, y su consulta podría necesitar hacer
frente a estos casos. Recuerde que cuando comparamos dos NULLs, obtenemos Desconocido
y la fila es filtrada. Así que la forma actual del predicado no direcciona las
entradas NULL correctamente. Algunos dirigen esta necesidad utilizando COALESCE
o ISNULL para sustituir los NULLs con un valor que no existe en los datos
normalmente, como en la siguiente.
SELECT
orderid, orderdate,
empid
FROM
Sales.Orders
WHERE
COALESCE(shippeddate, '19000101') = COALESCE(@dt, '19000101');
El problema es que aunque la solución ahora retorna el
resultado correcto, incluso cuando la entrada es NULL, el predicado no es un
argumento de búsqueda. Esto significa que SQL Server no puede utilizar
eficientemente un índice en la columna shippeddate. Para hacer del predicado un
argumento de búsqueda, es necesario evitar la manipulación de la columna
filtrada y reescribir el predicado como la siguiente.
SELECT
orderid, orderdate,
empid
FROM
Sales.Orders
WHERE
shippeddate = @dt
OR (shippeddate IS NULL AND @dt IS NULL);
Curiosamente, el SQL estándar tiene un
predicado llamado IS NOT DISTINCT FROM que tiene el mismo significado que el
predicado utilizado en la última consulta (retornar Verdadero cuando ambos lados
son iguales o cuando ambas son NULLs, que de otra manera es Falso).
Desafortunadamente, T-SQL no soporta este predicado.
Otro ejemplo de manipulación implica la columna filtrada
en una expresión; por ejemplo, col1-1 <= @n. A veces, puede reescribir el predicado
a una forma que sea un argumento de búsqueda, y que luego permita el uso
eficiente de indexación. El último predicado, por ejemplo, puede ser reescrito
usando matemáticas simples como col1<= @n+1.
En resumen, cuando un predicado involucra
manipulación de la columna filtrada, y hay formas alternativas para expresarlo
sin la manipulación, puede aumentar la probabilidad para un uso eficiente de la
indexación.
Combinando Predicados
Puede
combinar predicados en la cláusula WHERE por utilizar los operadores lógicos
AND y OR. También puede negar predicados por utilizar el operador lógico NOT.
Esta sección comienza por describir los aspectos importantes de la negación y
luego discute los predicados combinados.
La negación de Verdadero y Falso es sencilla, NOT Verdadero
es Falso, y NOT Falso es Verdadero. ¿Lo qué puede sorprenderle a algunos, es lo
que sucede cuando niegas Desconocido, NOT Desconocido aún es Desconocido.
Recuerde
que anteriormente la consulta que retornó todos los empleados del estado de
Washington; la consulta utilizó el predicado region=N'WA' en la cláusula WHERE.
Suponga que quiere retornar los empleados que no son de WA, y para ello utiliza
el predicado NOT region=N'WA'. Está claro que los casos que retornan Falso del
predicado positivo (dicen que la región es NY) retornan Verdadero del predicado
negativo. También está claro que los casos que retornan Verdadero del predicado
positivo (dicen que la región es WA) retornan Falso del predicado negativo. Sin
embargo, cuando la región es NULL, ambos el predicado positivo y negativo
retorna Desconocido y la fila es descartada. Así que la manera correcta para
que incluya casos NULL en el resultado, si es que sabe lo que necesita hacer,
es utilizar el operador IS NULL, como en NOT region=N'WA' OR region IS NULL.
En cuanto a la combinación de predicados, hay varias
cosas interesantes a notar. Algunas reglas de precedencia determinan el orden
de evaluación lógica de los diferentes predicados. El operador NOT precede a
AND y OR, y AND precede a OR. Por ejemplo, suponga que el filtro WHERE en su
consulta tiene la siguiente combinación de predicados.
WHERE
col1 = 'w' AND col2 = 'x' OR col3 = 'y' AND col4 = 'z'
Debido a que AND precede a OR, se obtiene el equivalente al
siguiente.
WHERE
(col1 = 'w' AND col2 = 'x') OR (col3 = 'y' AND col4 = 'z')
Tratando de expresar los operadores como seudo funciones,
esta combinación de operadores es equivalente a OR(AND(col1='w', col2='x'), AND(col3='y',
col4='z')).
Debido a que los paréntesis tienen la precedencia más
alta entre todos los operadores, siempre puede utilizarlos para controlar
totalmente el orden de evaluación lógica que necesita, como muestra el
siguiente ejemplo.
WHERE col1 = 'w' AND (col2 = 'x' OR col3 = 'y') AND col4 = 'z'
Una vez más, usando seudo
funciones, esta combinación de operadores y el uso de paréntesis es equivalente
a AND(col1='w', OR(col2='x', col3='y'), col4='z').
Recuerde que todas las
expresiones que aparecen en la misma fase de procesamiento de consulta lógica, por
ejemplo, la fase WHERE, es conceptualmente evaluada en el mismo punto en el
tiempo. Por ejemplo, considere el siguiente predicado de filtro.
WHERE
propertytype = 'INT'
AND CAST(propertyval AS INT) > 10
Suponga que la tabla que está siendo consultada mantiene
diferentes valores de propiedad. La columna propertytype representa el tipo de
propiedad (un INT, un DATE, y así sucesivamente), y la columna propertyval
mantiene el valor en una cadena de caracteres. Cuando el propertytype es 'INT',
el valor en propertyval es convertible a INT; de otra forma, no necesariamente.
Algunos asumen que a menos que las reglas de precedencia
dicten lo contrario, los predicados serán evaluados de izquierda a derecha, y que
los cortocircuitos tendrán lugar cuando sea posible. En otras palabras, si el
primer predicado propertytype='INT' se evalúa a Falso, SQL Server no evalúa el
segundo predicado CAST(propertyval AS INT)>10 porque el resultado es ya
conocido. Basado en este supuesto, la expectativa es que la consulta nunca
debería fallar, tratando de convertir algo que no es convertible.
La realidad, sin embargo, es diferente. SQL Server
soporta internamente un concepto de cortocircuito; sin embargo, debido al
concepto de todo en uno en el lenguaje, no necesariamente evaluará las
expresiones en orden de izquierda a derecha. Podría decidir, basado en razones
relativo a costos, comenzar con la segunda expresión, y luego, si la segunda
expresión se evalúa a Verdadero, evaluar la primera expresión también. Esto
significa que si hay filas en la tabla donde propertytype es diferente a ‘INT’,
y en esas filas propertyval no son convertibles a INT, la consulta puede fallar
debido a un error de conversión.
Puede hacer frente a
este problema en un número de maneras. Una opción sencilla es utilizar la
función TRY_CAST en lugar de CAST. Cuando la expresión de entrada no es
convertible al tipo de destino, TRY_CAST retorna un NULL en lugar de fallar. La
comparación de un NULL a algo produce Desconocido. Eventualmente, obtendrá el
resultado correcto, sin permitir a la consulta a fallar. Así que su cláusula
WHERE debe ser revisada como en la siguiente.
WHERE
propertytype = 'INT'
AND TRY_CAST(propertyval
AS INT) > 10
Filtrando Datos Carácter
En muchos aspectos, el
filtrado de datos carácter es lo mismo que el filtrado de otros tipos de datos.
Esta sección cubre un par de elementos que son específicos a los datos
carácter: la forma apropiada de literales y el predicado LIKE.
Un literal tiene un
tipo. Si se escribe una expresión que implica operandos de diferentes tipos,
SQL Server tendrá que aplicar la conversión implícita para alinear los tipos.
Dependiendo de las circunstancias, las conversiones implícitas a veces pueden
perjudicar el rendimiento. Es importante conocer la forma apropiada de
literales de diferentes tipos y asegurarse de usar las correctas. Un ejemplo
clásico para el uso de tipos literales incorrectos es con las cadenas de
caracteres Unicode (tipos NCHAR y NVARCHAR). La forma correcta para un literal
de cadena de caracteres Unicode es poner prefijos al literal con una N
mayúscula y delimitar el literal con comillas simples; por ejemplo, N'literal'.
Para un literal de cadena de caracteres regulares, solo se delimita el literal
con comillas simples; por ejemplo, ‘literal’. Es un mal hábito muy típico,
especificar un literal de cadena de caracteres regulares cuando la columna
filtrada es de un tipo Unicode, como en el siguiente ejemplo.
SELECT
empid, firstname,
lastname
FROM
HR.Employees
WHERE lastname = 'Davis';
Debido a que la columna y el literal tienen diferentes
tipos, SQL Server convierte implícitamente un tipo de operando a otro. En este
ejemplo, afortunadamente, SQL Server convierte el tipo del literal al tipo de
la columna, así que aún puede confiar eficientemente en la indexación. Sin
embargo, puede haber casos donde la conversión implícita perjudique el
rendimiento. Es una buena práctica usar la forma adecuada, como en la
siguiente.
SELECT
empid, firstname,
lastname
FROM
HR.Employees
WHERE lastname = N'Davis';
T-SQL proporciona el predicado LIKE, que puede utilizar
para filtrar los datos de cadena de caracteres (regulares y Unicode) basados en
la coincidencia de patrones. La forma de un predicado utilizando LIKE es como
sigue.
<column> LIKE <pattern>
El
predicado LIKE soporta comodines que puede utilizar en sus patrones. La Tabla describe
los comodines disponibles, su significado, y un ejemplo que muestra su uso.
Como un ejemplo, suponga que desea retornar todos los
empleados cuyo apellido comienza con la letra D. Se podría utilizar la
siguiente consulta.
SELECT
empid, firstname,
lastname
FROM
HR.Employees
WHERE
lastname LIKE N'D%';
Esta consulta retorna el siguiente resultado.
empid
firstname lastname
------
---------- -------------
1
Sara Davis
9
Zoya Dolgopyatova
Si desea buscar un carácter que es considerado un
comodín, puede indicarle después un carácter que se designe como un carácter de
escape por utilizar la palabra clave ESCAPE. Por ejemplo, la expresión col1
LIKE '!_%' ESCAPE '!' busca cadenas que comienzan con un guión bajo (_) utilizando
un signo de exclamación (!) como el carácter de escape.
Rendimiento
del Predicado LIKE
Cuando el patrón LIKE comienza
con un prefijo conocido, por ejemplo, col LIKE 'ABC%', SQL Server puede potencialmente
utilizar eficientemente un índice sobre la columna filtrada; en otras palabras,
SQL Server puede confiar en el orden de los índices. Cuando el patrón comienza
con un comodín, por ejemplo, col LIKE '%ABC%', SQL Server no puede confiar más en
el orden de los índices. También, cuando busca una cadena que empieza con un
prefijo conocido (digamos, ABC) asegúrese de utilizar el predicado LIKE, como
en col LIKE 'ABC%', porque esta forma es considerada un argumento de búsqueda.
Recordemos que aplicando la manipulación a la columna filtrada impide al
predicado a ser un argumento de búsqueda. Por ejemplo, la forma LEFT(col,
3)='ABC' no es un argumento de búsqueda y evitará a SQL Server de poder utilizar
un índice eficientemente.
Filtrando Datos Date y Time
Hay
varias consideraciones importantes cuando filtra los datos Date y Time que
están relacionados tanto a la exactitud de su código y a su rendimiento. Quiere
pensar en cosas como la forma de expresar literales, rangos de filtro, y usar
argumentos de búsqueda.
Empezará con literales. Suponga que necesita consultar la
tabla Sales.Orders y retornar sólo los pedidos realizados el 12 de febrero del
2007. Se utiliza la siguiente consulta.
SELECT orderid,
orderdate, empid,
custid
FROM Sales.Orders
WHERE orderdate = '02/12/07';
Si es americano, esta forma probablemente signifique el
12 de febrero del 2007. Sin embargo, si es británico, esta forma probablemente
le signifique el 2 de diciembre del 2007. Si es japonés, probablemente el
signifique el 7 de diciembre del 2002. La pregunta es, cuando SQL Server
convierte esta cadena de carácter a un tipo de fecha y de hora para alinearlo
con el tipo de la columna filtrada, ¿Cómo interpreta el valor? Pues resulta,
que depende del idioma del inicio de sesión que ejecuta el código. Cada inicio
de sesión tiene un idioma predeterminado asociado, y el idioma predeterminado
establece varias opciones de sesión sobre los inicios de sesión, incluyendo uno
llamado DATEFORMAT. Un inicio de sesión con us_english tendrá el ajuste DATEFORMAT
establecido a mdy, el británico a dmy y el japonés a ymd. El problema es, ¿Cómo
un desarrollador expresa una fecha si quiere que sea interpretado de la manera
del destinatario, sin importar quien ejecuta su código?
Hay dos enfoques principales. Una es usar una forma que es
considerada independiente del idioma. Por ejemplo, la forma '20070212' es siempre
interpretada como ymd, independientemente de su idioma. Note que la forma
'2007-02-12' es considerada independiente del idioma sólo para los tipos de
datos DATE, DATETIME2 y DATETIMEOFFSET. Lamentablemente, debido a razones
históricas, esta forma es considerada dependiente del idioma para los tipos
DATETIME y SMALLDATETIME. La ventaja de la forma sin los separadores es que es
independiente del idioma para todos los tipos de fecha y de hora. Así que la
recomendación es escribir la consulta como en la siguiente.
SELECT
orderid, orderdate,
empid, custid
FROM
Sales.Orders
WHERE orderdate = '20070212';
Almacenar
Fechas en una Columna DATETIME
La columna filtrada orderdate
es de un tipo de datos DATETIME que representa tanto la fecha y la hora. Aún,
el literal especificado en el filtro contiene sólo una parte de fecha. Cuando
SQL Server convierte el literal al tipo de la columna filtrada, se asume la medianoche
cuando una parte del tiempo no está indicada. Si quiere un filtro para retornar
todas las filas de la fecha especificada, es necesario asegurarse que almacena
todos los valores con la medianoche como la hora.
Otro enfoque es utilizar las funciones CONVERT o PARSE,
que puede utilizar para indicar cómo quiere que SQL Server interprete el
literal que especifique. La función CONVERT soporta un número de estilo
representando el estilo de conversión, y la función PARSE soporta indicar un
nombre de cultura.
Otro aspecto importante del filtrado de datos de fecha y de
hora es tratar siempre que sea posible utilizar los argumentos de búsqueda. Por
ejemplo, suponga que necesita filtrar sólo los pedidos realizados en febrero del
2007. Puede utilizar las funciones YEAR y MONTH, como en la siguiente.
SELECT
orderid, orderdate,
empid, custid
FROM
Sales.Orders
WHERE
YEAR(orderdate) = 2007 AND MONTH(orderdate) = 2;
Sin embargo, ya que aquí aplica la manipulación de la
columna filtrada, el predicado no es considerado un argumento de búsqueda, y
por lo tanto, SQL Server no podrá confiar en el ordenado del índice. Podría
revisar su predicado como un rango, como la siguiente.
SELECT
orderid, orderdate,
empid, custid
FROM
Sales.Orders
WHERE
orderdate >= '20070201'
AND orderdate <
'20070301';
Ahora que no aplica la manipulación a la columna
filtrada, el predicado es considerado un argumento de búsqueda, y hay la
posibilidad de que SQL Server confíe en el ordenado del índice.
Si se pregunta por qué este código expresa el rango de
fechas utilizando los operadores mayor o igual que (> =) y menor que (<)
en lugar de utilizar BETWEEN, hay una razón para ello. Cuando utiliza BETWEEN y
la columna mantiene tanto los elementos de fecha y de hora, ¿Qué utiliza como
el valor final? Como puede darse cuenta, para los diferentes tipos, hay
diferentes precisiones. Es más, suponga que el tipo es DATETIME, y se utiliza
el siguiente predicado.
WHERE
orderdate BETWEEN '20070201'
AND '20070228
23:59:59.999'
La precisión del tipo es tres y un tercio de milisegundos.
La parte de milisegundos del punto final 999 no es una multiplicación de la
unidad de precisión, por lo que SQL Server termina redondeando el valor a
medianoche del 1 de marzo del 2007. Como resultado, puede terminar obteniendo
algunos pedidos que no se supone que vea. En pocas palabras, en lugar de BETWEEN,
use >= y <, y esta forma funcionará correctamente en todos los casos, con
todos los tipos de fecha y de hora, así la porción de tiempo sea aplicable o
no.
Ejercicio 1: Usar la Cláusula WHERE para Filtrar Filas con NULLs
En
este ejercicio, practica el uso de la cláusula WHERE para filtrar los pedidos
no enviados de la tabla Sales.Orders.
1. Abra el SSMS y conéctese a la base de
datos de muestra TSQL2012.
2. Se le pedirá que escriba una consulta que
retorne los pedidos que no se enviaron aún. Dichos pedidos tienen un NULL en la
columna shippeddate. Para su primer intento, utilice la siguiente consulta.
SELECT orderid, orderdate, custid, empid
FROM Sales.Orders
WHERE
shippeddate = NULL;
Sin embargo, cuando ejecuta este
código, se obtiene un conjunto de resultado vacío.
orderid
orderdate custid empid
-----------
----------------------- ----------- -----------
La razón para esto es que cuando la
expresión compare dos NULLs, el resultado es Desconocido, y la fila es filtrada.
3. Revisar el predicado de filtro para
utilizar el operador IS NULL en lugar de la igualdad (=), como en la siguiente.
SELECT orderid, orderdate, custid, empid
FROM Sales.Orders
WHERE
shippeddate IS NULL;
Esta vez, obtiene el resultado
correcto, mostrado en forma abreviada.
orderid
orderdate custid empid
-----------
----------------------- ----------- -----------
11008 2008-04-08
00:00:00.000 20 7
11019 2008-04-13
00:00:00.000 64 6
11039 2008-04-21
00:00:00.000 47 1
...
Ejercicio 2: Usar la Cláusula WHERE para Filtrar un Rango de Fechas
En
este ejercicio, practica el uso de la cláusula WHERE para filtrar los pedidos en
un cierto rango de fechas de la tabla Sales.Orders.
1. Se le pide retornar todos los pedidos que
fueron colocados entre el 11 de febrero del 2008 y el 12 de febrero del 2008.
La columna orderdate por la que se supone filtra es de un tipo DATETIME. Con
los datos actuales en la tabla, todos los valores orderdate tienen el tiempo
establecido a medianoche, pero suponga que este no es el caso, a saber, que la
porción de tiempo podría ser un valor distinto de la medianoche. Para su primer
intento, utilice el predicado BETWEEN, de la siguiente manera.
SELECT orderid, orderdate, custid, empid
FROM Sales.Orders
WHERE
orderdate BETWEEN '20080211'
AND '20080212
23:59:59.999';
Debido a que 999 no es una
multiplicación de la unidad de precisión del tipo DATETIME (tres y un tercio de
milisegundos), el valor final en el rango será redondeada a la próxima medianoche,
y el resultado incluye filas del 13 de febrero que no solicitó.
orderid
orderdate custid empid
-----------
----------------------- ----------- -----------
10881 2008-02-11
00:00:00.000 12 4
10887 2008-02-13
00:00:00.000 29 8
10886 2008-02-13
00:00:00.000 34 1
10884 2008-02-12
00:00:00.000 45 4
10883 2008-02-12
00:00:00.000 48 8
10882 2008-02-11
00:00:00.000 71 4
10885 2008-02-12 00:00:00.000 76 6
2. Para corregir el problema, revise el filtro
del rango para usar los operadores >= y <, de la siguiente manera.
SELECT orderid, orderdate, custid, empid
FROM Sales.Orders
WHERE
orderdate >= '20080211'
AND orderdate <
'20080213';
Esta vez, se obtiene el resultado
correcto.
Este post nos muestra el filtrado con Where. Espero les sea de utilidad.
ResponderBorrar