Sintaxis del servidor SQL. Variables del sistema global. Volvamos a DDL por un momento.

En la primera parte ya tocamos un poco el lenguaje DML, utilizando casi todo el conjunto de sus comandos, a excepción del comando MERGE.

Hablaré de DML según mi propia secuencia, desarrollada a partir de mi experiencia personal. En el camino, también intentaré hablar sobre los lugares "resbaladizos" en los que vale la pena centrarse; estos lugares "resbaladizos" son similares en muchos dialectos del lenguaje SQL.

Porque el libro de texto está dedicado a a un amplio círculo lectores (no sólo programadores), entonces la explicación a veces será apropiada, es decir, largo y tedioso. Esta es mi visión del material, que se obtuvo principalmente en la práctica como resultado de la actividad profesional.

Objetivo principal este libro de texto, paso a paso, desarrolle una comprensión completa de la esencia del lenguaje SQL y enseñe cómo aplicar correctamente sus construcciones. Los profesionales en este campo también pueden estar interesados ​​en desplazarse este material, tal vez puedan aprender algo nuevo por sí mismos, o tal vez simplemente les resulte útil leer para refrescar su memoria. Espero que todos lo encuentren interesante.

Porque DML en el dialecto de la base de datos MS SQL está muy relacionado con la sintaxis de la construcción SELECT, por lo que comenzaré a hablar de DML con él. En mi opinión, la construcción SELECT es la construcción más importante en el lenguaje DML, porque gracias a él o a sus partes, los datos necesarios se recuperan de la base de datos.

El lenguaje DML contiene las siguientes construcciones:

  • SELECCIONAR – selección de datos
  • INSERTAR – insertar nuevos datos
  • ACTUALIZACIÓN – actualización de datos
  • BORRAR – eliminar datos
  • FUSIONAR – fusión de datos

En esta parte, veremos solo la sintaxis básica del comando SELECT, que se ve así:

SELECCIONE column_list o * DESDE la fuente DONDE filtrar ORDEN POR sort_expression
El tema de la declaración SELECT es muy amplio, por lo que en esta parte me centraré sólo en sus construcciones básicas. Creo que sin conocer bien los conceptos básicos no se puede empezar a estudiar estructuras más complejas, porque entonces todo girará en torno a este diseño básico (subconsultas, uniones, etc.).

Además, como parte de esta parte, también hablaré de la oferta TOP. Intencionalmente no indiqué esta oración en la sintaxis básica, porque... se implementa de manera diferente en diferentes dialectos SQL.

Si el lenguaje DDL es más estático, es decir con su ayuda, se crean estructuras rígidas (tablas, relaciones, etc.), luego el lenguaje DML es de naturaleza dinámica, aquí puede obtener los resultados correctos de diferentes maneras.

El entrenamiento también continuará en modo Paso a Paso, es decir. Al leer, debes intentar inmediatamente completar el ejemplo con tus propias manos. Luego analizas el resultado obtenido e intentas comprenderlo de forma intuitiva. Si algo no queda claro, por ejemplo el significado de una función, busque ayuda en Internet.

Los ejemplos se mostrarán en la base de datos de prueba, que se creó usando DDL+DML en la primera parte.

Para aquellos que no crearon una base de datos en la primera parte (ya que es posible que no todos estén interesados ​​en el lenguaje DDL), pueden usar el siguiente script:

Script de creación de base de datos de prueba

Crear una base de datos CREAR BASE DE DATOS Prueba GO: actualizar la base de datos de prueba USAR Prueba GO: crear tablas de referencia CREAR TABLA Posiciones (ID int IDENTIDAD (1,1) NO NULO CONSTRAINT PK_Positions PRIMARY KEY, Nombre nvarchar(30) NOT NULL) CREAR TABLA Departamentos(ID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Departments PRIMARY KEY, Nombre nvarchar(30) NOT NULL) GO - llenar las tablas de referencia con datos SET IDENTITY_INSERT Posiciones ON INSERT Posiciones(ID,Nombre)VALUES (1,N"Contable"), (2,N"Director"), (3,N"Programador"), (4,N"Programador senior") SET IDENTITY_INSERT Posiciones OFF GO SET IDENTITY_INSERT Departamentos ON INSERT Departamentos(ID,Nombre)VALUES (1,N"Administración"), (2,N"Contabilidad"), (3,N"IT") SET IDENTITY_INSERT Departamentos OFF GO - crear una tabla con empleados CREAR TABLA Empleados(ID int NOT NULL, Nombre nvarchar(30), Fecha de cumpleaños, Correo electrónico nvarchar(30), ID de posición int, ID de departamento int, Fecha de contratación fecha NOT NULL CONSTRAINT DF_Employees_HireDate DEFAULT SYSDATETIME(), ManagerID int, CONSTRAINT PK_Employees PRIMARY KEY (ID), CONSTRAINT FK_Employees_DepartmentID CLAVE EXTRANJERA (ID de departamento) REFERENCIAS Departamentos (ID), RESTRICCIÓN FK_Employees_PositionID CLAVE EXTRANJERA (ID de posición) REFERENCIAS Posiciones (ID), RESTRICCIÓN FK_Employees_ManagerID CLAVE EXTRANJERA (ID de gerente) REFERENCIAS Empleados (ID), CONSTRAINT UQ_ Emp loyees_Email ÚNICO (correo electrónico) , CONSTRAINT CK_Employees_ID CHECK (ID ENTRE 1000 Y 1999), INDEX IDX_Employees_Name(Nombre)) GO - rellénelo con datos INSERTAR Empleados (ID,Nombre,Cumpleaños,Correo electrónico,ID de posición,ID de departamento,ID de gerente)VALUES (1000,N"Ivanov I.I. ", "19550219"," [correo electrónico protegido]",2,1,NULL), (1001,N"Petrov P.P.","19831203"," [correo electrónico protegido]",3,3,1003), (1002,N"Sidorov S.S.","19760607"," [correo electrónico protegido]",1,2,1000), (1003,N"Andreev A.A.","19820417"," [correo electrónico protegido]",4,3,1000)

Eso es todo, ahora estamos listos para comenzar a aprender el lenguaje DML.

SELECT – operador de selección de datos

En primer lugar, para el editor de consultas activo, hagamos la prueba de la base de datos actual seleccionándola en la lista desplegable o usando el comando "UTILIZAR Prueba".

Comencemos con la forma más básica de SELECT:

SELECCIONAR * DE Empleados
En esta consulta, solicitamos devolver todas las columnas (indicadas por un "*") de la tabla Empleados; puede leer esto como "SELECCIONAR todos los campos DE la tabla de empleados". Si hay un índice agrupado, lo más probable es que los datos devueltos se ordenen por él, en en este caso por columna ID (pero esto no es importante, ya que en la mayoría de los casos indicaremos ordenar en explícitamente usted mismo usando ORDER BY...):

IDENTIFICACIÓN Nombre Cumpleaños Correo electrónico ID de posición ID de departamento Fecha de contratación ID del administrador
1000 Ivánov I.I. 1955-02-19 [correo electrónico protegido] 2 1 2015-04-08 NULO
1001 Petrov P.P. 1983-12-03 [correo electrónico protegido] 3 3 2015-04-08 1003
1002 Sidorov S.S. 1976-06-07 [correo electrónico protegido] 1 2 2015-04-08 1000
1003 Andréyev A.A. 1982-04-17 [correo electrónico protegido] 4 3 2015-04-08 1000

En general, vale la pena decir que en el dialecto MS SQL la mayoría forma sencilla Es posible que la consulta SELECT no contenga un bloque FROM, en cuyo caso puede usarlo para obtener algunos valores:

SELECT 5550/100*15, SYSDATETIME(), - obteniendo la fecha del sistema de base de datos SIN(0)+COS(0)

(Sin nombre de columna) (Sin nombre de columna) (Sin nombre de columna)
825 2015-04-11 12:12:36.0406743 1

Tenga en cuenta que la expresión (5550/100*15) dio como resultado 825, aunque si calculamos en una calculadora el valor será (832,5). El resultado 825 se obtuvo porque en nuestra expresión todos los números son enteros, por lo tanto el resultado es un número entero, es decir (5550/100) nos da 55, no (55,5).

Recuerde que la siguiente lógica funciona en MS SQL:

  • Entero / Entero = Entero (es decir, en este caso hay división entera)
  • Real / Entero = Real
  • Entero / Real = Real
Aquellos. el resultado se convierte a tipo más grande, entonces en los últimos 2 casos obtenemos un número real (piense como en matemáticas: rango números reales es mayor que el rango de números enteros, por lo que el resultado se convierte a él):

SELECCIONE 123/10, -- 12 123./10, -- 12,3 123/10. -- 12.3
Aquí (123.) = (123.0), es solo que en este caso se puede descartar 0 y solo queda el punto.

Con otros operaciones aritméticas Se aplica la misma lógica, sólo que en el caso de la división este matiz es más relevante.

Así que presta atención al tipo de datos. columnas numéricas. Si es un número entero y necesita obtener un resultado real, utilice una transformación o simplemente coloque un punto después del número indicado como constante (123.).

Puede utilizar la función CAST o CONVERT para convertir campos. Por ejemplo, usemos el campo ID, es de tipo int:

SELECT ID, ID/100, -- la división entera ocurrirá aquí CAST(ID AS float)/100, -- use la función CAST para convertir al tipo flotante CONVERT(float,ID)/100, -- use la función CONVERT para convertir al tipo float ID/100. -- use la transformación especificando que el denominador es un número real DE Empleados

IDENTIFICACIÓN (Sin nombre de columna) (Sin nombre de columna) (Sin nombre de columna) (Sin nombre de columna)
1000 10 10 10 10.000000
1001 10 10.01 10.01 10.010000
1002 10 10.02 10.02 10.020000
1003 10 10.03 10.03 10.030000

Sólo una nota. En la base de datos ORACLE, la sintaxis sin un bloque FROM es inaceptable, para ello se utiliza la tabla del sistema DUAL, que contiene una línea:

SELECCIONE 5550/100*15, -- y en ORACLE el resultado será igual a 832.5 sysdate, sin(0)+cos(0) FROM DUAL


Nota. El nombre de la tabla en muchos RDB puede ir precedido del nombre del esquema:

SELECCIONAR * DE dbo.Employees -- dbo – nombre del esquema

Un esquema es una unidad lógica de una base de datos, que tiene su propio nombre y permite agrupar objetos de la base de datos como tablas, vistas, etc. dentro de sí misma.

La definición de un esquema en diferentes bases de datos puede diferir; en algunos casos, el esquema está directamente relacionado con el usuario de la base de datos, es decir. en este caso, podemos decir que el esquema y el usuario son sinónimos y todos los objetos creados en el esquema son esencialmente objetos de este usuario. En M.S. esquema SQL es una unidad lógica independiente que se puede crear por sí sola (consulte CREAR ESQUEMA).

De forma predeterminada, se crea un esquema en la base de datos MS SQL con el nombre dbo (Propietario de la base de datos) y listo. objetos creados de forma predeterminada, se crean en este esquema. En consecuencia, si simplemente especificamos el nombre de una tabla en una consulta, se buscará en el esquema dbo de la base de datos actual. Si queremos crear un objeto en esquema específico, también tendremos que anteponer el nombre del objeto con el nombre del esquema, por ejemplo, “CREATE TABLE nombre_esquema.nombre_tabla(...)”.

En el caso de MS SQL, el nombre del esquema también puede ir precedido del nombre de la base de datos en la que se encuentra el esquema:

SELECCIONAR * DE Test.dbo.Employees - nombre_base_datos.nombre_esquema.tabla
Esta aclaración puede resultar útil, por ejemplo, si:

  • en una solicitud accedemos a objetos ubicados en diferentes esquemas o bases de datos
  • necesita transferir datos de un esquema o base de datos a otro
  • Al estar en una base de datos, necesita solicitar datos de otra base de datos.
  • etc.
Un esquema es una herramienta muy conveniente que resulta útil al desarrollar una arquitectura de base de datos, especialmente bases de datos grandes.

Además, no olvide que en el texto de la solicitud podemos utilizar comentarios tanto de una sola línea “-- ...” como de varias líneas “/* ... */”. Si la solicitud es grande y compleja, los comentarios pueden ser de gran ayuda para usted o para otra persona, después de un tiempo, a recordar o comprender su estructura.

Si hay muchas columnas en la tabla, y especialmente si todavía hay muchas filas en la tabla, además si estamos realizando consultas a la base de datos a través de la red, entonces sería preferible seleccionar con un listado directo de los campos que necesitas, separados por comas:

SELECCIONAR ID, Nombre DE Empleados

Aquellos. aquí decimos que solo necesitamos devolver los campos ID y Nombre de la tabla. El resultado será el siguiente (por cierto, el optimizador aquí decidió usar el índice creado por el campo Nombre):

IDENTIFICACIÓN Nombre
1003 Andréyev A.A.
1000 Ivánov I.I.
1001 Petrov P.P.
1002 Sidorov S.S.

Sólo una nota. A veces resulta útil observar cómo se recuperan los datos, por ejemplo, para saber qué índices se utilizan. Esto se puede hacer haciendo clic en el botón "Mostrar plan de ejecución estimado" o configurando "Incluir plan de ejecución real - Incluir el plan de ejecución de consulta real en el resultado" (en este caso, solo podremos ver el plan real, respectivamente). después de ejecutar la solicitud):

El análisis del plan de ejecución es muy útil al optimizar una consulta; le permite descubrir qué índices faltan o qué índices no se utilizan en absoluto y se pueden eliminar.

Si acaba de comenzar a aprender DML, entonces esto ya no es tan importante para usted, simplemente tome nota y podrá olvidarse de ello con seguridad (tal vez nunca lo necesite): nuestro objetivo inicial es aprender los conceptos básicos del lenguaje DML y aprenda a utilizarlos correctamente y la optimización ya es un arte aparte. A veces es más importante que simplemente tenga una consulta escrita correctamente que devuelva el resultado correcto desde el punto de vista del tema y que ya se esté optimizando. individuos. Primero, debe aprender a escribir consultas correctamente, utilizando cualquier medio para lograr el objetivo. El objetivo principal que debe alcanzar ahora es que su consulta arroje los resultados correctos.

Configuración de alias de tablas

Al enumerar columnas, pueden ir precedidas del nombre de la tabla ubicada en el bloque FROM:

SELECCIONE Empleados.ID, Empleados.Nombre DE Empleados

Pero esta sintaxis suele ser incómoda de usar, porque el nombre de la tabla puede ser largo. Para estos efectos, más nombres cortos– alias:

SELECCIONE emp.ID,emp.Nombre DE Empleados COMO emp
o

SELECCIONE emp.ID, emp.Name DE Empleados emp - palabra clave AS se puede liberar (prefiero esta opción)

Aquí emp es un alias para la tabla Empleados que se puede usar en el contexto de esta declaración SELECT. Aquellos. podemos decir que en el contexto de esta declaración SELECT le estamos dando a la tabla un nuevo nombre.

Por supuesto, en este caso, los resultados de la consulta serán exactamente los mismos que para "SELECCIONAR ID, Nombre DE Empleados". Por qué es necesario esto quedará claro más adelante (ni siquiera en esta parte), por ahora solo recordamos que el nombre de la columna puede ir precedido (aclarado) ya sea directamente por el nombre de la tabla o usando un alias. Aquí puedes usar una de dos cosas, es decir. Si establece un alias, deberá usarlo, pero ya no podrá usar el nombre de la tabla.

Sólo una nota. En ORACLE, sólo se permite la opción de especificar un alias de tabla sin la palabra clave AS.

DISTINCT – descartando filas duplicadas

La palabra clave DISTINCT se utiliza para descartar filas duplicadas del resultado de la consulta. En términos generales, imagine primero ejecutar una consulta sin la opción DISTINCT y luego descartar todos los duplicados del resultado. Demostremos esto para mayor claridad usando un ejemplo:

Creemos una tabla temporal para demostración CREATE TABLE #Trash(ID int NOT NULL PRIMARY KEY, Col1 varchar(10), Col2 varchar(10), Col3 varchar(10)) - llenar esta mesa todo tipo de basura INSERT #Trash(ID,Col1,Col2,Col3)VALUES (1,"A","A","A"), (2,"A","B","C"), ( 3, "C","A","B"), (4,"A","A","B"), (5,"B","B","B"), (6, "A ","A","B"), (7,"A","A","A"), (8,"C","A","B"), (9,"C ", "A","B"), (10,"A","A","B"), (11,"A",NULL,"B"), (12,"A",NULL, "B ") - veamos qué devuelve la consulta sin la opción DISTINCT SELECT Col1,Col2,Col3 FROM #Papelera - veamos qué devuelve la consulta con la opción DISTINCT SELECT DISTINCT Col1,Col2,Col3 FROM #Papelera - eliminar la tabla temporal DROP TABLE #Trash

Visualmente se verá así (todos los duplicados están marcados con el mismo color):

Ahora veamos dónde se puede aplicar esto, usando un ejemplo más práctico: solo regresaremos identificadores únicos departamentos (es decir, descubrimos los ID de los departamentos en los que están registrados los empleados):

SELECCIONAR ID de departamento DISTINTO DE Empleados

Aquí tenemos 4 líneas, porque... No hay combinaciones repetidas (DepartmentID, PositionID) en nuestra tabla.

Volvamos a DDL por un momento.

Dado que estamos empezando a quedarnos sin datos para ejemplos de demostración y queremos hablar de manera más amplia y clara, ampliemos un poco nuestra tabla de Empleados. Además, recordemos un poco de DDL, como dicen, “la repetición es la madre del aprendizaje”, y además, avancemos un poco nuevamente y apliquemos la declaración ACTUALIZAR:

Creamos nuevas columnas ALTER TABLE Employees ADD LastName nvarchar(30), -- apellido FirstName nvarchar(30), -- primer nombre MiddleName nvarchar(30), -- segundo nombre Salario flotante, -- y por supuesto salario en algunas unidades BonusPercent flotante - porcentaje para calcular el bono del salario GO - complételos con datos (algunos datos se omiten intencionalmente) ACTUALIZAR Empleados SET LastName=N"Ivanov", FirstName=N"Ivan", MiddleName=N"Ivanovich", Salario=5000, BonusPercent= 50 DONDE ID=1000 -- Ivanov I.I. ACTUALIZAR Empleados SET Apellido=N"Petrov",Nombre=N"Petr",SegundoNombre=N"Petrovich", Salario=1500, BonusPercent= 15 WHERE ID=1001 -- Petrov P.P. ACTUALIZAR Empleados SET Apellido=N"Sidor",Nombre=N"Sidor",SegundoNombre=NULL, Salario=2500,BonusPercent=NULL WHERE ID=1002 -- Sidorov S.S. ACTUALIZAR Empleados SET Apellido=N"Andreev",Nombre=N"Andrey",SegundoNombre=NULL, Salario=2000,BonusPercent= 30 WHERE ID=1003 -- Andreev A.A.

Asegurémonos de que los datos se hayan actualizado correctamente:

SELECCIONAR * DE Empleados

IDENTIFICACIÓN Nombre Apellido Nombre de pila Segundo nombre Salario BonificaciónPorcentaje
1000 Ivánov I.I. Ivánov Iván Ivánovich 5000 50
1001 Petrov P.P. petrov Pedro Petróvich 1500 15
1002 Sidorov S.S. Sidorov sidor NULO 2500 NULO
1003 Andréyev A.A. andréyev andrés NULO 2000 30

Establecer alias para columnas de consulta

Creo que será más fácil mostrarlo aquí que escribirlo:

SELECCIONAR: proporcione el nombre a la columna calculada Apellido+" "+Nombre+" "+Segundo nombre COMO Nombre completo, - use comillas dobles, porque Se utiliza el espacio HireDate AS "Fecha de recepción", -- utilice corchetes, porque se utiliza espacio Cumpleaños AS [Fecha de nacimiento], -- la palabra AS no es necesaria Salario ZP DE Empleados

nombre completo Fecha de admisión Fecha de nacimiento ZP
Ivanov Ivan Ivanovich 2015-04-08 1955-02-19 5000
Petrov Petr Petrovich 2015-04-08 1983-12-03 1500
NULO 2015-04-08 1976-06-07 2500
NULO 2015-04-08 1982-04-17 2000

Como podemos ver, los alias de columna que especificamos se reflejan en el encabezado de la tabla resultante. En realidad, este es el objetivo principal de los alias de columnas.

Tenga en cuenta, porque los últimos 2 empleados no tenían un segundo nombre especificado (valor NULL), entonces el resultado de la expresión “Apellido+" "+Nombre+" "+Segundo Nombre" también nos devolvió NULL.

Para unir (agregar, concatenar) cadenas en MS SQL, se utiliza el símbolo “+”.

Recuerde que todas las expresiones que involucran NULL (por ejemplo, división por NULL, suma con NULL) devolverán NULL.

Sólo una nota.
En el caso de ORACLE, el operador “||” se utiliza para concatenar cadenas y la concatenación se vería como "Apellido||" "||Nombre||" "||Segundo nombre". Para ORACLE, vale la pena señalar que tiene una excepción para los tipos de cadena, para ellos NULL y la cadena vacía "" son lo mismo, por lo que en ORACLE dicha expresión devolverá para los últimos 2 empleados "Sidorov Sidor" y "Andrey Andréiev”. En el momento de ORACLE 12c, hasta donde yo sé, no hay ninguna opción que cambie este comportamiento (si me equivoco, corríjame). Aquí me resulta difícil juzgar si esto es bueno o malo, porque... En algunos casos, el comportamiento de una cadena NULL es más conveniente, como en MS SQL, y en otros, como en ORACLE.

En ORACLE, todos los alias de columnas enumerados anteriormente también son válidos, excepto [...].


Para no bloquear la construcción usando la función ISNULL, en MS SQL podemos usar la función CONCAT. Consideremos y comparemos 3 opciones:

SELECCIONE Apellido+" "+Nombre+" "+SegundoNombre Nombre Completo1, -- 2 opciones para reemplazo NULO vacío líneas "" (obtenemos el comportamiento como en ORACLE) ISNULL(LastName,"")+" "+ISNULL(FirstName,"")+" "+ISNULL(SegundoNombre,"") FullName2, CONCAT(LastName," ", Nombre "," ",Segundo Nombre) Nombre Completo3 DE Empleados

Nombre completo1 Nombre completo2 Nombre completo3
Ivanov Ivan Ivanovich Ivanov Ivan Ivanovich Ivanov Ivan Ivanovich
Petrov Petr Petrovich Petrov Petr Petrovich Petrov Petr Petrovich
NULO Sidorov Sidor Sidorov Sidor
NULO Andreyev Andrey Andreyev Andrey

En MS SQL, los alias también se pueden especificar utilizando el signo igual:

SELECCIONE "Fecha de recepción"=Fechadecontratación, -- además de "..." y […] puede usar "..." [Fecha de nacimiento]=Cumpleaños, ZP=Salario DE Empleados

Usar la palabra clave AS o el signo igual para especificar un alias probablemente sea más una cuestión de gustos. Pero al analizar las solicitudes de otras personas, este conocimiento puede resultar útil.

Finalmente diré que es mejor establecer nombres para alias usando solo caracteres latinos y números, evitando el uso de “…”, “…” y […], es decir, usar las mismas reglas que usamos al nombrar las tablas. . Además, en los ejemplos utilizaré sólo esos nombres y no “…”, “…” y […].

Operadores aritméticos SQL básicos


La prioridad de ejecución de los operadores aritméticos es la misma que en matemáticas. Si es necesario, el orden de aplicación de los operadores se puede cambiar usando paréntesis - (a+b)*(x/(y-z)).

Y repito una vez más que cualquier operación con NULL produce NULL, por ejemplo: 10+NULL, NULL*15/3, 100/NULL - todo esto dará como resultado NULL. Aquellos. En pocas palabras, un valor indefinido no puede producir un resultado definido. Tenga esto en cuenta al redactar su consulta y, si es necesario, maneje valores NULL usando las funciones ISNULL y COALESCE:

SELECT ID,Nombre, Salario/100*BonusPercent AS Result1, -- sin procesar valores NULL Salario/100*ISNULL(BonusPercent,0) AS Result2, -- utilice la función ISNULL Salario/100*COALESCE(BonusPercent,0) COMO Resultado3 - - use la función FUSIONAR DE Empleados

Les cuento un poco sobre la función COALESCE:

COALESCE (expr1, expr2, ..., exprn): devuelve el primer valor no NULO de una lista de valores.

SELECT COALESCE(f1, f1*f2, f2*f3) val - en este caso se devolverá el tercer valor FROM (SELECT null f1, 2 f2, 3 f3) q

Me centraré principalmente en hablar sobre construcciones DML y, en su mayor parte, no hablaré sobre las funciones que aparecerán en los ejemplos. Si no entiendes lo que hace una función en particular, busca su descripción en Internet, incluso puedes buscar información por grupo de funciones a la vez, por ejemplo, buscando en Google “funciones de cadena MS SQL”, “MS SQL”. funciones matemáticas"o "Funciones de procesamiento NULL de MS SQL". Hay mucha información sobre funciones y puede encontrarla fácilmente. Por ejemplo, en la biblioteca de MSDN, puede encontrar más información sobre la función COALESCE:

Recorte de MSDN Comparación de COALESCE y CASE

La expresión COALESCE es un atajo sintáctico para la expresión CASE. Esto significa que el optimizador de consultas reescribe COALESCE(expresión1,...n) como la siguiente expresión CASE:

CASO CUANDO (la expresión1 NO ES NULA) ENTONCES expresión1 CUANDO (la expresión2 NO ES NULA) ENTONCES expresión2 ... ELSE expresiónN FINAL

Por ejemplo, veamos cómo se puede utilizar el resto de la división (%). Este operador muy útil cuando necesitas dividir registros en grupos. Por ejemplo, saquemos todos los empleados que tienen números de personal (ID) pares, es decir, aquellos ID que son divisibles por 2:

SELECCIONE ID, Nombre DE Empleados DONDE ID%2=0 - el resto cuando se divide entre 2 es 0

ORDENAR POR: ordenar el resultado de la consulta

Cláusula de PEDIDO BY se utiliza para ordenar el resultado de la consulta.

SELECCIONE Apellido, Nombre, Salario DE los Empleados ORDEN POR Apellido, Nombre - ordene el resultado por 2 columnas - por Apellido y luego por Nombre

Para una nota. Hay una palabra clave ASC para ordenar en orden ascendente, pero como la ordenación ascendente es la opción predeterminada, puede olvidarse de esta opción (no recuerdo un momento en el que usé esta opción).

Vale la pena señalar que la cláusula ORDER BY también puede usar campos que no figuran en la cláusula SELECT (excepto en el caso en que se usa DISTINCT, que analizaré a continuación). A modo de ejemplo, me adelantaré un poco usando la opción TOP y mostraré cómo, por ejemplo, puedes seleccionar 3 empleados que tengan el salario más alto, teniendo en cuenta que por motivos de confidencialidad no debo mostrar el salario en sí:

SELECCIONE LOS 3 PRINCIPALES: devuelve solo los primeros 3 registros del resultado completo ID,Apellido,Nombre DE los empleados ORDEN POR Salario DESC: ordena el resultado en orden descendente de Salario

IDENTIFICACIÓN Apellido Nombre de pila
1000 Ivánov Iván
1002 Sidorov sidor

Por supuesto, aquí se da el caso de que varios empleados pueden tener el mismo salario y es difícil decir qué tres empleados serán devueltos. esta solicitud, esto ya debe resolverse con el director de tareas. Digamos que después de discutir esta tarea con el gerente, estuvo de acuerdo y decidió usar la siguiente opción: realizar una clasificación adicional por campo de fecha de nacimiento (es decir, valoramos a los jóvenes) y si la fecha de nacimiento de varios empleados puede coincidir. (después de todo, esto tampoco está excluido), luego puede realizar una tercera clasificación en orden descendente de valores de ID (los últimos en la muestra serán aquellos con el ID más alto, por ejemplo, los que fueron aceptados en último lugar, digamos Los números de personal se emiten secuencialmente):

SELECCIONE LOS 3 PRINCIPALES: devuelva solo los primeros 3 registros del resultado completo ID,Apellido,Nombre DE Empleados ORDEN POR Salario DESC, - 1. ordene el resultado en orden descendente por Cumpleaños del salario, - 2. luego por Fecha de nacimiento ID DESC - 3 y para una claridad completa del resultado, agregue clasificación por ID.

Aquellos. debe intentar que el resultado de la solicitud sea predecible, de modo que en caso de una sesión informativa pueda explicar por qué estas personas en particular fueron incluidas en la “lista negra”, es decir, todo fue elegido honestamente, según las reglas establecidas.

También puedes ordenar usando diferentes expresiones en la cláusula ORDER BY:

SELECCIONE Apellido, Nombre DE Empleados ORDEN POR CONCAT (Apellido", ", Nombre) - use la expresión

También puede utilizar alias especificados para las columnas en ORDER BY:

SELECCIONE CONCAT(Apellido", ",Nombre) fi DE Empleados ORDEN POR fi - use un alias

Vale la pena señalar que cuando se usa la cláusula DISTINCT, solo las columnas enumeradas en el bloque SELECT se pueden usar en la cláusula ORDER BY. Aquellos. después de aplicar la operación DISTINCT obtenemos nuevo conjunto datos, con un nuevo conjunto de columnas. Por este motivo, el siguiente ejemplo no funcionará:

SELECCIONE DISTINCT Apellido, Nombre, Salario DE Empleados ORDEN POR ID - El ID no está en el conjunto resultante que obtuvimos con DISTINCT

Aquellos. la cláusula ORDER BY se aplica al conjunto resultante antes de que el resultado se devuelva al usuario.

Nota 1. También puede utilizar los números de las columnas enumeradas en SELECT en la cláusula ORDER BY:

SELECCIONE Apellido, Nombre, Salario DE Empleados ORDEN POR - ordenar en orden 3 DESC, - 1. Salario descendente 1, - 2. por Apellido 2 - 3. por Nombre

Para los principiantes parece conveniente y tentador, pero es mejor olvidarlo y nunca utilizar esta opción de clasificación.

Si en este caso (cuando los campos se enumeran explícitamente), esta opción sigue siendo aceptable, entonces, en el caso de utilizar "*", es mejor no utilizar nunca esta opción. Por qué: porque si alguien, por ejemplo, cambia el orden de las columnas en la tabla o elimina columnas (y esta es una situación normal), es posible que su consulta aún funcione, pero incorrectamente, porque La clasificación ya se puede realizar mediante otras columnas, y esto es insidioso porque este error Es posible que no se revele muy pronto.

Si los pilares estuvieran enumerados explícitamente, entonces, en la situación anterior, la consulta continuaría funcionando, pero también correctamente (ya que todo está definido explícitamente), o simplemente arrojaría un error que de esta columna no existe.

Por lo tanto, puede olvidarse con seguridad de ordenar por números de columna.

Nota 2.
En MS SQL al ordenar en orden ascendente valores NULL se mostrará primero.

SELECCIONE BonusPercent DE Empleados ORDEN POR BonusPercent

En consecuencia, al utilizar DESC estarán al final.

SELECCIONAR BonusPercent DE Empleados ORDENAR POR BonusPercent DESC

Si necesita cambiar la lógica para ordenar valores NULL, utilice expresiones, por ejemplo:

SELECCIONE BonusPercent DE Empleados ORDEN POR ISNULL(BonusPercent,100)

ORACLE proporciona dos opciones para este propósito: NULLS FIRST y NULLS LAST (usados ​​por defecto). Por ejemplo:

SELECCIONAR BonusPercent DE Empleados ORDENAR POR BonusPercent DESC NULLS ÚLTIMOS

Preste atención a esto cuando cambie a una base de datos en particular.

ARRIBA: devuelve el número especificado de registros

Extracto de MSDN. SUPERIOR: limita el número de filas devueltas en el conjunto de resultados de la consulta a un número o porcentaje específico. Cuando se utiliza una cláusula TOP junto con una cláusula ORDER BY, el conjunto de resultados se limita a las primeras N filas del resultado ordenado. De lo contrario, las primeras N filas se devuelven en un orden no especificado.

Generalmente esta expresión se usa con la cláusula ORDER BY y ya hemos visto ejemplos en los que era necesario devolver las primeras N filas del conjunto de resultados.

Sin ORDER BY normalmente esta propuesta Se usa cuando solo necesitamos mirar una tabla desconocida para nosotros, que puede tener muchos registros, en este caso podemos, por ejemplo, pedir que nos devuelva solo las primeras 10 filas, pero para mayor claridad diremos solo 2:

SELECCIONE TOP 2 * DE Empleados

También puede especificar la palabra PORCENTAJE para devolver el porcentaje correspondiente de filas del conjunto de resultados:

SELECCIONE EL 25 POR CIENTO SUPERIOR * DE Empleados

En mi práctica, el muestreo más utilizado es el número de filas.

También puede usar la opción CON LAZOS con ARRIBA, que ayudará a devolver todas las filas en caso de clasificación ambigua, es decir, esta oración devolverá todas las filas que tienen la misma composición que las filas que caen en la selección TOP N, como resultado, se pueden seleccionar más de N filas, agreguemos otro "Programador" con un salario de 1500 para demostración:

INSERTAR Empleados(ID,Nombre,Correo electrónico,ID de puesto,ID de departamento,ID de gerente,Salario) VALORES(1004,N"Nikolaev N.N."," [correo electrónico protegido]",3,3,1003,1500)

Y agreguemos otro empleado sin indicar puesto y departamento con un salario de 2000:

INSERTAR Empleados(ID,Nombre,Correo electrónico,ID de puesto,ID de departamento,ID de gerente,Salario) VALORES(1005,N"Alexandrov A.A."," [correo electrónico protegido]",NULL,NULL,1000,2000)

Ahora seleccionemos, usando la opción CON LAZOS, todos los empleados cuyo salario coincida con el salario de 3 empleados, con el salario más pequeño (espero que quede más claro a qué me refiero):

SELECCIONE LOS 3 PRINCIPALES CON LAZOS ID, Nombre, Salario DE Empleados ORDEN POR Salario

Aquí, aunque se indica TOP 3, la solicitud devolvió 4 registros, porque El valor salarial que arrojó TOP 3 (1500 y 2000) se encontró en 4 empleados. Visualmente funciona algo como esto:

Sólo una nota.
TOP está implementado en diferentes bases de datos. de diferentes maneras, en MySQL hay una cláusula LIMIT para esto, en la que además puede establecer el desplazamiento inicial.

En ORACLE 12c, también introdujeron su propio análogo, combinando la funcionalidad TOP y LIMIT: busque las palabras "ORACLE OFFSET FETCH". Antes de la versión 12c, la pseudocolumna ROWNUM se utilizaba normalmente para este propósito.


¿Qué pasa si aplicas las cláusulas DISTINCT y TOP al mismo tiempo? Estas preguntas pueden responderse fácilmente mediante la realización de experimentos. En general, no tengas miedo y no seas perezoso para experimentar, porque... mayoría se aprende a través de la práctica. El orden de las palabras en la instrucción SELECT es el siguiente: DISTINCT va primero, seguido de TOP, es decir. Si piensa lógicamente y lee de izquierda a derecha, se aplicará el primero en descartar duplicados y luego se creará TOP en función de este conjunto. Bueno, comprobemos y asegurémonos de que este sea el caso:

SELECCIONAR DISTINTO TOP 2 Salario DE Empleados ORDENAR POR Salario

Salario
1500
2000

Aquellos. Como resultado, recibimos los dos salarios más bajos de todos. Por supuesto, puede darse el caso de que el salario de algunos empleados no esté especificado (NULL), porque El esquema nos permite hacer esto. Por lo tanto, dependiendo de la tarea, decidimos procesar valores NULL en la cláusula ORDER BY, o simplemente descartar todos los registros para los cuales Salario es NULL, y para ello procedemos a estudiar la cláusula WHERE.

DONDE – condición de selección de fila

Esta oración se utiliza para filtrar registros según una condición determinada. Por ejemplo, seleccionemos todos los empleados que trabajan en el departamento de "TI" (su ID=3):

SELECCIONE ID, Apellido, Nombre, Salario DE Empleados DONDE DepartamentoID = 3 - ORDEN POR Apellido, Nombre

IDENTIFICACIÓN Apellido Nombre de pila Salario
1004 NULO NULO 1500
1003 andréyev andrés 2000
1001 petrov Pedro 1500

La cláusula WHERE se escribe antes del comando ORDER BY.

El orden de aplicación de los comandos al conjunto inicial de Empleados es el siguiente:

  1. DÓNDE: si se especifica, el primer paso de todo el conjunto de Empleados es seleccionar solo los registros que cumplan la condición.
  2. DISTINCT: si se especifica, se descartan todos los duplicados
  3. ORDENAR POR: si se especifica, el resultado se ordena
  4. ARRIBA: si se especifica, solo se devuelve el número especificado de registros del resultado ordenado

Veamos un ejemplo para mayor claridad:

SELECCIONE DISTINTO TOP 1 Salario DE Empleados DONDE IDDepartamento=3 ORDENAR POR Salario

Visualmente se verá así:

Vale la pena señalar que la verificación de NULL no se realiza con un signo igual, sino utilizando los operadores IS NULL y IS NOT NULL. Solo recuerde que no puede comparar en NULL usando el operador “=" (signo igual), porque el resultado de la expresión también será igual a NULL.

Por ejemplo, seleccionemos todos los empleados que no tienen un departamento especificado (es decir, IDDepartamento ES NULO):

SELECCIONE ID, Nombre DE Empleados DONDE ID de Departamento ES NULO

Ahora, como ejemplo, calculemos la bonificación para todos los empleados que tienen el valor BonusPercent especificado (es decir, BonusPercent NO ES NULO):

SELECCIONE ID, Nombre, Salario/100*BonusPercent COMO Bonificación DE Empleados DONDE BonusPercent NO ES NULO

Sí, por cierto, si lo piensas bien, el valor de BonusPercent puede ser igual a cero (0) y el valor también se puede ingresar con un signo menos, porque no impusimos ninguna restricción en este campo.

Bueno, habiendo hablado del problema, nos dijeron que por ahora consideráramos que si (BonusPercent<=0 или BonusPercent IS NULL), то это означает что у сотрудника так же нет бонуса. Для начала, как нам сказали, так и сделаем, реализуем это при помощи логического оператора OR и NOT:

SELECCIONE ID,Nombre,Salario/100*BonusPercent COMO Bonificación DE Empleados DONDE NO(BonusPercent<=0 OR BonusPercent IS NULL)

Aquellos. Aquí es donde empezamos a aprender sobre los operadores booleanos. La expresión entre paréntesis “(BonusPercent<=0 OR BonusPercent IS NULL)» проверяет на то что у сотрудника нет бонуса, а NOT инвертирует это значение, т.е. говорит «верни всех сотрудников которые не сотрудники у которых нет бонуса».

Esta expresión también se puede reescribir diciendo inmediatamente "devolver todos los empleados que tienen un bono" expresando esto con la expresión (BonusPercent>0 and BonusPercent IS NOT NULL):

SELECCIONE ID, Nombre, Salario/100*BonusPercent COMO Bonificación DE Empleados DONDE BonusPercent>0 Y BonusPercent NO ES NULO

También en el bloque WHERE puedes comprobar varios tipos de expresiones utilizando operadores y funciones aritméticas. Por ejemplo, se puede realizar una verificación similar usando una expresión con la función ISNULL:

SELECCIONE ID, Nombre, Salario/100*BonusPercent COMO Bonificación DE Empleados DONDE ISNULL(BonusPercent,0)>0

Operadores booleanos y operadores de comparación simples

Sí, no podemos hacer esto sin las matemáticas, así que hagámoslo. pequeña excursión mediante operadores de comparación booleanos y simples.

Solo hay 3 operadores booleanos en SQL: Y, O y NO:

Para cada operador booleano, puede proporcionar tablas de verdad que muestren adicionalmente cuál será el resultado cuando las condiciones puedan ser NULL:

Existen los siguientes operadores simples comparaciones que se utilizan para formar condiciones:

Además, hay 2 operadores para verificar un valor/expresión para NULL:

ES NULO Prueba de igualdad NULL
NO ES NULO Prueba de desigualdad NULL

Prioridad: 1) Todos los operadores de comparación; 2) NO; 3) Y; 4) O.

Al construir complejos expresiones lógicas Se utilizan paréntesis:

((condición1 Y condición2) O NO(condición3 Y condición4 Y condición5)) O (…)

Además, al utilizar paréntesis, puede cambiar la secuencia estándar de cálculos.

Aquí intenté dar una idea del álgebra de Boole en un volumen suficiente para trabajar. Como puede ver, para escribir condiciones más complejas no puede prescindir de la lógica, pero aquí no hay mucha (Y, O y NO) y fue inventada por la gente, por lo que todo es bastante lógico.

Vayamos al final de la segunda parte.

Como puede ver, incluso podemos hablar durante mucho tiempo sobre la sintaxis básica del operador SELECT, pero para permanecer dentro del alcance del artículo, finalmente mostraré operadores lógicos adicionales: ENTRE, EN y ME GUSTA.

ENTRE – comprobar la inclusión en un rango

Valor_prueba ENTRE valor_inicial Y valor_final

Las expresiones pueden actuar como valores.

Veamos un ejemplo:

SELECCIONE ID, Nombre, Salario DE Empleados DONDE Salario ENTRE 2000 Y 3000 - que tiene un salario en el rango de 2000-3000

En realidad, BETWEEN es una notación simplificada de la forma:

SELECCIONE ID, Nombre, Salario DE Empleados DONDE Salario>=2000 Y Salario<=3000 -- все у кого ЗП в диапозоне 2000-3000

La palabra NOT se puede usar antes de la palabra ENTRE, que verificará si el valor no está dentro del rango especificado:

SELECCIONE ID, Nombre, Salario DE Empleados DONDE Salario NO ENTRE 2000 Y 3000 - similar a NO (Salario>=2000 Y Salario<=3000)

En consecuencia, si usa ENTRE, EN, LIKE, también puede combinarlas con otras condiciones usando AND y OR:

SELECCIONE ID, Nombre, Salario DE Empleados DONDE Salario ENTRE 2000 Y 3000 - que tiene un salario en el rango de 2000-3000 Y ID de Departamento=3 - tome en cuenta a los empleados del departamento 3 únicamente

EN – comprobar la inclusión en la lista de valores

Este operador tiene la siguiente forma:

Valor_prueba IN (valor1, valor2, ...)

Creo que es más fácil demostrarlo con un ejemplo:

SELECCIONE ID, nombre, salario DE los empleados DONDE ID de posición EN (3,4) - cuya posición es 3 o 4

Aquellos. esto es esencialmente lo mismo que la siguiente expresión:

SELECCIONE ID, Nombre, Salario DE Empleados DONDE PosiciónID=3 O PosiciónID=4 - cuya posición es 3 o 4

En el caso de NOT será similar (nos saldrán todos menos los de los departamentos 3 y 4):

SELECCIONE ID, nombre, salario DE los empleados DONDE ID de posición NO EN (3,4) - similar a NO (ID de posición = 3 O ID de posición = 4)

Una consulta con NOT IN también se puede expresar usando AND:

SELECCIONE ID, Nombre, Salario DE Empleados DONDE ID de posición<>3AND ID de posición<>4 - equivalente a PositionID NO EN(3,4)

Tenga en cuenta que la búsqueda de valores NULL utilizando la construcción IN no funcionará porque marcar NULL=NULL también devolverá NULL, no True:

SELECCIONE ID, Nombre, ID de departamento DE Empleados DONDE ID de departamento IN (1,2, NULL): los registros NULL no se incluirán en el resultado

En este caso, divida el cheque en varias condiciones:

SELECCIONE ID, nombre, ID de departamento DE Empleados DONDE ID de departamento EN (1,2) - 1 o 2 O ID de departamento ES NULO - o NULO

O podrías escribir algo como:

SELECCIONE ID,Nombre,IDDepartamento DE Empleados DONDE ISNULL(IDDepartamento,-1) IN(1,2,-1) - si está seguro de que no hay ningún departamento con ID=-1

Creo que la primera opción, en este caso, será más correcta y fiable. Bien, este es sólo un ejemplo para demostrar qué otras estructuras se pueden construir.

También vale la pena mencionar un error aún más insidioso asociado con NULL, que se puede cometer cuando se usa la construcción NOT IN. Por ejemplo, intentemos seleccionar todos los empleados excepto aquellos cuyo departamento es 1 o cuyo departamento no está especificado en absoluto, es decir es igual a NULO. Como solución, se sugiere la siguiente opción:

SELECCIONE ID, Nombre, ID de departamento DE Empleados DONDE ID de departamento NO EN (1, NULO)

Pero después de ejecutar la consulta, no recibiremos ni una sola fila, aunque esperábamos ver lo siguiente:

Nuevamente, la broma aquí la jugó NULL especificado en la lista de valores.

Veamos por qué ocurrió un error lógico en este caso. Ampliemos la consulta usando AND:

SELECCIONE ID, nombre, ID de departamento DE Empleados DONDE ID de departamento<>1 Y ID de departamento<>NULL: el problema se debe a esta verificación NULL; esta condición siempre devolverá NULL

Condición correcta (ID de departamento<>NULL) siempre nos dará incertidumbre aquí, es decir NULO. Ahora recuerde la tabla de verdad para el operador AND, donde (TRUE AND NULL) da NULL. Aquellos. cuando se cumple la condición izquierda (DepartmentID<>1) debido a una condición correcta indefinida, terminaremos con un valor indefinido para toda la expresión (IDDepartamento<>1 Y ID de departamento<>NULL), por lo que la cadena no se incluirá en el resultado.

La condición se puede reescribir correctamente de la siguiente manera:

SELECCIONE ID, nombre, ID de departamento DE Empleados DONDE ID de departamento NO EN (1) - o en este caso solo ID de departamento<>1 Y el ID de departamento NO ES NULO, y verifique por separado NO NULO

IN también se puede utilizar con subconsultas, pero volveremos a este formulario en partes posteriores de este tutorial.

ME GUSTA: verificar una cadena usando un patrón

Hablaré de este operador solo en su forma más simple, que es un estándar y es compatible con la mayoría de los dialectos del lenguaje SQL. Incluso de esta forma, se puede utilizar para resolver muchos problemas que requieren verificar el contenido de una cadena.

Este operador tiene la siguiente forma:

cadena_prueba COMO patrón_cadena

Se pueden utilizar los siguientes caracteres especiales en "pattern_string":

  1. El guión bajo “_” significa que cualquier carácter puede ocupar su lugar.
  2. El signo de porcentaje “%” indica que puede ser reemplazado por cualquier número de caracteres, incluido ninguno.
Veamos ejemplos con el símbolo "%" (en la práctica, por cierto, se usa con más frecuencia):

SELECCIONE ID, Nombre DE Empleados DONDE Nombre COMO "Pet%" - cuyo nombre comienza con las letras "Mascota" SELECCIONE ID, Apellido DE Empleados DONDE Apellido COMO "%ov" - cuyo apellido termina con "ov" SELECCIONE ID, Apellido DE Empleados DONDE Apellido COMO "%re%" - cuyo apellido contiene la combinación "re"

Veamos ejemplos con el símbolo “_”:

SELECCIONE ID, Apellido DE Empleados DONDE Apellido COMO "_etrov" - cuyo apellido consta de cualquier primer carácter y las letras posteriores "etrov" SELECCIONE ID, Apellido DE Empleados DONDE Apellido COMO "____ov" - cuyo apellido consta de cuatro caracteres cualesquiera y letras posteriores "ov"

Usando ESCAPE, puede especificar un carácter de escape que cancele el efecto de verificación de los caracteres especiales "_" y "%". Esta cláusula se utiliza cuando desea verificar directamente si hay un signo de porcentaje o un guión bajo en una cadena.

Para demostrar ESCAPE, pongamos basura en una entrada:

ACTUALIZAR Empleados SET FirstName="Esto es basura que contiene %" WHERE ID=1005

Y veamos qué devuelven las siguientes consultas:

SELECCIONE * DE Empleados DONDE Nombre COMO "%!%%" ESCAPE "!" -- la línea contiene el signo "%" SELECCIONAR * DE Empleados DONDE Nombre COMO "%!_%" ESCAPE "!" -- la línea contiene el signo "_"

Si necesita verificar que una cadena coincida completamente, en lugar de ME GUSTA es mejor simplemente usar el signo "=":

SELECCIONE * DE Empleados DONDE Nombre="Peter"

Sólo una nota.
En MS SQL, en la plantilla del operador LIKE, también puede especificar una búsqueda utilizando expresiones regulares, lea sobre esto en Internet si las capacidades estándar de este operador no son suficientes para usted.

ORACLE usa la función REGEXP_LIKE para buscar usando expresiones regulares.

Un poco sobre cuerdas

En caso de verificar la presencia de caracteres Unicode en una cadena, deberá colocar el carácter N antes de las comillas, es decir NORTE"…". Pero como todos los campos de caracteres de nuestra tabla están en formato Unicode (tipo nvarchar), siempre puedes usar este formato para estos campos. Ejemplo:

SELECCIONE ID, Nombre DE Empleados DONDE Nombre COMO N"Pet%" SELECCIONE ID, Apellido DE Empleados DONDE Apellido=N"Petrov"

Cuando se hace correctamente, al comparar con un campo de tipo varchar (ASCII), debe intentar usar pruebas usando "...", y al comparar un campo de tipo nvarchar (Unicode), debe intentar usar pruebas usando N" ...". Esto se hace para evitar conversiones de tipos implícitas durante la ejecución de la consulta. Usamos la misma regla al insertar (INSERT) valores en un campo o actualizarlos (ACTUALIZAR).

Al comparar cadenas, vale la pena considerar el punto de que, dependiendo de la configuración de la base de datos (intercalación), la comparación de cadenas puede no distinguir entre mayúsculas y minúsculas (cuando "Petrov" = "PETROV") o entre mayúsculas y minúsculas (cuando "Petrov"<>"PETROV").
En el caso de una configuración que distinga entre mayúsculas y minúsculas, si desea realizar una búsqueda que no distinga entre mayúsculas y minúsculas, puede, por ejemplo, convertir previamente las expresiones derecha e izquierda a una sola mayúscula o minúscula:

SELECCIONE ID,Nombre DE Empleados DONDE SUPERIOR(Nombre) COMO SUPERIOR(N"Pet%") - o INFERIOR(Nombre) COMO LOWER(N"Pet%") SELECCIONE ID,Apellido DESDE Empleados DONDE SUPERIOR(Apellido)=UPPER( N"Petrov") -- o LOWER(Apellido)=LOWER(N"Petrov")

Un poco sobre fechas

Al comprobar una fecha, puede utilizar, al igual que con las cadenas, comillas simples "...".

Independientemente de la configuración regional en MS SQL, puede utilizar la siguiente sintaxis de fecha "AAAAMMDD" (año, mes, día juntos sin espacios). MS SQL siempre entenderá este formato de fecha:

SELECCIONE ID, Nombre, Cumpleaños DE Empleados DONDE Cumpleaños ENTRE "19800101" Y "19891231" - empleados de los años 80 ORDEN POR Cumpleaños

En algunos casos, es más conveniente configurar la fecha usando la función DATEFROMPARTS:

SELECCIONE ID, Nombre, Cumpleaños DE Empleados DONDE Cumpleaños ENTRE FECHA DE PARTES (1980,1,1) Y FECHA DE PARTES (1989,12,31) ORDEN POR Cumpleaños

También hay una función similar DATETIMEFROMPARTS, que se utiliza para configurar la fecha y la hora (para el tipo de fecha y hora).

También puede utilizar la función CONVERTIR si necesita convertir una cadena a un valor de fecha o fecha y hora:

SELECCIONAR CONVERTIR (fecha, "12.03.2015", 104), CONVERTIR (fecha y hora, "2014-11-30 17:20:15", 120)

Los valores 104 y 120 indican qué formato de fecha se utiliza en la cadena. Puede encontrar una descripción de todos los formatos válidos en la biblioteca de MSDN buscando "MS SQL CONVERT".

Hay muchas funciones para trabajar con fechas en MS SQL, busque "funciones de ms sql para trabajar con fechas".

Nota. Todos los dialectos del lenguaje SQL tienen su propio conjunto de funciones para trabajar con fechas y aplican su propio enfoque para trabajar con ellas.

Un poco sobre los números y sus transformaciones.

La información de esta sección probablemente será más útil para los especialistas en TI. Si no lo es y su objetivo es simplemente aprender a escribir consultas para obtener la información que necesita de la base de datos, entonces es posible que no necesite tales sutilezas, pero en cualquier caso, puede leer rápidamente el texto y tomar notas. , porque . Si ha comenzado a estudiar SQL, entonces ya se está uniendo a TI.

A diferencia de la función de conversión CAST, la función CONVERT puede especificar un tercer parámetro, que es responsable del estilo (formato) de conversión. Los diferentes tipos de datos pueden tener su propio conjunto de estilos, lo que puede afectar el resultado devuelto. Ya hemos tocado el uso de estilos al considerar la conversión de una cadena usando la función CONVERTIR en los tipos de fecha y fecha y hora.

Puede leer más sobre las funciones y estilos CAST, CONVERT en MSDN - “Funciones CAST y CONVERT (Transact-SQL)”: msdn.microsoft.com/ru-ru/library/ms187928.aspx

Para simplificar los ejemplos, aquí se utilizarán las declaraciones del lenguaje Transact-SQL DECLARE y SET.

Por supuesto, en el caso de convertir un número entero a un número real (que mencioné al comienzo de esta lección para demostrar la diferencia entre división entera y real), el conocimiento de los matices de la conversión no es tan crítico. porque allí hicimos una conversión de entero a real (cuyo rango es mucho mayor que el rango de números enteros):

DECLARAR @min_int int SET @min_int=-2147483648 DECLARAR @max_int int SET @max_int=2147483647 SELECCIONAR -- (-2147483648) @min_int,CAST(@min_int AS float),CONVERTIR(float,@min_int), -- 2147483647 @max_int ,CAST(@max_int AS float),CONVERTIR(float,@max_int), -- numérico(16,6) @min_int/1., -- (-2147483648.000000) @max_int/1. -- 2147483647.000000

Quizás no valga la pena especificar el método de conversión implícita obtenida al dividir por (1.), porque Es recomendable intentar hacer conversiones explícitas para tener un mayor control sobre el tipo de resultado obtenido. Aunque, si queremos obtener un resultado de tipo numérico, con un número específico de dígitos después del punto decimal, entonces podemos usar un truco en MS SQL para multiplicar un valor entero por (1., 1.0, 1.00, etc.) :

DECLARAR @int int SET @int=123 SELECT @int*1., -- numérico(12, 0) - 0 decimales @int*1.0, -- numérico(13, 1) - 1 decimal @int*1.00, -- numeric(14, 2) - 2 caracteres -- aunque a veces es mejor hacer una conversión explícita CAST(@int AS numeric(20, 0)), -- 123 CAST(@int AS numeric(20, 1) ), -- 123.0 CAST(@int AS numérico(20, 2)) -- 123.00

En algunos casos, los detalles de la conversión pueden ser realmente importantes, porque... afectan la exactitud del resultado obtenido, por ejemplo, en el caso de que se realice una conversión de un valor numérico a una cadena (varchar). Veamos ejemplos de conversión de dinero y valores flotantes a varchar:

Comportamiento al convertir dinero a varchar DECLARE @money money SET @money = 1025.123456789: habrá una conversión implícita a 1025.1235, porque el tipo de dinero almacena solo 4 dígitos después del punto decimal SELECT @money, -- 1025.1235 -- de forma predeterminada, CAST y CONVERT se comportan igual (es decir, en términos generales, se aplica el estilo 0) CAST(@money as varchar(20)) , -- 1025.12 CONVERT(varchar(20), @money), -- 1025.12 CONVERT(varchar(20), @money, 0), -- 1025.12 (estilo 0 - sin separador de milésimas y 2 decimales (formato predeterminado)) CONVERT( varchar(20), @money, 1), -- 1.025.12 (estilo 1 - usa un separador de milésimas y 2 decimales) CONVERT(varchar(20), @money, 2) -- 1025.1235 (estilo 2 - sin separador y 4 números después del punto decimal)

Comportamiento al convertir float a varchar DECLARE @float1 float SET @float1 = 1025.123456789 DECLARE @float2 float SET @float2 = 1231025.123456789 SELECT @float1, -- 1025.123456789 @float2, -- 1231025 .12345679 -- Por defecto , CAST y CONVERT se comportan igual (es decir, en términos generales, se utiliza el estilo 0) -- estilo 0 - No más de 6 dígitos. La notación exponencial se usa por necesidad: aquí suceden cosas realmente aterradoras al convertir a varchar CAST(@float1 as varchar(20)), -- 1025.12 CONVERT(varchar(20), @float1), -- 1025.12 CONVERT(varchar( 20 ), @float1, 0), -- 1025.12 CAST(@float2 como varchar(20)), -- 1.23103e+006 CONVERTIR(varchar(20), @float2), -- 1.23103e+006 CONVERTIR(varchar( 20 ), @float2, 0), -- 1.23103e+006 -- estilo 1 - Siempre 8 dígitos. Siempre se utiliza la notación científica para los números.

-- este estilo para float tampoco es muy preciso CONVERT(varchar(20), @float1, 1), -- 1.0251235e+003 CONVERT(varchar(20), @float2, 1), -- 1.2310251e+006 - - estilo 2 - Siempre 16 bits. Siempre se utiliza la notación científica para los números.

Si necesita controlar explícitamente la precisión hasta un determinado signo, más de 4, a veces es mejor utilizar el tipo decimal/numérico para almacenar datos. Si 4 caracteres son suficientes, entonces puede usar el tipo de dinero; corresponde aproximadamente a numérico(20,4).

Decimal y numérico DECLARAR @money money SET @money = 1025.123456789 -- 1025.1235 DECLARAR @float1 float SET @float1 = 1025.123456789 DECLARAR @float2 float SET @float2 = 1231025.123456789 DECLARAR @numer ic numeric(28,9) SET @ numérico = 1025.123456789 SELECCIONAR CAST ( @numeric como varchar(20)), -- 1025.12345679 CONVERTIR(varchar(20), @numeric), -- 1025.12345679 CAST(@money as numeric(28,9)), -- 1025.123500000 CAST(@float1 como numérico( 28,9)), -- 1025.123456789 CAST(@float2 como numérico(28,9)) -- 1231025.123456789

Nota.
A partir de la versión MS SQL 2008, puedes usar en lugar de la construcción: Agregar etiquetas
  • Traducción

No basta con escribir código que sea fácil de leer: también es necesario que se ejecute rápido.

Hay tres reglas básicas para escribir código T-SQL que funcionarán bien. Son acumulativas: seguir todas estas reglas tendrá un impacto positivo en el código. Omitir o cambiar cualquiera de estos probablemente tendrá un impacto negativo en el rendimiento de su código.

  • Escriba según la estructura de almacenamiento de datos: si almacena datos de fecha y hora, use fecha y hora, no varchar ni nada más.
  • Escriba en función de la presencia de índices: si hay índices creados en la tabla y deberían estar allí, escriba el código para que pueda aprovechar al máximo esos índices. Asegúrese de que el índice agrupado, del cual solo puede haber uno por tabla, se utilice de la manera más eficiente.
  • Escriba de una manera que ayude al optimizador de consultas: el optimizador de consultas es una parte maravillosa de un DBMS. Desafortunadamente, puede dificultar mucho su trabajo escribiendo una consulta que le resultará "difícil" de analizar, por ejemplo, que contenga vistas anidadas (cuando una vista recibe datos de otra, o incluso de una tercera), y así sucesivamente. Tómese su tiempo para comprender cómo funciona el optimizador y escriba consultas de tal manera que puedan ayudarlo y no perjudicarlo.
Hay varios errores comunes que la gente comete en su código T-SQL; no los cometa.

Usar tipos de datos incorrectos

En teoría, evitar este error es muy sencillo, pero en la práctica ocurre con bastante frecuencia. Por ejemplo, está utilizando algún tipo de datos en su base de datos. ¡Úselo en sus parámetros y variables! Sí, sé que SQL Server puede convertir implícitamente un tipo de datos a otro. Pero cuando se produce una conversión de tipo implícita, o usted mismo convierte el tipo de datos de una columna a otro tipo, está realizando una conversión en toda la columna. Cuando realiza esta transformación en una columna en una cláusula WHERE o en una condición de unión, siempre verá un escaneo de la tabla. Se podría crear un índice excelente en esta columna, pero dado que está haciendo un CAST en los valores almacenados en esta columna para comparar, por ejemplo, la fecha almacenada en esta columna con el tipo de carácter que utilizó en la condición, el índice no será utilizado.

¿No me crees? Veamos esta consulta:

SELECCIONE e.BusinessEntityID, e.NationalIDNumber FROM HumanResources.Employee AS e WHERE e.NationalIDNumber = 112457891;
Bien escrito y muy sencillo. Debe estar cubierto por un índice creado en esta tabla. Pero aquí está el plan de ejecución:

Esta consulta es lo suficientemente rápida y la tabla es pequeña, por lo que solo se requieren cuatro lecturas para escanear el índice. Observe el pequeño signo de exclamación en la declaración SELECT. Si miramos sus propiedades, veremos:

Bien. Esta es una advertencia (nueva en SQL Server 2012) de que hay una conversión de tipo en curso que afecta el plan de ejecución. En resumen, esto se debe a que la solicitud utiliza un tipo de datos incorrecto:

SELECCIONE e.BusinessEntityID, e.NationalIDNumber FROM HumanResources.Employee AS y DONDE e.NationalIDNumber = "112457891";
Y obtenemos este plan de ejecución de consulta:

Y aquí sólo se utilizan dos operaciones de lectura, en lugar de cuatro. Y sí, entiendo que hice un poco más rápido una consulta que ya era de ejecución rápida. Pero ¿qué pasaría si hubiera millones de filas almacenadas en la tabla? Sí, entonces me convertiría en un héroe.

Utilice los tipos de datos correctos.

Uso de funciones en condiciones de unión y cláusulas WHERE

Hablando de funciones, la mayoría de las funciones utilizadas en condiciones de unión o cláusulas WHERE a las que se pasa una columna como argumento interfieren con el uso correcto de los índices. Verás cuán lentas son las consultas cuando se utilizan funciones que toman columnas como argumentos. He aquí un ejemplo:

SELECCIONE a.AddressLine1, a.AddressLine2, a.City, a.StateProvinceID FROM Person.Address COMO WHERE "4444" = LEFT(a.AddressLine1, 4);
Esta función, IZQUIERDA, toma una columna como argumento, lo que da como resultado este plan de ejecución:

Esto da como resultado 316 lecturas para encontrar los datos deseados, y esto lleva 9 milisegundos (tengo discos muy rápidos). Esto se debe a que '4444' debe compararse con cada cadena devuelta por esta función. SQL Server ni siquiera puede simplemente escanear la tabla, necesita hacer un movimiento hacia la IZQUIERDA en cada fila. Sin embargo, puedes hacer algo como esto:

SELECCIONE a.AddressLine1, a.AddressLine2, a.City, a.StateProvinceID FROM Person.Address COMO DONDE a.AddressLine1 COMO "4444%";
Y ahora vemos un plan de ejecución completamente diferente:

La consulta requiere 3 lecturas y 0 milisegundos para completarse. Bueno, o que sea 1 milisegundo, por objetividad. Este es un gran aumento de rendimiento. Y todo porque usé una función que se puede usar para buscar por índice (anteriormente se llamaba sargeable - una palabra intraducible, en general: SARG – Argumentos de búsqueda –able, si la función es SARGeable – puede pasarle una columna como argumento y la Búsqueda de índice se seguirá utilizando, si no es SARGeable – por desgracia, la Exploración de índice siempre será usado - aprox. traductor). En cualquier caso, no utilice funciones en cláusulas WHERE o condiciones de búsqueda, ni utilice únicamente aquellas que puedan utilizarse en condiciones de búsqueda de índice.

Uso de UDF de declaraciones múltiples

UDF de declaraciones múltiples en la edición rusa de msdn se traduce aproximadamente como “Funciones definidas por el usuario que constan de varias instrucciones, pero esto, en mi opinión, suena algo extraño, por lo que en el título y más adelante en el texto traté de evitar traducir esto plazo - aprox. traductor

Básicamente, te están atrapando. A primera vista, este maravilloso mecanismo nos permite utilizar T-SQL como un lenguaje de programación real. Puede crear estas funciones y llamarlas entre sí y el código se puede reutilizar, a diferencia de estos antiguos procedimientos almacenados. Esto es asombroso. Hasta que intentes ejecutar este código en una gran cantidad de datos.

El problema con estas funciones es que se basan en variables de tabla. Las variables de tabla son algo genial si las usas para el propósito previsto. Tienen una diferencia obvia con las tablas temporales: no se basan en estadísticas. Esta diferencia puede ser muy útil o puede... matarte. Si no tiene estadísticas, el optimizador supone que cualquier consulta ejecutada en una variable de tabla o UDF devolverá solo una fila. Una (1) línea. Esto está bien si en realidad devuelven varias filas. Pero un día te devolverán cientos o miles de filas y decides unir una UDF a otra... El rendimiento bajará muy, muy rápido y muchísimo.

El ejemplo es bastante grande. A continuación se muestran algunas UDF:

CREAR FUNCIÓN dbo.SalesInfo () DEVUELVE @return_variable TABLA (SalesOrderID INT, OrderDate DATETIME, SalesPersonID INT, PurchaseOrderNumber dbo.OrderNumber, AccountNumber dbo.AccountNumber, ShippingCity NVARCHAR(30)) COMO COMENZAR;
INSERTAR EN @return_variable (SalesOrderID, OrderDate, SalesPersonID, PurchaseOrderNumber, AccountNumber, ShippingCity) SELECCIONE soh.SalesOrderID, soh.OrderDate, soh.SalesPersonID, soh.PurchaseOrderNumber, soh.AccountNumber, a.City FROM Sales.SalesOrderHeader AS soh JOIN Person. Dirección COMO ON soh.ShipToAddressID = a.AddressID;

SELECCIONE csi.OrderDate, csi.PurchaseOrderNumber, csi.AccountNumber, csi.OrderQty, csi.UnitPrice FROM dbo.CombinedSalesInfo() COMO csi DONDE csi.SalesPersonID = 277 AND csi.ShippingCity = "Odessa";
Una petición muy sencilla. Aquí está su plan de ejecución, también muy sencillo:

Pero se ejecuta en 2,17 segundos, devuelve 148 filas y utiliza 1456 lecturas. Tenga en cuenta que nuestra función tiene un costo cero y solo el escaneo de la tabla, la variable de la tabla, afecta el costo de la consulta. Mmmm, ¿es verdad? Intentemos ver qué se esconde detrás del operador de ejecución UDF de costo cero. Esta consulta recuperará el plan de ejecución de la función del caché:

SELECCIONE deqp.query_plan, dest.text, SUBSTRING(dest.text, (deqs.statement_start_offset / 2) + 1, (deqs.statement_end_offset - deqs.statement_start_offset) / 2 + 1) COMO declaración actual DESDE sys.dm_exec_query_stats AS deqs CROSS APPLY sys .dm_exec_query_plan(deqs.plan_handle) COMO deqp APLICACIÓN CRUZADA sys.dm_exec_sql_text(deqs.sql_handle) COMO destino DONDE deqp.objectid = OBJECT_ID("dbo.CombinedSalesInfo");
Y esto es lo que realmente está sucediendo allí:

Vaya, parece que hay algunas más de estas pequeñas funciones y escaneos de tablas acechando por aquí que casi no valen nada, pero no del todo. Además, el operador de unión Hash Match, que escribe en tempdb y tiene un costo de ejecución considerable. Veamos el plan de ejecución de otra UDF:

¡Aquí! Y ahora vemos el escaneo de índice agrupado, que escanea una gran cantidad de filas. Ya no es genial. En general, en toda esta situación, la UDF parece cada vez menos atractiva. ¿Qué pasa si, bueno, no lo sé exactamente, simplemente intentamos acceder a las tablas directamente? Así, por ejemplo:

SELECCIONE soh.OrderDate, soh.PurchaseOrderNumber, soh.AccountNumber, sod.OrderQty, sod.UnitPrice FROM Sales.SalesOrderHeader AS soh ÚNETE a Sales.SalesOrderDetail COMO sod ON soh.SalesOrderID = sod.SalesOrderID ÚNETE a Person.Address COMO ba ON soh.BillToAddressID = ba.AddressID JOIN Person.Address AS sa ON soh.ShipToAddressID = sa.AddressID WHERE soh.SalesPersonID = 277 AND sa.City = "Odessa";
Ahora, al ejecutar esta consulta, obtendremos exactamente los mismos datos, pero en solo 310 milisegundos en lugar de 2170. Además, SQL Server solo realizará 911 lecturas en lugar de 1456. Honestamente, es muy fácil tener problemas de rendimiento usando UDF.

Habilitación de la configuración Trabajar más rápido: uso de lecturas sucias

Volviendo al pasado, a los ordenadores antiguos con 286 procesadores a bordo, podemos recordar que, por diversos motivos, tenían un botón “Turbo” en el panel frontal. Si lo "exprimiste" accidentalmente, la computadora inmediatamente comenzó a ralentizarse increíblemente. Entonces comprende que algunas cosas siempre deben estar habilitadas para garantizar el máximo rendimiento. Del mismo modo, muchas personas consideran el nivel de aislamiento READ_UNCOMMITTED y la sugerencia NO_LOCK como un botón turbo para SQL Server. Al usarlos, tenga la seguridad de que casi cualquier consulta y todo el sistema en su conjunto será más rápido. Esto se debe al hecho de que no se aplicarán ni comprobarán ningún bloqueo durante la lectura. Menos bloqueos significan resultados más rápidos. Pero…

Cuando usa READ_UNCOMMITTED o NO_LOCK en sus consultas, termina con lecturas sucias. Todo el mundo entiende que esto significa que puede leer "perro" en lugar de "gato" si hay una operación de actualización en curso pero aún no se ha completado. Pero también puede terminar con más o menos filas de las que realmente tiene, así como filas duplicadas, porque las páginas de datos pueden moverse mientras se ejecuta la consulta y no debe colocar ningún bloqueo para evitarlo. No sé ustedes, pero la mayoría de las empresas para las que he trabajado esperaban que la mayoría de las consultas en la mayoría de los sistemas arrojaran datos consistentes. La misma consulta con los mismos parámetros, ejecutada con el mismo conjunto de datos, debería dar el mismo resultado. No si usas NO_LOCK. Para asegurarte de esto, te aconsejo que leas este post.

Uso irrazonable de sugerencias en consultas.

La gente se apresura demasiado a decidir utilizar sugerencias. La situación más común es cuando una pista ayuda a resolver un problema muy poco común en una de las solicitudes. Pero cuando las personas ven una mejora significativa en el rendimiento de esta consulta... inmediatamente comienzan a enviarla a todas partes.

Por ejemplo, mucha gente cree que LOOP JOIN es la mejor manera de unir tablas. Llegan a esta conclusión porque es más común en consultas pequeñas y rápidas. Entonces deciden forzar a SQL Server a usar LOOP JOIN. No es nada difícil:

SELECCIONAR s. AS StoreName, p.LastName + ", " + p.FirstName FROM Sales.Store AS s JOIN sales.SalesPerson AS sp ON s.SalesPersonID = sp.BusinessEntityID JOIN HumanResources.Employee AS e ON sp.BusinessEntityID = e.BusinessEntityID JOIN Persona .Persona AS p ON e.BusinessEntityID = p.BusinessEntityID OPCIÓN (LOOP JOIN);
Esta consulta se ejecuta durante 101 milisegundos y realiza 4115 lecturas. En general, no está mal, pero si eliminamos esta sugerencia, la misma consulta se ejecutará en 90 milisegundos y producirá solo 2370 lecturas. Cuanto más cargado esté el sistema, más evidente será la eficacia de la solicitud sin utilizar una pista.

Aquí hay otro ejemplo. La gente suele crear un índice en una tabla esperando que resuelva un problema. Entonces tenemos una consulta:

SELECCIONE * DE Purchasing.PurchaseOrderHeader COMO poh DONDE poh.PurchaseOrderID * 2 = 3400;
El problema nuevamente es que cuando realiza una transformación de columna, no se utilizará ningún índice de manera adecuada. El rendimiento se degrada porque se analiza el índice agrupado. Entonces, cuando la gente ve que su índice no se está utilizando, esto es lo que hacen:

SELECCIONE * DE Purchasing.PurchaseOrderHeader COMO poh CON (INDEX (PK_PurchaseOrderHeader_PurchaseOrderID)) DONDE poh.PurchaseOrderID * 2 = 3400;
Y ahora obtienen un escaneo del índice elegido, no del agrupado, por lo que el índice está "en uso", ¿verdad? Pero el rendimiento de la consulta cambia: ahora, en lugar de 11 operaciones de lectura, se realizan 44 (el tiempo de ejecución para ambas es de aproximadamente 0 milisegundos, ya que tengo discos realmente rápidos). “Para ser usado” significa que se usa, pero no como se esperaba. La solución a este problema es reescribir la consulta así:

SELECCIONE * DE Purchasing.PurchaseOrderHeader poh DONDE PurchaseOrderID = 3400/2;
Ahora el número de lecturas se ha reducido a dos porque se utiliza la búsqueda de índice: el índice se utiliza correctamente.

Las sugerencias en las consultas siempre deben usarse al final, después de que se hayan probado y fallado todas las demás opciones posibles.

Uso del procesamiento 'Fila por fila agonizante'

El procesamiento línea por línea se realiza utilizando cursores u operaciones en un bucle WHILE, en lugar de operaciones en conjuntos. Al utilizarlos, la productividad es muy, muy baja. Los cursores se utilizan comúnmente por dos razones. Los primeros son desarrolladores que están acostumbrados a utilizar el procesamiento línea por línea en su código, y los segundos son desarrolladores que provienen de Oracle y piensan que los cursores son algo bueno. Cualquiera sea el motivo, los cursores acaban con la productividad.

A continuación se muestra un ejemplo típico de mal uso del cursor. Necesitamos actualizar el color de los productos seleccionados según un criterio determinado. No está inventado, se basa en un código que una vez tuve que optimizar.

COMENZAR LA TRANSACCIÓN DECLARAR @Name NVARCHAR(50), @Color NVARCHAR(15), @Weight DECIMAL(8, 2) DECLARAR EL CURSOR BigUpdate PARA SELECCIONAR p. ,p.Color ,p. DE Producción.Producto AS p ; ABRIR BigUpdate; BUSCAR SIGUIENTE DE BigUpdate EN @Name, @Color, @Weight; MIENTRAS @@FETCH_STATUS = 0 COMENZAR SI @Peso< 3 BEGIN UPDATE Production.Product SET Color = "Blue" WHERE CURRENT OF BigUpdate END FETCH NEXT FROM BigUpdate INTO @Name, @Color, @Weight ; END CLOSE BigUpdate ; DEALLOCATE BigUpdate ; SELECT * FROM Production.Product AS p WHERE Color = "Blue" ; ROLLBACK TRANSACTION
En cada iteración, realizamos dos operaciones de lectura y la cantidad de productos que cumplen con nuestros criterios es de cientos. En mi máquina, sin carga, el tiempo de ejecución es superior a un segundo. Esto es completamente inaceptable, especialmente porque es muy sencillo reescribir esta consulta:

COMENZAR TRANSACCIÓN ACTUALIZAR Producción.Producto SET Color = "AZUL" DONDE< 3 ; ROLLBACK TRANSACTION
Ahora sólo se realizan 15 lecturas y el tiempo de ejecución es de sólo 1 milisegundo. No te rías. La gente suele escribir códigos como este o incluso peores. Los cursores son algo que se debe evitar y utilizar sólo cuando no se puede prescindir de ellos, por ejemplo, en tareas de mantenimiento en las que es necesario "ejecutar" diferentes tablas o bases de datos.

Uso inadecuado de vistas anidadas

Vistas que hacen referencia a vistas que se conectan a vistas que hacen referencia a otras vistas que se conectan a vistas... Una vista es solo una consulta. Pero como pueden tratarse como mesas, la gente puede empezar a pensar en ellas como mesas. Pero en vano. ¿Qué sucede cuando conectas una vista con otra, vinculas a una tercera vista, etc.? Simplemente estás creando un plan de consulta muy complicado. El optimizador intentará simplificarlo. Probará planes que no utilicen todas las tablas, pero el tiempo para trabajar en la elección de un plan es limitado y cuanto más complejo sea el plan, menos probable será que termine con un plan de ejecución bastante simple. Y los problemas de rendimiento serán casi inevitables.

Aquí, por ejemplo, hay una secuencia de consultas simples que definen vistas:

CREAR VISTA dbo.SalesInfoView AS SELECT soh.SalesOrderID, soh.OrderDate, soh.SalesPersonID, soh.PurchaseOrderNumber, soh.AccountNumber, a.City AS ShippingCity FROM Sales.SalesOrderHeader AS soh JOIN Person.Address AS a ON soh.ShipToAddressID = a .ID de dirección; CREAR VISTA dbo.SalesDetailsView COMO SELECCIONAR sod.SalesOrderID, sod.SalesOrderDetailID, sod.OrderQty, sod.UnitPrice FROM Sales.SalesOrderDetail AS sod; CREAR VISTA dbo.CombinedSalesInfoView COMO SELECCIONAR si.SalesPersonID, si.ShippingCity, si.OrderDate, si.PurchaseOrderNumber, si.AccountNumber, sd.OrderQty, sd.UnitPrice DESDE dbo.SalesInfoView AS si ÚNETE a dbo.SalesDetailsView AS sd ON si.SalesOrderID = sd.SalesOrderID;
Y aquí el autor del texto olvidó indicar la petición, pero la da en los comentarios (nota del traductor):
SELECCIONE csi.OrderDate DESDE dbo. CominedSalesInfoView csi DONDE csi.SalesPersonID = 277
Como resultado, nuestra consulta tarda 155 milisegundos en completarse y utiliza 965 lecturas. Aquí está su plan de ejecución:

Se ve bien, especialmente porque tenemos 7000 filas, por lo que todo parece estar en orden. Pero, ¿qué pasa si intentamos ejecutar una consulta como esta?

SELECCIONE soh.OrderDate FROM Sales.SalesOrderHeader AS soh DONDE soh.SalesPersonID = 277;
Ahora la consulta se ejecuta en 3 milisegundos y utiliza 685 lecturas, una gran diferencia. Y aquí está su plan de ejecución:

Como puede ver, el optimizador no puede eliminar todas las tablas superfluas como parte del proceso de simplificación de consultas. Por lo tanto, en el primer plan de ejecución hay dos operaciones adicionales: Index Scan y Hash Match, que recopilan los datos juntos. Podría ahorrarle a SQL Server algo de trabajo adicional escribiendo esta consulta sin usar vistas. Y recuerde: este ejemplo es muy simple, la mayoría de las consultas en la vida real son mucho más complejas y generan problemas de rendimiento mucho mayores.

Hay una pequeña disputa en los comentarios a este artículo, cuya esencia es que Grant (el autor del artículo) parece haber ejecutado sus consultas no en la base de datos estándar AdventureWorks, sino en una base de datos similar, pero con una base ligeramente diferente. La estructura, razón por la cual el plan de ejecución es "subóptimo" "de la consulta en la última sección es diferente de lo que podría ver si hiciera el experimento usted mismo. Nota traductor
Si en algún lugar me quedé demasiado callado (y puedo estarlo) y el texto es difícil de entender, o puedes ofrecerme una mejor redacción de cualquier cosa, estaré encantado de escuchar todos los comentarios.

Aquí hay una lista completa de funciones de cadena tomadas de BOL:

ASCII NCHAR SONIDO
CARBONIZARSE PATINDEX ESPACIO
CARÍNDEX REEMPLAZAR FUE
DIFERENCIA NOMBRE DE LA COTIZACIÓN COSA
IZQUIERDA REPRODUCIR EXACTAMENTE SUBCADE
LEN CONTRARRESTAR UNICODIO
MÁS BAJO BIEN SUPERIOR
LTRIM RTRIM

Comencemos con dos funciones mutuamente inversas: ASCII Y CARBONIZARSE.

La función ASCII devuelve el código ASCII del carácter más a la izquierda de la expresión de cadena que es el argumento de la función.

Así, por ejemplo, se explica cómo puede determinar cuántas letras diferentes hay que inician los nombres de los barcos en la tabla Barcos:


Cabe señalar que se puede obtener un resultado similar más fácilmente utilizando otra función: IZQUIERDA, que tiene la siguiente sintaxis:

IZQUIERDA (<expresión de cadena>, <expresión entera>)

y corta el número de caracteres de la izquierda especificados por el segundo argumento de la cadena que es el primer argumento. Entonces,

SELECCIONAR DISTINTO IZQUIERDO (nombre, 1) DE Envíos ORDEN POR 1

Así es como, por ejemplo, puede obtener una tabla de códigos para todos los caracteres alfabéticos:

SELECT CHAR(ASCII("a")+ num-1) letra, ASCII("a")+ num - 1
DESDE (SELECCIONAR 5*5*(a-1)+5*(b-1) + c AS num
DESDE (SELECCIONAR 1 a UNION TODO SELECCIONAR 2 UNION TODO SELECCIONAR 3 UNION TODO SELECCIONAR 4 UNION TODO SELECCIONAR 5) x
UNIÓN CRUZADA
(SELECCIONAR 1 b UNION TODO SELECCIONAR 2 UNION TODO SELECCIONAR 3 UNION TODO SELECCIONAR 4 UNION TODO SELECCIONAR 5) y
UNIÓN CRUZADA
(SELECCIONAR 1 c UNION TODO SELECCIONAR 2 UNION TODO SELECCIONAR 3 UNION TODO SELECCIONAR 4 UNION TODO SELECCIONAR 5) z
) x
DONDE ASCII("a")+ num -1 ENTRE ASCII("a") Y ASCII("z")

Para aquellos que aún no conocen la generación de una secuencia numérica, les remito al artículo correspondiente.

Como sabes, los códigos para letras minúsculas y mayúsculas son diferentes. Por lo tanto, para obtener el conjunto completo sin reescribir la solicitud, sólo necesita agregar uno similar al código anterior:


Supongo que no sería demasiado difícil agregar esta carta a la tabla si fuera necesario.

Consideremos ahora la tarea de determinar dónde encontrar la subcadena deseada en una expresión de cadena. Para esto se pueden utilizar dos funciones: CARÍNDEX Y PATINDEX. Ambos devuelven la posición inicial (la posición del primer carácter de la subcadena) de la subcadena en la cadena. La función CHARINDEX tiene la sintaxis:

CARÍNDEX( expresión_de_búsqueda, expresión_cadena[, posición_inicial])

Aquí hay un parámetro entero opcional. posición_inicial define la posición en una expresión de cadena desde la cual se realiza la búsqueda expresión_de_búsqueda. Si se omite este parámetro la búsqueda se realiza desde el principio expresión_cadena. Por ejemplo, solicitar

Cabe señalar que si la subcadena o expresión de cadena buscada es NULL, el resultado de la función también será NULL.

El siguiente ejemplo determina las posiciones de la primera y segunda aparición del carácter "a" en el nombre del barco "California".

SELECCIONE CHARINDEX("a",nombre) primero_a,
CHARINDEX("a", nombre, CHARINDEX("a", nombre)+1) segundo_a
DESDE Barcos DONDE nombre="California"

Tenga en cuenta que al definir el segundo carácter en la función, se utiliza la posición inicial, que es la posición del carácter que sigue a la primera letra "a" - CHARINDEX("a", nombre)+1. La exactitud del resultado (2 y 10) es fácil de comprobar :-).

La función PATINDEX tiene la sintaxis:

PATINDEX("% muestra%" , expresión_cadena)

La principal diferencia entre esta función y CHARINDEX es que la cadena de búsqueda puede contener caracteres comodín: % y _. En este caso, se requieren los caracteres finales "%". Por ejemplo, usar esta función en el primer ejemplo se vería así


El resultado de esta consulta se ve así:


El hecho de que terminemos con un conjunto de resultados vacío significa que no existen tales barcos en la base de datos. Tomemos una combinación de valores: la clase y el nombre del barco.

Combinar dos valores de cadena en uno se llama concatenación, y en Servidor SQL para esta operación se utiliza el signo "+" (en el estándar "||"). Entonces,

¿Qué pasa si la expresión de cadena contiene solo una letra? La consulta lo mostrará. Puedes verificar esto fácilmente escribiendo

Al migrar de MS SQL a MySQL, además de migrar datos, también debe migrar el código de la aplicación que se encuentra en la base de datos.

Anteriormente discutimos cómo usar la herramienta WorkSQL Workbench.

Como parte de la migración, solo convertirá tablas y copiará datos, pero no convertirá activadores, vistas ni procedimientos almacenados. Debes convertirlos manualmente a la base de datos MySQL.

Para realizar esta conversión manualmente, debe comprender las diferencias básicas entre las consultas de MS SQL y MySQL.

Durante mi conversión de Microsoft SQL Server a la base de datos MySQL, me encontré con las siguientes declaraciones y consultas de MS SQL que no eran compatibles con MySQL y tuve que convertirlas como se muestra a continuación.

1. Creación de procedimientos almacenados. Sintaxis

La sintaxis básica para crear procedimientos almacenados es diferente.

MS SQL almacenado, sintaxis de creación de procedimientos:

CREAR PROCEDIMIENTO. @someString VarChar(150) Como COMIENZO - Las consultas SQL van aquí FINAL

para MySQL la sintaxis para crear un procedimiento es:

CREAR PROCEDIMIENTO almacenadoProcedureName(IN someString VarChar(150)) BEGIN - Las consultas SQL van aquí FIN

2. Creando tablas temporales

En el código MS SQL, he creado varias tablas temporales que son necesarias para la aplicación. La sintaxis para crear una tabla temporal varía como se muestra a continuación.

Sintaxis de MS SQL para crear una tabla temporal:

CREAR TABLA #tableName(emp_id VARCHAR(10)COLLATE Database_Default PRIMARY KEY, emp_Name VARCHAR(50) COLLATE Database_Default, emp_Code VARCHAR(30) COLLATE Database_Default, emp_Department VARCHAR(30) COLLATE Database_Default)

La sintaxis de MySQL para crear una tabla temporal es:

CREAR TABLA TEMPORAL nombreTabla(emp_id VARCHAR(10), emp_Name VARCHAR(50), emp_Code VARCHAR(30), emp_Department VARCHAR(30));

3. Sintaxis SI

He utilizado muchas condiciones en mis procedimientos almacenados y activadores que no funcionaron después de convertir a MySQL ya que la sintaxis es diferente, como se muestra a continuación.

Sintaxis de condición IF de MS SQL:

If(@intSomeVal="") COMENZAR CONFIGURAR @intSomeVal=10 FINALIZAR

Sintaxis de condición IF de MySQL:

IF @intSomeVal=""ENTONCES ESTABLECER @intSomeVal=10; ENDIF;

4. Estado SI EXISTE

Otro uso común es, si es una condición, verificar si la consulta devolvió alguna fila o no; y si devuelve varias filas, haz algo. Para esto, he usado IF EXISTS en MS SQL, que debe convertirse a comandos IF de MySQL como se describe a continuación.

MS SQL SI SALE Ejemplo:

SI EXISTE (SELECCIONE 1 DE #nombretabla CON(NOLOCK) DONDE ColName="empType") COMIENZA - Las consultas SQL van aquí FINAL

El equivalente MySQL de lo anterior, utilizado cuando se cumple la condición:

IF(SELECT count(*) FROM tableName WHERE ColName="empType") > 0 ENTONCES - Las consultas SQL van aquí END IF;

5. Funciones de fecha

El uso de funciones de datos dentro de un procedimiento almacenado es bastante común. La siguiente tabla muestra las diferencias entre MS SQL y datos mysql, funciones relacionadas.

Servidor MS SQLServidor MySQL
OBTENER FECHA()AHORA()
FECHA DEL SISTEMA()
CURRENT_TIMESTAMP()
OBTENER FECHA() + 1AHORA() + INTERVALO 1 DÍA
CURRENT_TIMESTAMP +INTERVAL 1 DÍA
FECHAADD(dd, -1, OBTENER FECHA())AÑADIR FECHA(AHORA(), INTERVALO -1 DÍA)
CONVERTIR(VARCHAR(19),GETDATE())DATE_FORMAT(AHORA(),’%b %d %Y %h:%i %p’)
CONVERTIR(VARCHAR(10),GETDATE(),110)DATE_FORMAT(AHORA(),’%m-%d-%Y’)
CONVERTIR(VARCHAR(24),GETDATE(),113)DATE_FORMAT(AHORA(),’%d %b %Y %T:%f’)
CONVERTIR(VARCHAR(11),GETDATE(),6)DATE_FORMAT(AHORA(),’%d %b %y’)

6. Declaración de variables

En los procedimientos almacenados de MS SQL, puede declarar variables en algún lugar entre "Inicio" y "Fin".

Sin embargo, en MySql sólo hay que declararlos después de declarar el procedimiento almacenado de “inicio”. No se permite declarar una variable en cualquier punto intermedio.

7. Seleccione los primeros N registros.

En MS SQL, utilizará SELECT, TOP si desea seleccionar solo los primeros registros. Por ejemplo, para seleccionar los primeros 10 registros, haría lo siguiente:

SELECCIONE LOS 10 PRINCIPALES * DE LA TABLA;

En MySQL, tendrás que usar LIMIT en lugar de TOP como se muestra a continuación.

SELECCIONE * DE LA TABLA LÍMITE 10;

8. Convertir entero a carácter

En MS SQL lo harías próximos pasos(Funciones de conversión) para convertir un número entero en un carácter.

CONVERTIR(VARCHAR(50), algúnIntVal)

En MySQL, utilizará la función CAST para convertir un número entero en un carácter, como se muestra a continuación.

CAST(algúnIntVal como CHAR)

9. Operador de concatenación

Si está manipulando una gran cantidad de datos dentro de un procedimiento almacenado, es posible que desee realizar alguna concatenación de cadenas.

En M.S. declaración SQL concatenación + símbolo. A continuación se muestra un ejemplo de dicho uso.

SET @algunaCadena = "%|" + @algunStringVal + "|%"

En MySQL, si usa el modo AnSi, es lo mismo que en MS SQL. aquellos. Símbolo +, funcionará para la concatenación.

Pero, en el modo predeterminado, en MySQL, tenemos que usar la función CONCAT(“str1”, “str2”, “str3”.. “strN”).

SET algunaCadena = CONCAT("%|", algunaCadenaVal, "|%");

El lenguaje SQL se utiliza para recuperar datos de la base de datos. SQL es un lenguaje de programación que se parece mucho al inglés pero está destinado a programas de gestión de bases de datos. SQL se utiliza en cada consulta en Access.

Comprender cómo funciona SQL le ayuda a crear consultas más precisas y facilita la corrección de consultas que devuelven resultados incorrectos.

Este es un artículo de una serie de artículos sobre el lenguaje SQL para Access. Describe los conceptos básicos del uso de SQL para recuperar datos y proporciona ejemplos de sintaxis SQL.

En este artículo

¿Qué es SQL?

SQL es un lenguaje de programación diseñado para trabajar con conjuntos de hechos y las relaciones entre ellos. En programas de control bases de datos relacionales datos como oficina de microsoft Access, se utiliza el lenguaje SQL para trabajar con datos. A diferencia de muchos lenguajes de programación, SQL es legible y comprensible incluso para principiantes. Como muchos lenguajes de programación, SQL es estándar internacional, reconocido por comités de estandarización como ISO y ANSI.

Los conjuntos de datos se describen en SQL para ayudar a responder preguntas. En usando SQL se debe utilizar la sintaxis correcta. La sintaxis es un conjunto de reglas que permiten combinar correctamente los elementos de un lenguaje. La sintaxis SQL se basa en la sintaxis. idioma en Inglés y tiene mucho elementos comunes con la sintaxis del lenguaje Visual Básico para aplicaciones (VBA).

Por ejemplo, una declaración SQL simple que recupera una lista de apellidos de contactos llamados Mary podría verse así:

SELECCIONAR Apellido
DE Contactos
DONDE Nombre_nombre = "María";

Nota: El lenguaje SQL se utiliza no sólo para realizar operaciones con datos, sino también para crear y cambiar la estructura de los objetos de la base de datos, como las tablas. La parte de SQL que se utiliza para crear y modificar objetos de bases de datos se llama DDL. DDL no se trata en este artículo. Para obtener más información, consulte Crear o modificar tablas o índices mediante una consulta de definición de datos.

SELECCIONAR declaraciones

La declaración SELECT se utiliza para describir un conjunto de datos en SQL. Contiene una descripción completa del conjunto de datos que deben recuperarse de la base de datos, incluido lo siguiente:

    tablas que contienen datos;

    conexiones entre datos de diferentes fuentes;

    campos o cálculos basados ​​en los datos seleccionados;

    condiciones de selección que deben cumplir los datos incluidos en el resultado de la consulta;

    Necesidad y método de clasificación.

declaraciones SQL

Una declaración SQL se compone de varias partes llamadas cláusulas. Cada cláusula de una declaración SQL tiene un propósito. Se requieren algunas ofertas. La siguiente tabla muestra las sentencias SQL más utilizadas.

declaración SQL

Descripción

Obligatorio

Define los campos que contienen los datos requeridos.

Define tablas que contienen los campos especificados en la cláusula SELECT.

Define las condiciones de selección de campos que deben cumplir todos los registros incluidos en los resultados.

Determina el orden de clasificación de los resultados.

En una declaración SQL que contiene funciones de agregación, identifica los campos para los cuales no se calcula un valor de resumen en la cláusula SELECT.

Sólo si dichos campos están presentes

Una declaración SQL que contiene funciones de agregación define las condiciones que se aplican a los campos para los cuales se calcula un valor de resumen en la cláusula SELECT.

términos SQL

Cada oración SQL consta de términos que se pueden comparar con partes del discurso. La siguiente tabla muestra los tipos de términos SQL.

término SQL

Parte comparable del discurso

Definición

Ejemplo

identificador

sustantivo

Un nombre utilizado para identificar un objeto de base de datos, como un nombre de campo.

Clientes.[Número de teléfono]

operador

verbo o adverbio

Una palabra clave que representa o modifica una acción.

constante

sustantivo

Un valor que no cambia, como un número o NULL.

expresión

adjetivo

Una combinación de identificadores, operadores, constantes y funciones diseñadas para calcular un valor único.

>= Productos.[Precio]

Cláusulas SQL básicas: SELECT, FROM y WHERE

El formato general de las sentencias SQL es:

SELECCIONAR campo_1
DE tabla_1
DONDE criterio_1
;

Notas:

    Access no respeta los saltos de línea en las sentencias SQL. A pesar de esto, se recomienda comenzar cada oración con nueva linea para que la declaración SQL sea fácil de leer tanto para la persona que la escribió como para todos los demás.

    Cada instrucción SELECT termina con un punto y coma (;). Un punto y coma puede aparecer al final de la última frase o al final linea separada al final de la declaración SQL.

Ejemplo en acceso

El siguiente ejemplo muestra cómo se vería una declaración SQL para una consulta de selección simple en Access.

1. Cláusula SELECT

2. Cláusula DE

3. Cláusula WHERE

Veamos el ejemplo frase por frase para entender cómo funciona la sintaxis SQL.

cláusula SELECCIONAR

SELECCIONAR,Empresa

Esta es una cláusula SELECT. Contiene una declaración (SELECT) seguida de dos identificadores ("[Dirección de correo electrónico]" y "Empresa").

Si el identificador contiene espacios o señales especiales(por ejemplo, "Dirección de correo electrónico"), debe estar entre corchetes rectangulares.

La cláusula SELECT no requiere que especifique las tablas que contienen los campos y no puede especificar las condiciones de selección que deben cumplir los datos incluidos en los resultados.

En una declaración SELECT, la cláusula SELECT siempre va antes de la cláusula FROM.

Cláusula DE

DE Contactos

Esta es una cláusula FROM. Contiene una declaración (FROM) seguida de un identificador (Contactos).

La cláusula FROM no especifica los campos a seleccionar.

cláusula donde

DONDE Ciudad="Seattle"

Esta es la cláusula WHERE. Contiene una declaración (DÓNDE) seguida de la expresión (Ciudad="Rostov").

Hay muchas cosas que puedes hacer con las cláusulas SELECT, FROM y WHERE. Para obtener más información sobre el uso de estas ofertas, consulte los siguientes artículos:

Clasificación de resultados: ORDENAR POR

Como en microsoft excel, en Access puedes ordenar los resultados de una consulta en una tabla. Al utilizar la cláusula ORDER BY, también puede especificar cómo se ordenan los resultados cuando se ejecuta la consulta. Si se utiliza una cláusula ORDER BY, debe aparecer al final de la declaración SQL.

La cláusula ORDER BY contiene una lista de campos para ordenar, en el mismo orden en que se aplicará la ordenación.

Supongamos, por ejemplo, que primero es necesario ordenar los resultados por el campo "Empresa" en orden descendente, y luego si hay registros con el mismo valor campos "Empresa", - ordénelos por el campo "Dirección de correo electrónico" en orden ascendente. La cláusula ORDER BY tendría este aspecto:

ORDEN POR Empresa DESC,

Nota: De forma predeterminada, Access ordena los valores en orden ascendente (de la A a la Z, de menor a mayor). Para ordenar los valores en orden descendente, debe especificar la palabra clave DESC.

Para obtener más información sobre la cláusula ORDER BY, consulte el artículo sobre la cláusula ORDER BY.

Trabajar con datos resumidos: cláusulas GROUP BY y HAVING

A veces es necesario trabajar con datos resumidos, como las ventas totales del mes o los artículos más caros en stock. Para hacer esto, la cláusula SELECT aplica una función agregada al campo. Por ejemplo, si ejecutara una consulta para obtener la cantidad de direcciones de correo electrónico de cada empresa, la cláusula SELECT podría verse así:

La capacidad de utilizar una función agregada particular depende del tipo de datos en el campo y de la expresión deseada. Para obtener más información sobre las funciones agregadas disponibles, consulte Funciones estadísticas de SQL.

Especificación de campos que no se utilizan en una función agregada: cláusula GROUP BY

Cuando se utilizan funciones agregadas, normalmente es necesario crear una cláusula GROUP BY. La cláusula GROUP BY especifica todos los campos a los que no se aplica la función agregada. Si las funciones agregadas se aplican a todos los campos de la consulta, no es necesario crear una cláusula GROUP BY.

oferta GRUPO BY debe seguir inmediatamente a la cláusula WHERE o FROM si no existe una cláusula WHERE. La cláusula GROUP BY enumera los campos en el mismo orden que la cláusula SELECT.

Sigamos con el ejemplo anterior. En la cláusula SELECT, si la función agregada se aplica solo al campo [Dirección de correo electrónico], entonces la cláusula GROUP BY tendría este aspecto:

GRUPO POR Empresa

Para obtener más información sobre la cláusula GROUP BY, consulte el artículo sobre la cláusula GROUP BY.

Restringir valores agregados mediante condiciones de agrupación: la cláusula HAVING

Si necesita especificar condiciones para limitar los resultados, pero el campo al que desea aplicarlas se usa en una función agregada, no puede usar una cláusula WHERE. En su lugar, se debe utilizar la cláusula HAVING. La cláusula HAVING funciona igual que la cláusula WHERE, pero se usa para datos agregados.

Supongamos, por ejemplo, que el primer campo de la cláusula SELECT es función AVG(que calcula el promedio):

SELECCIONAR CUENTA(), Empresa

Si desea limitar los resultados de la consulta según el valor funciones de CONTAR, no se puede aplicar una condición de selección en la cláusula WHERE a este campo. En cambio, la condición debería colocarse en la cláusula HAVING. Por ejemplo, si desea que su consulta devuelva filas solo si una empresa tiene varias direcciones de correo electrónico, puede utilizar la siguiente cláusula HAVING:

TENER CUENTA()>1

Nota: Una consulta puede incluir tanto una cláusula WHERE como una cláusula HAVING, con condiciones de selección para campos que no se usan en funciones estadísticas especificadas en la cláusula WHERE y condiciones para campos que se usan en funciones estadísticas en la cláusula HAVING.

Para obtener más información sobre la cláusula HAVING, consulte el artículo sobre la cláusula HAVING.

Combinando resultados de consulta: operador UNION

El operador UNION se utiliza para ver simultáneamente todos los datos devueltos por múltiples consultas de selección similares como un conjunto combinado.

El operador UNION le permite combinar dos declaraciones SELECT en una. Las declaraciones SELECT que se fusionan deben tener el mismo número y orden de campos de salida con tipos de datos iguales o compatibles. Cuando se ejecuta una consulta, los datos de cada conjunto de campos coincidentes se combinan en un único campo de salida, por lo que la salida de la consulta tiene tantos campos como cada instrucción SELECT individual.

Nota: En consultas para unir números y tipos de texto Los datos son compatibles.

Con el operador UNION, puede especificar si las filas duplicadas, si las hay, deben incluirse en los resultados de la consulta. Para hacer esto, use la palabra clave ALL.

Una consulta para combinar dos declaraciones SELECT tiene la siguiente sintaxis básica:

SELECCIONAR campo_1
DE tabla_1
UNIÓN
SELECCIONAR campo_a
DE tabla_a
;

Por ejemplo, supongamos que tiene dos tablas llamadas "Productos" y "Servicios". Ambas tablas contienen campos con el nombre del producto o servicio, precio e información de garantía, así como un campo que indica la exclusividad del producto o servicio ofrecido. Aunque las tablas de Productos y Servicios brindan diferentes tipos de garantías, la información básica es la misma (si los productos o servicios individuales están garantizados). Puede utilizar la siguiente consulta de combinación para unir cuatro campos de dos tablas:

SELECCIONE nombre, precio, garantía_disponible, oferta_exclusiva
DE Productos
UNIÓN TODOS
SELECCIONE nombre, precio, garantía_disponible, oferta_exclusiva
DE Servicios
;

Para obtener más información sobre cómo combinar declaraciones SELECT utilizando el operador UNION, consulte




Arriba