80575032 Libro de SQL y Tl SQL Excelente

280
Page 1 of 280 Transact-SQL User's Guide (Spanish) Prefacio Chapter 1: Introducción Chapter 2: Consultas: selección de datos de una tabla Chapter 3: Cómo resumir, agrupar y ordenar resultados de consultas Chapter 4: Combinaciones: recuperación de datos de varias tablas Chapter 5: Subconsultas: uso de consultas dentro de otras consultas Chapter 6: Uso y creación de tipos de datos Chapter 7: Creación de bases de datos y tablas Chapter 8: Adición, modificación y eliminación de datos Chapter 9: Vistas: limitación del acceso a datos Chapter 10: Uso de funciones incorporadas en consultas Chapter 11: Creación de índices en tablas Chapter 12: Definición de valores predeterminados y reglas para datos Chapter 13: Uso de lotes y lenguaje de control de flujo Chapter 14: Uso de procedimientos almacenados Chapter 15: Disparadores: imposición de la integridad de referencia Chapter 16: Cursores: acceso a los datos fila por fila Chapter 17: Transacciones: mantenimiento de la consistencia y recuperación de datos Glosario Prefacio Este manual, la Guía del Usuario de Transact-SQL , trata sobre Transact-SQL(R), una versión mejorada del lenguaje de bases de datos relacionales SQL. La Guía del Usuario de Transact-SQL está pensada para los principiantes y aquellos usuarios que ya tienen experiencia con otras implementaciones de SQL. A quién va dirigido Los usuarios de los sistemas de administración de bases de datos de SQL Server(TM) de Sybase que no están familiarizados con SQL pueden considerar esta guía como un libro de texto y comenzar por el principio. Los usuarios que carecen de experiencia con SQL deben concentrarse en la primera parte de este manual. En la segunda parte se describen temas que son más avanzados que los incluidos en la primera. Para los lectores que ya conocen otras versiones de SQL, este manual resulta útil como método de revisión y como guía a las mejoras de Transact-SQL. Los expertos en SQL deben estudiar las funciones y características que Transact-SQL ha añadido a SQL estándar, sobre todo el material sobre procedimientos almacenados. Utilización del manual Este manual es una guía completa a Transact-SQL que contiene un capítulo introductorio con una descripción general de SQL y varios capítulos divididos en dos partes principales: Conceptos básicos y Temas avanzados. El Capítulo 1, "Introducción", trata las convenciones para nombres utilizadas por SQL y las mejoras (también conocidas como extensiones) añadidas por Transact-SQL. También incluye una explicación sobre cómo empezar a usar Transact-SQL con la utilidad isql . Todos los usuarios deberían leer este capítulo, ya que constituye una iniciación al resto de los capítulos. "Parte 1: Conceptos básicos" incluye los capítulos 2 a 9. Estos capítulos constituyen una introducción a la funcionalidad básica de SQL. Los usuarios nuevos de SQL deben familiarizarse con los conceptos descritos en estos capítulos antes de pasar a la segunda parte. Los usuarios que ya tienen experiencia con SQL posiblemente quieran hojear los capítulos para aprender sobre las diversas extensiones Transact-SQL que presentan y, al mismo tiempo, repasar el material. "Parte 2: Temas avanzados" incluye los capítulos 10 a 17. En estos capítulos se describe Transact-SQL en mayor detalle, así como las mayoría de sus extensiones. Esta parte la deberían estudiar los usuarios familiarizados con SQL, pero no con Transact- SQL. Los ejemplos de esta guía, de los cuales hay muchos, están basados en la base de datos de muestra p ubs2 . Para aprovechar al máximo la información de la Guía del Usuario de Tr ansact-SQL , los usuarios nuevos deben trabajar con los ejemplos paso a paso. Diríjase a su administrador del sistema para solicitar una copia limpia de p ubs2 . Si desea obtener una descripción completa de la base de datos pubs2 , consulte el Suplemento de Referencia de SQL Server . Puede utilizar Transact-SQL con el programa autónomo isql de SQL Server. i sql es un programa de utilidad que se ejecuta directamente desde el sistema operativo.

Transcript of 80575032 Libro de SQL y Tl SQL Excelente

Page 1: 80575032 Libro de SQL y Tl SQL Excelente

Page 1 of 280

Transact-SQL User's Guide (Spanish)

Prefacio Chapter 1: Introducción Chapter 2: Consultas: selección de datos de una tabla Chapter 3: Cómo resumir, agrupar y ordenar resultados de consultas Chapter 4: Combinaciones: recuperación de datos de varias tablas Chapter 5: Subconsultas: uso de consultas dentro de otras consultas Chapter 6: Uso y creación de tipos de datos Chapter 7: Creación de bases de datos y tablas Chapter 8: Adición, modificación y eliminación de datos Chapter 9: Vistas: limitación del acceso a datos Chapter 10: Uso de funciones incorporadas en consultas Chapter 11: Creación de índices en tablas Chapter 12: Definición de valores predeterminados y reglas para datos Chapter 13: Uso de lotes y lenguaje de control de flujo Chapter 14: Uso de procedimientos almacenados Chapter 15: Disparadores: imposición de la integridad de referencia Chapter 16: Cursores: acceso a los datos fila por fila Chapter 17: Transacciones: mantenimiento de la consistencia y recuperación de datos Glosario

Prefacio

Este manual, la Guía del Usuario de Transact-SQL , trata sobre Transact-SQL(R), una versión mejorada del lenguaje de bases de datos relacionales SQL. La Guía del Usuario de Transact-SQL está pensada para los principiantes y aquellos usuarios que ya tienen experiencia con otras implementaciones de SQL.

A quién va dirigido

Los usuarios de los sistemas de administración de bases de datos de SQL Server(TM) de Sybase que no están familiarizados con SQL pueden considerar esta guía como un libro de texto y comenzar por el principio. Los usuarios que carecen de experiencia con SQL deben concentrarse en la primera parte de este manual. En la segunda parte se describen temas que son más avanzados que los incluidos en la primera.

Para los lectores que ya conocen otras versiones de SQL, este manual resulta útil como método de revisión y como guía a las mejoras de Transact-SQL. Los expertos en SQL deben estudiar las funciones y características que Transact-SQL ha añadido a SQL estándar, sobre todo el material sobre procedimientos almacenados.

Utilización del manual

Este manual es una guía completa a Transact-SQL que contiene un capítulo introductorio con una descripción general de SQL y varios capítulos divididos en dos partes principales: Conceptos básicos y Temas avanzados.

El Capítulo 1, "Introducción", trata las convenciones para nombres utilizadas por SQL y las mejoras (también conocidas como extensiones) añadidas por Transact-SQL. También incluye una explicación sobre cómo empezar a usar Transact-SQL con la utilidad isql . Todos los usuarios deberían leer este capítulo, ya que constituye una iniciación al resto de los capítulos.

"Parte 1: Conceptos básicos" incluye los capítulos 2 a 9. Estos capítulos constituyen una introducción a la funcionalidad básica de SQL. Los usuarios nuevos de SQL deben familiarizarse con los conceptos descritos en estos capítulos antes de pasar a la segunda parte. Los usuarios que ya tienen experiencia con SQL posiblemente quieran hojear los capítulos para aprender sobre las diversas extensiones Transact-SQL que presentan y, al mismo tiempo, repasar el material.

"Parte 2: Temas avanzados" incluye los capítulos 10 a 17. En estos capítulos se describe Transact-SQL en mayor detalle, así como las mayoría de sus extensiones. Esta parte la deberían estudiar los usuarios familiarizados con SQL, pero no con Transact-SQL.

Los ejemplos de esta guía, de los cuales hay muchos, están basados en la base de datos de muestra p ubs2 . Para aprovechar al máximo la información de la Guía del Usuario de Tr ansact-SQL , los usuarios nuevos deben trabajar con los ejemplos paso a paso. Diríjase a su administrador del sistema para solicitar una copia limpia de p ubs2 . Si desea obtener una descripción completa de la base de datos pubs2 , consulte el Suplemento de Referencia de SQL Server .

Puede utilizar Transact-SQL con el programa autónomo isql de SQL Server. i sql es un programa de utilidad que se ejecuta directamente desde el sistema operativo.

Page 2: 80575032 Libro de SQL y Tl SQL Excelente

Page 2 of 280

Documentos relacionados

La documentación del sistema de administración de bases de datos relacionales de SQL Server está diseñada para satisfacer la necesidad de simplicidad del usuario sin experiencia y, al mismo tiempo, el deseo de comodidad y amplitud de información del usuario con experiencia. La guía del usuario y los manuales de referencia abarcan las distintas necesidades de los usuarios finales, desarrolladores de aplicaciones, programadores y administradores de base de datos.

Otros manuales que pueden resultar de utilidad son:

Novedades de SQL Server de Sybase, Versión 11.0 , que describe las características nuevas introducidas en la versión 11.0.

Guía de Administración del Sistema SQL Server , que proporciona información pormenorizada sobre la administración de servidores y bases de datos. En este manual se incluyen instrucciones y pautas para administrar recursos físicos y bases de datos del sistema y del usuario, así como para especificar parámetros de conversión de caracteres, de idiomas internacionales y de criterios de ordenación.

Manual de Referencia de SQL Server , que contiene información detallada sobre los comandos y procedimientos del sistema explicados en este manual.

Suplemento de Referencia de SQL Server , que proporciona una lista de palabras reservadas de Transact-SQL, definiciones de tablas del sistema, una descripción de la base de datos de muestra p ubs2 , una lista de mensajes de error de SQL Server y otros datos de referencia comunes a todos los manuales.

Guía de Mejora de Rendimiento y Afinación de SQL Server , que proporciona información detallada sobre cómo afinar SQL Server y las consultas para obtener el máximo rendimiento.

Manual de programas de utilidad de SQL Server, que incluye información sobre los programas de utilidad de Sybase, como i sql y b cp , que se ejecutan desde el sistema operativo.

Guía del Usuario de las Características de Seguridad de SQL Server , que está dirigida al usuario general y donde se explica cómo utilizar las características de seguridad de SQL Server.

Guía de Administración de Seguridad de SQL Server , que está dirigida a los administradores del sistema responsables de mantener la seguridad del entorno operativo de SQL Server. En el manual se explica cómo utilizar las características de seguridad de SQL Server para controlar el acceso de usuarios a los datos.

La guía de instalación y configuración de SQL Server, donde se describen los procedimientos de instalación de SQL Server y se documentan las tareas de administración específicas del sistema operativo.

Master Index for SQL Server Publications, donde se combinan los índices del Manual de Referencia de SQL Server , la Guía del Usuario de Tr ansact-SQL , la Guía de Administración del Sistema y la Guía de Mejora de Rendimiento y Afinación . Utilice dicho índice para localizar diversos temas en distintos contextos a lo largo de toda la documentación.

Convenciones utilizadas en este manual

Formato de las instrucciones SQL

SQL es un lenguaje de forma libre: no hay reglas acerca del número de palabras que pueden ponerse en una línea, o acerca de dónde debe dividirse una línea. Sin embargo, a efectos de legibilidad, todos los ejemplos e instrucciones de sintaxis de este manual se han de formatear, de modo que cada cláusula de una instrucción comience en una nueva línea. Las cláusulas que tienen más de una parte se extienden a líneas adicionales, que aparecen con sangría.

Convenciones de sintaxis SQL

Las convenciones de las instrucciones de sintaxis de este manual son las siguientes:

Tabla 1: Convenciones de las instrucciones de sintaxis

Clave Definición

coman do o comand o

Los nombres de comando, de opción de comando, de utilidad, de indicador de utilidad y otras palabras clave se imprimen en C ourier negrita en las instrucciones de sintaxis, y en Helvetica negrita en el texto de los párrafos.

variable Las variables o las palabras que representan valores que debe introducir el usuario se muestran en cursiva.

{ } Las llaves indican que el usuario debe elegir al menos una de las opciones contenidas en ellas. No incluya las llaves en la opción.

[ ] Los corchetes significan que es opcional elegir una o más de las opciones contenidas entre ellos. No incluya los corchetes en la opción.

( ) Los paréntesis deben utilizarse como parte del comando.

Page 3: 80575032 Libro de SQL y Tl SQL Excelente

Page 3 of 280

| La barra vertical significa que puede seleccionar sólo una de las opciones mostradas.

, La coma significa que puede elegir tantas de las opciones mostradas como desee, separando las elegidas con comas, que se deben introducir como parte del comando.

Las instrucciones de sintaxis (que muestran la sintaxis y todas las opciones de un comando) se imprimen de la siguiente manera:

sp_dropdevice [ device_name ]

o, en el caso de un comando con más opciones:

select column_name

from table_name

where search_conditions

En las instrucciones de sintaxis, las palabras clave (comandos) aparecen en una fuente normal y los identificadores en minúsculas: fuente normal para las palabras clave y cursiva para las palabras suministradas por el usuario.

Los ejemplos que muestran el uso de comandos Transact-SQL se imprimen de la siguiente forma:

select * from publishers

Los ejemplos de salida de la computadora se imprimen de la siguiente manera:

pub_id pub_name city state

------- ------------------- ----------- -----

0736 New Age Books Boston MA

0877 Binnet & Hardley Washington DC

1389 Algodata Infosystems Berkeley CA

(3 rows affected)

Uso de mayúsculas o minúsculas

Las palabras clave pueden escribirse indistintamente en mayúsculas o minúsculas:

SELECT es lo mismo que Select y que select .

Opciones obligatorias {debe elegir al menos una}

Llaves y barras verticales: elija una y sólo una opción.

{die_on_your_feet | live_on_your_knees |

live_on_your_feet}

Llaves y com a : elija una o más opciones. Si elige más de una, sepárelas con comas.

{cash, check, credit}

Opciones optativas [no tiene que elegir ninguna]

Un elemento entre corchetes: no tiene obligación de elegirlo.

[anchovies]

Corchetes y barras verticales: elija una sola o ninguna .

[beans | rice | sweet_potatoes]

Page 4: 80575032 Libro de SQL y Tl SQL Excelente

Page 4 of 280

Corchetes y comas: elija ninguna, una o más de una opción. Si elige más de una, sepárelas con comas.

[extra_cheese, avocados, sour_cream]

Puntos suspensivos: repítalo una vez (y otra)...

Los puntos suspensivos (...) significan que es posible repetir la última unidad tantas veces como se desee. En esta instrucción de sintaxis, buy es una palabra clave necesaria:

buy thing = price [cash | check | credit]

[, thing = price [cash | check | credit] ]...

Debe comprar al menos una cosa y dar su precio. Puede elegir una forma de pago: una de las opciones que aparecen entre corchetes. También puede elegir comprar cosas adicionales: tantas como quiera. Por cada cosa que compre, dé su nombre y precio, y (de forma opcional) su forma de pago.

Expresiones

En las instrucciones de sintaxis de SQL Server, se usan distintos tipos de expresiones.

Tabla 2: Tipos de expresiones utilizadas en instrucciones de sintaxis

Uso Definición

expression Puede incluir constantes, literales, funciones, identificadores de columnas, variables o parámetros

logical expression Expresión que devuelve TRUE, FALSE o UNKNOWN

constant expression

Expresión que siempre devuelve el mismo valor, como "5+3" o "ABCDE"

float_expr Cualquier expresión de coma flotante o expresión que se convierte de forma implícita en un valor de coma flotante

integer_expr Cualquier expresión de número entero o expresión que se convierte de forma implícita en un valor de número entero

numeric_expr Cualquier expresión numérica que devuelve un solo valor

char_expr Cualquier expresión que devuelve un solo valor de tipo de caracteres

binary_expression Expresión que devuelve un solo valor b inary o varbinary

Si necesita ayuda

Existe a su disposición ayuda sobre el software de Sybase en la forma de documentación y Servicio de Asistencia Técnica de Sybase.

Cada instalación de Sybase tiene una persona designada que puede ponerse en contacto con el Servicio de Asistencia Técnica. Si no puede resolver un problema usando los manuales, deberá pedir a la persona designada que se ponga en contacto con el Servicio de Asistencia Técnica de Sybase.

Chapter 1

Introducción

Este capítulo trata lo siguiente:

Introducción general a SQL y sus componentes

Convenciones para nombres usadas para las diferentes partes de SQL

Mejoras de Transact-SQL (también conocidas como extensiones) añadidas a SQL

Compatibilidad ANSI

Uso de Transact-SQL con la utilidad isql

Introducción general

Convenciones para nombres

Page 5: 80575032 Libro de SQL y Tl SQL Excelente

Page 5 of 280

Extensiones Transact-SQL

Cumplimiento de normas

Uso de Transact-SQL con la utilidad isql

Introducción general

SQL (Structured Query Language - Lenguaje estructurado de consultas) es un lenguaje de alto nivel para sistemas de bases de datos relacionales. Desarrollado originalmente por el Laboratorio de Investigación de IBM en San José a finales de los años 70, SQL ha sido adoptado y adaptado en muchos sistemas de administración de bases de datos relacionales. Ha sido aprobado como norma oficial para lenguajes de consultas relacionales por parte del American National Standards Institute (ANSI) y la International Organizacion for Standardization (ISO). Transact-SQL es compatible con IBM SQL y con la mayoría de las demás implementaciones comerciales de SQL, y también proporciona importantes capacidades y funciones adicionales.

Aunque la "Q" de SQL significa "Query" (consulta), SQL incluye comandos no sólo para la consulta (recuperación de datos) de una base de datos, sino también para la creación de bases de datos y objetos de base de datos , adición de datos nuevos, modificación de datos existentes y otras funciones.

Consultas, modificación de datos y comandos

En este manual, consulta se refiere a una solicitud de recuperación de datos, llevada a cabo con el comando select . Por ejemplo:

select au_lname, city, state

from authors

where state = 'NY'

Modificación de datos se refiere a la adición, eliminación o edición de datos, realizadas mediante el comando insert, delete o update, respectivamente. Por ejemplo:

insert into authors (au_lname, au_fname, au_id)

values ("Smith", "Gabriella", "999-03-2346")

Otros comandos SQL son instrucciones para realizar operaciones administrativas. Por ejemplo:

drop table authors

Cada comando o instrucción SQL comienza con una palabra clave , como insert , que da nombre a la operación básica realizada. Muchos comandos SQL tienen una o más frases de palabras clave , o cláusulas , que adaptan el comando para que satisfaga una necesidad en particular. Cuando se ejecuta una consulta, Transact-SQL muestra el resultado al usuario. Si ninguno de los datos cumplen los criterios especificados en la consulta, el usuario obtiene un mensaje al efecto. Las instrucciones de modificación de datos y administrativas no muestran resultados, ya que no recuperan datos. Transact-SQL proporciona un mensaje que permite saber al usuario si la modificación de datos u otro comando se ha llevado a cabo.

Tablas, columnas y filas

SQL es un lenguaje de bases de datos específicamente diseñado para el modelo relacional de administración de bases de datos. En un sistema de administración de bases de datos relacionales, los usuarios ven los datos como tablas, que también se conocen como relaciones.

Cada fila (o registro) de una tabla describe una aparición de una entidad: una persona, empresa, venta o alguna otra cosa. Cada columna, o campo, describe una característica de la entidad: un nombre de persona o dirección, un nombre de empresa o su presidente, artículos vendidos, o una cantidad o fecha. Una base de datos consta de un conjunto de tablas relacionadas.

Figure 1-1: Una tabla de una base de datos relacional

Las operaciones relacionales

Las operaciones básicas de consulta en un sistema relacional son la selección (también llamada restricción), proyección y combinación. Todas ellas pueden combinarse en el comando select de SQL.

Page 6: 80575032 Libro de SQL y Tl SQL Excelente

Page 6 of 280

Una selección es un subconjunto de las filas de una tabla, basada en ciertas condiciones especificadas por el usuario. Por ejemplo, podría consultar las filas de todos los autores que viven en California.

Una proyección es un subconjunto de las columnas de una tabla. Por ejemplo, una consulta puede mostrar sólo el nombre y la ciudad de todos los autores, omitiendo la calle, el número de teléfono y el resto de la información.

Una combinación enlaza las filas de dos o más tablas comparando los valores de campos especificados. Por ejemplo, supongamos que hay una tabla con información sobre autores que incluye las columnas au_id (número de ID del autor) y au_lname (apellido del autor), y otra tabla con información sobre títulos de libros que incluye una columna au_id (número de ID del autor del libro). Las tablas authors y titles podrían combinarse, verificando la igualdad de los valores de las columnas au_id de cada tabla. Siempre que exista una coincidencia, se creará una fila nueva, con columnas de ambas tablas, que aparecerá como parte del resultado de la combinación. Las combinaciones a menudo se mezclan con proyecciones y selecciones para que sólo aparezcan las columnas elegidas de las filas seleccionadas coincidentes.

Convenciones para nombres

Una instrucción SQL debe seguir reglas sintácticas y estructurales precisas, y puede incluir sólo palabras clave SQL, identificadores (nombres de bases de datos, tablas u otros objetos de base de datos), operadores y constantes. Los caracteres que pueden utilizarse para cada parte de una instrucción SQL varían de una instalación a otra y se determinan en parte mediante definiciones del juego de caracteres predeterminado usado por SQL Server.

Por ejemplo, los caracteres permitidos para el lenguaje SQL, como las palabras clave SQL, caracteres especiales y extensiones Transact-SQL, están más limitados que los permitidos para los identificadores. El juego de caracteres que puede utilizarse para los datos es mucho mayor e incluye todos los caracteres que pueden usarse para el lenguaje SQL o los identificadores.

La Figura 1-2 muestra la relación entre los juegos de caracteres permitidos para las palabras clave SQL, identificadores y datos.

Figure 1-2: Caracteres usados para distintas partes de las instrucciones SQL

En las secciones siguientes se describen los juegos de caracteres que pueden utilizarse para cada parte de una instrucción. La sección sobre identificadores también describe las convenciones para nombres de los objetos de base de datos.

Caracteres de datos SQL

El juego de caracteres de datos SQL es el mayor juego de donde se toman los caracteres del lenguaje SQL y de los identificadores. Cualquier carácter del juego de caracteres de SQL Server, incluidos los caracteres de un solo byte o de múltiples bytes, puede utilizarse para valores de datos.

Caracteres del lenguaje SQL

Las palabras clave SQL, extensiones Transact-SQL y caracteres especiales, como los operadores de comparación ">" y "<", pueden representarse sólo mediante valores ASCII de 7 bits que cubran el rango A - Z, a - z, 0 - 9, y los siguientes caracteres ASCII.

Tabla 1-1: Caracteres ASCII usados en SQL

; (punto y coma) ( (paréntesis inicial) ) (paréntesis final)

, (coma) : (dos puntos) % (signo de porcentaje)

- (signo menos) ? (interrogación final) ' (comilla simple)

" (comilla doble) + (signo más) _ (subrayado)

* (asterisco) / (barra inclinada) (espacio)

< (operador menor que) > (operador mayor que) = (operador de igualdad)

& (símbolo de "y") | (barra vertical) ^ (acento circunflejo)

[ (corchete inicial) ] (corchete final) \ (barra invertida)

@ (símbolo de "en") ~ (tilde) ! (exclamación final)

$ (símbolo de dólar) # (símbolo de número) . (punto)

Identificadores

Page 7: 80575032 Libro de SQL y Tl SQL Excelente

Page 7 of 280

Las convenciones para los nombres de objetos de base de datos se aplican a todo el software y la documentación de SQL Server. Los identificadores pueden tener una longitud de hasta 30 bytes, se utilicen o no caracteres multibyte. El primer carácter de un identificador debe declararse como carácter alfabético en la definición del juego de caracteres usado en SQL Server.

Note: Los juegos de caracteres multibyte disponen de un margen más amplio de caracteres para su uso con los identificadores. Por ejemplo, en un servidor que tiene instalado el idioma japonés, es posible utilizar los siguientes tipos de caracteres como primer carácter de un identificador: Zenkaku o Hankaku Katakana, Hiragana, Kanji, Romaji, cirílico, griego o ASCII.

Los símbolos @ o _ (carácter de subrayado) también pueden utilizarse. El símbolo @ como primer carácter de un identificador indica una variable local.

Los nombres de tablas temporales deben empezar por # (símbolo de número) si se crean fuera de tempdb , o ir precedidos de " tempdb ..". Los nombres de las tablas temporales que existen fuera de tempdb no deben superar los 13 bytes de longitud, incluido el símbolo de número, ya que SQL Server les otorga un sufijo numérico interno.

Después del primer carácter, los identificadores pueden incluir caracteres declarados como alfabéticos, numéricos o los símbolos $, #, @, _, ¥ (yen) o £ (libra esterlina).

La distinción entre mayúsculas y minúsculas de SQL Server se establece al instalar el servidor y puede cambiarla el administrador del sistema. Para ver el parámetro del servidor, ejecute este comando:

sp_helpsort

En un servidor que no distinga entre mayúsculas y minúsculas, los identificadores MIOBJETO , miobjeto y MiObjeto (y todas las combinaciones posibles de caracteres en mayúsculas y minúsculas) se consideran idénticos. Sólo se puede crear uno de estos objetos, y el uso de esas combinaciones de mayúsculas y minúsculas referenciará a ese objeto.

No se permiten espacios incrustados en los identificadores, y no puede utilizarse ninguna palabra clave SQL reservada. Las palabras reservadas se enumeran en el Suplemento de Referencia de SQL Server .

Puede utilizar la función valid_name a fin de determinar si el identificador que ha creado es aceptable para SQL Server. A continuación se muestra la sintaxis:

select valid_name ( "string ")

donde string es el identificador que va a verificarse. Si string no es válido como identificador, SQL Server devuelve un 0 (cero). Si string es un identificador válido, SQL Server devuelve un número distinto de cero. SQL Server devuelve un 0 si los caracteres utilizados son ilegales o si string tiene más de 30 bytes de longitud.

Identificadores delimitados

Los identificadores delimitados son nombres de objetos incluidos entre comillas dobles. El uso de identificadores delimitados permite evitar ciertas restricciones sobre los nombres de objeto. Se pueden utilizar las comillas dobles para delimitar los nombres de tablas, vistas y columnas; no se pueden usar para otros objetos de base de datos.

Los identificadores delimitados pueden ser palabras reservadas, empezar con caracteres no alfabéticos e incluir caracteres que, de otro modo, no estarían permitidos. No pueden superar los 28 bytes.

Antes de crear o hacer referencia a un identificador delimitado, ejecute:

set quoted_identifier on

Esta opción permite que SQL Server reconozca los identificadores delimitados. Cada vez que utilice el identificador entre comillas dentro de una instrucción, debe incluirlo entre comillas dobles. Por ejemplo:

create table "1one"(col1 char(3))

select * from "1one"

create table "include spaces" (col1 int)

Note: Los identificadores delimitados no pueden usarse como parámetros de los procedimientos del sistema ni con bcp , y pueden no ser compatibles con todos los productos frontales.

Page 8: 80575032 Libro de SQL y Tl SQL Excelente

Page 8 of 280

Convenciones para nombres

Los nombres de objetos de base de datos no necesitan ser únicos en una base de datos. Sin embargo, los nombres de columnas y de índices deben ser únicos dentro de una tabla, y otros nombres de objetos deben ser únicos para cada propietario dentro de una base de datos. Los nombres de bases de datos deben ser únicos en SQL Server.

Si intenta crear una columna utilizando un nombre que no es único en la tabla o crear otro objeto de base de datos , como una tabla, una vista o un procedimiento almacenado, con un nombre ya usado en la misma base de datos, SQL Server responde con un mensaje de error.

Una tabla o columna pueden identificarse de forma única añadiendo otros nombres que las califiquen, es decir, el nombre de la base de datos, el nombre del propietario y, para una columna, el nombre de la tabla o de la vista. Cada uno de estos calificadores se separa del siguiente mediante un punto:

database.owner.table_name.column_name

database.owner.view_name.column_name

Por ejemplo, si el usuario "sharon" posee la tabla authors de la base de datos pubs2 , el identificador único de la columna city en dicha tabla es:

pubs2.sharon.authors.city

La misma sintaxis de asignación de nombres se aplica a otros objetos de base de datos. De igual modo, puede hacerse referencia a cualquier objeto:

pubs2.dbo.titleview

dbo.postalcoderule

Si la opción quoted_identifier está definida como on (activada), puede utilizar comillas dobles con partes concretas de un nombre de objeto calificado. Use un par distinto de comillas para cada calificador que precise comillas. Por ejemplo, utilice:

database . owner ." table_name "." column_name "

en lugar de:

database . owner ." table_name . column_name "

No siempre se permite la sintaxis de asignación de nombres completa en instrucciones create porque no se puede crear una vista, procedimiento, regla, valor predeterminado o disparador en una base de datos diferente de la actual. Las convenciones para nombres se señalan en la sintaxis como:

[[ database .] owner .] object_name

o bien:

[ owner .] object_name

El valor predeterminado de owner es el usuario actual y el de database es la base de datos actual. Cuando se hace referencia a un objeto en instrucciones SQL distintas de las instrucciones create , sin calificarlo con el nombre de la base de datos ni el nombre del propietario, SQL Server primero busca todos los objetos de propiedad del usuario y después todos los objetos pertenecientes al propietario de la base de datos , cuyo nombre en la base de datos es "dbo". Siempre que se proporcione suficiente información a SQL Server para identificar un objeto, no es necesario teclear cada elemento de su nombre. Los elementos intermedios pueden omitirse y sus posiciones pueden indicarse con puntos:

database..table_name

Al calificar un nombre de columna y un nombre de tabla en la misma instrucción, hay que asegurarse de utilizar las mismas abreviaturas de nombre para cada uno; tales abreviaturas se evalúan como cadenas de caracteres y deben coincidir, o se devolverá un error. Aquí se muestran dos ejemplos con entradas diferentes para el nombre de columna. El segundo ejemplo no se ejecuta porque la sintaxis del nombre de la columna no coincide con la del nombre de la tabla.

Page 9: 80575032 Libro de SQL y Tl SQL Excelente

Page 9 of 280

select pubs2.dbo.publishers.city

from pubs2.dbo.publishers

city

-----------------------

Boston

Washington

Berkeley

select pubs2.dbo.publishers.city

from pubs2..publishers

El prefijo de columna "pubs2.dbo.publishers" no coincide con ningún nombre de tabla o nombre de alias utilizado en la consulta.

Identificación de servidores remotos

Los procedimientos almacenados pueden ejecutarse en un SQL Server remoto, y los resultados del procedimiento almacenado aparecen impresos en el terminal que llamó al procedimiento. La sintaxis para la identificación de un servidor remoto y el procedimiento almacenado es:

[execute] server .[ database ].[ owner ]. procedure_name

La palabra clave execute puede omitirse cuando la llamada de procedimientos remotos es la primera instrucción de un lote. Si otras instrucciones SQL preceden a la llamada de procedimientos remotos, debe utilizarse execute o exec . Es necesario proporcionar el nombre del servidor y el del procedimiento almacenado. Si se omite el nombre de la base de datos, SQL Server buscará procedure_name en la base de datos predeterminada. Si se facilita el nombre de la base de datos, también deberá facilitarse el nombre del propietario del procedimiento, a menos que el usuario posea el procedimiento, o que el procedimiento pertenezca al propietario de la base de datos.

Todas las instrucciones siguientes ejecutan el procedimiento almacenado byroyalty de la base de datos pubs2 ubicada en el servidor GATEWAY:

Instrucción Notas

GATEWAY.pubs2.dbo.byroyalty GATEWAY.pubs2..byroyalty

byroyalty pertenece al propietario de la base de datos.

GATEWAY...byroyalty Debe usarse si pubs2 es la base de datos predeterminada.

declare @var int exec GATEWAY...byroyalty

Debe usarse cuando la instrucción no es la primera instrucción de un lote.

Consulte la Guía de Administración del Sistema SQL Server para obtener información sobre la configuración de SQL Server para acceso remoto. Un nombre de servidor remoto (GATEWAY en el ejemplo anterior) debe coincidir con un nombre de servidor del archivo interfaces de SQL Server. Si el nombre de servidor de interfaces aparece todo en mayúsculas, también debe usarse en mayúsculas en la llamada de procedimientos remotos.

Extensiones Transact-SQL

Transact-SQL fue diseñado para aumentar la potencia de SQL y para minimizar, si no eliminar, las ocasiones en las que los usuarios deben recurrir a un lenguaje de programación para llevar a cabo las tareas deseadas. Transact-SQL va más allá de las normas ISO y de las diversas versiones comerciales de SQL.

La mayoría de las mejoras de Transact-SQL (conocidas como extensiones) se resumen aquí. Otras extensiones, como las herramientas de administración de Transact-SQL, se describen en sus respectivos manuales.

La cláusula compute

La cláusula compute es una extensión Transact-SQL importante que se utiliza con funciones agregadas de fila, sum , max , min, avg y count , para calcular valores totales. Los resultados de una consulta que incluye una cláusula compute , se muestran con filas detalladas y resumidas, y tienen el aspecto de un informe que la mayoría de los DBMS sólo pueden producir con un generador de informes. compute muestra valores totales como filas adicionales en los resultados, en lugar de columnas nuevas. La cláusula compute se explica en el Capítulo 3, "Cómo resumir, agrupar y ordenar resultados de consultas".

Lenguaje de control de flujo

Page 10: 80575032 Libro de SQL y Tl SQL Excelente

Page 10 of 280

Transact-SQL proporciona un lenguaje de control de flujo que puede utilizarse como parte de cualquier instrucción SQL o lote. Estas estructuras están disponibles: begin ... end , break , continue , declare , goto label , if ... else , print , raiserror , return , waitfor y while . Las variables locales pueden definirse con declare y valores asignados. El sistema ofrece varias variables globales predefinidas.

Procedimientos almacenados

Una de las extensiones Transact-SQL más importantes es la capacidad de crear procedimientos almacenados. Los procedimientos almacenados pueden combinar casi cualquier instrucción SQL con el lenguaje de control de flujo. El creador de un procedimiento almacenado también puede definir parámetros que se faciliten cuando se ejecute el procedimiento almacenado.

La capacidad de escribir procedimientos almacenados propios aumenta en gran medida la potencia, eficacia y flexibilidad del lenguaje de base de datos SQL. Puesto que el plan de ejecución se guarda después de ejecutar los procedimientos almacenados, éstos pueden ejecutarse posteriormente mucho más deprisa que las instrucciones autónomas.

Los procedimientos almacenados suministrados por SQL Server, llamados procedimientos del sistema , se proporcionan para su uso en la administración del sistema de SQL Server. En el Capítulo 14, "Uso de procedimientos almacenados", se explican los procedimientos del sistema y el modo de crear procedimientos almacenados. Los procedimientos del sistema se describen de forma detallada en el Manual de Referencia de SQL Server .

Los usuarios pueden ejecutar procedimientos almacenados en servidores remotos. Otras extensiones Transact-SQL soportan valores de retorno de procedimientos almacenados, estado de retorno definido por el usuario de procedimientos almacenados y la capacidad de pasar parámetros desde un procedimiento a su solicitante.

Disparadores

Un disparador es un tipo especial de procedimiento almacenado que se utiliza para proteger la integridad de referencia: para imponer reglas sobre las relaciones entre datos de tablas diferentes. Los disparadores se activan cuando un usuario intenta modificar datos con un comando insert , delete o update .

Un disparador puede indicar al sistema que realice un número cualquiera de acciones cuando se intenta efectuar un cambio específico. Al evitar los cambios incorrectos, no autorizados o incoherentes, los disparadores ayudan a mantener la integridad de una base de datos.

Los disparadores pueden llamar a procedimientos almacenados locales o remotos, así como a otros disparadores. Los disparadores se pueden anidar a una profundidad de 16 niveles.

Reglas y valores predeterminados

Transact-SQL proporciona palabras clave para ayudar a mantener la integridad de la entidad (para garantizar que se facilite un valor para cada columna que requiera uno) e integridad de dominio (para garantizar que cada valor de una columna pertenezca al conjunto de valores legales de dicha columna). Los disparadores, descritos anteriormente, ayudan a mantener la integridad de referencia. Los valores predeterminados y las reglas definen las restricciones de integridad que entran en juego durante la introducción y modificación de datos.

Un valor predeterminado es un valor vinculado a una columna o tipo de datos concreto e insertado por el sistema si no se facilita ningún valor durante la introducción de datos. Las reglas son restricciones de integridad definidas por el usuario vinculadas a una columna o tipo de datos concreto e impuestas en el momento de la introducción de datos. Las reglas y valores predeterminados se explican en el Capítulo 12, "Definición de valores predeterminados y reglas para datos".

Manipulación de errores y opciones de set

Hay un gran número de técnicas de manipulación de errores a disposición del programador de Transact-SQL, incluida la capacidad de capturar el estado de retorno a partir de procedimientos almacenados, definir valores de retorno personalizados a partir de procedimientos almacenados, pasar parámetros desde un procedimiento a su solicitante y obtener informes a partir de variables globales como @@error . Las instrucciones raiserror y print , en combinación con el lenguaje de control de flujo, pueden dirigir mensajes de error al usuario de una aplicación Transact-SQL. Los desarrolladores pueden localizar print y raiserror para utilizar diferentes lenguajes.

Las opciones de set pueden personalizar la visualización de resultados, mostrar estadísticas de procesamiento y proporcionar otras ayudas de diagnóstico para depurar los programas Transact-SQL.

Page 11: 80575032 Libro de SQL y Tl SQL Excelente

Page 11 of 280

Extensiones SQL Server adicionales de SQL

Entre otras funciones únicas o poco usuales de Transact-SQL se incluyen:

Menos restricciones para las cláusulas group by y order by . Consulte el Capítulo 3, "Cómo resumir, agrupar y ordenar resultados de consultas".

Subconsultas, que pueden utilizarse casi en cualquier lugar donde se permita una expresión. Consulte el Capítulo 5, "Subconsultas: uso de consultas dentro de otras consultas".

Tablas temporales y otros objetos de base de datos temporales, que sólo existen mientras dura la sesión de trabajo actual y después desaparecen. Consulte el Capítulo 7, "Creación de bases de datos y tablas".

Tipos de datos definidos por el usuario generados a partir de los tipos de datos suministrados por SQL Server. Consulte el Capítulo 7 y el Capítulo 12, "Definición de valores predeterminados y reglas para datos".

La capacidad de insertar (con insert ) datos de una tabla en la misma tabla. Consulte el Capítulo 8, "Adición, modificación y eliminación de datos".

La capacidad de extraer datos de una tabla y ponerlos en otra mediante el comando update . Consulte el Capítulo 8.

La capacidad de quitar datos basados en datos de otras tablas utilizando la combinación en una instrucción delete . Consulte el Capítulo 8.

Una forma rápida de eliminar todas las filas de una tabla especificada y recuperar el espacio que ocupaban con el comando truncate table . Consulte el Capítulo 8.

Actualizaciones y selecciones mediante vistas. A diferencia de la mayoría de las demás versiones de SQL, Transact-SQL no pone ninguna restricción en la recuperación de datos mediante vistas, y relativamente pocas en la actualización de datos mediante vistas. Consulte el Capítulo 9, "Vistas: limitación del acceso a datos".

Gran número de funciones incorporadas. Consulte el Capítulo 10, "Uso de funciones incorporadas en consultas".

Opciones del comando create index para afinar aspectos de rendimiento determinados por los índices y controlar el tratamiento de claves y filas duplicadas. Consulte el Capítulo 11, "Creación de índices en tablas".

Control del usuario sobre lo que ocurre cuando se intentan introducir claves duplicadas en un índice único o filas duplicadas en una tabla. Consulte el Capítulo 11.

Operadores basados en bits para su uso con columnas de tipo integer y bit . Consulte el Manual de Referencia de SQL Server .

Soporte para los tipos de datos text e image . Consulte el Manual de Referencia de SQL Server .

Cumplimiento de normas

La progresión de las normas para los sistemas de administración de bases de datos relacionales está en curso. Estas normas las ha adoptado, y sigue adoptando, ISO y varios organismos de normalización. SQL86 fue la primera de estas normas y se sustituyó por SQL89. Esta, a su vez, fue sustituida por SQL92, que es la norma actual. SQL92 define tres niveles de cumplimiento: entrada, intermedio y completo. En EE.UU., el National Institute for Standards and Technology (NIST) ha establecido el nivel transicional, que está entre el de entrada y el intermedio.

Algunos comportamientos definidos por las normas no son compatibles con las aplicaciones SQL Server existentes. Transact-SQL dispone de opciones de set que permiten conmutar estos comportamientos.

El comportamiento compatible está activado de forma predeterminada para todas las aplicaciones de precompilador de Embedded SQL(TM). Otras aplicaciones que precisen satisfacer el comportamiento estándar SQL pueden utilizar los valores de opción de la Tabla 1-2 para el cumplimiento de SQL92 a nivel de entrada. Para obtener más información sobre la definición de estas opciones, consulte set en el Manual de Referencia de SQL Server .

Tabla 1-2: Opciones de set para el cumplimiento SQL

Opción Parámetro

ansi_permissions on

ansinull on

arithabort off

arithabort numeric_truncation on

arithignore off

chained on

close on endtran on

fipsflagger on

quoted_identifier on

string_rtruncation on

Page 12: 80575032 Libro de SQL y Tl SQL Excelente

Page 12 of 280

transaction isolation level 3

En las siguientes secciones se describen las diferencias entre el comportamiento estándar y el comportamiento predeterminado de Transact-SQL.

Creador de indicadores FIPS

Para clientes que escriben aplicaciones que deben cumplir con la norma, SQL Server proporciona una opción set fipsflagger . Cuando esta opción está activada, todos los comandos que contienen extensiones Transact-SQL que no se permiten a nivel de entrada SQL92 generan un mensaje informativo.

Transacciones encadenadas y niveles de aislamiento

Ahora SQL Server proporciona el comportamiento de transacciones "encadenadas" compatible con la norma SQL como una opción. En el modo encadenado, todos los comandos de recuperación y modificación de datos ( delete , insert , open , fetch , select y update ) inician de forma implícita una transacción . Dado que dicho comportamiento es incompatible con muchas aplicaciones Transact-SQL, las transacciones de tipo Transact-SQL (o "no encadenadas") permanecen como la opción predeterminada.

El modo de transacciones encadenadas puede iniciarse con la nueva opción set chained . La nueva opción set transaction isolation level controla los niveles de aislamiento de transacciones. Consulte el Capítulo 17, "Transacciones: mantenimiento de la consistencia y recuperación de datos", para obtener más información.

Identificadores delimitados

Ahora SQL Server admite el uso de identificadores delimitados para nombres de tablas, vistas y columnas. Los identificadores delimitados son nombres de objetos entre comillas dobles y su uso permite evitar ciertas restricciones sobre nombres de objetos.

Utilice la nueva opción set quoted_identifier para reconocer los identificadores delimitados. Cuando esta opción está activada, todos los caracteres incluidos entre comillas dobles son tratados como identificadores. Dado que este comportamiento es incompatible con muchas aplicaciones existentes, el valor predeterminado para esta opción es off (desactivada).

Comentarios de tipo estándar SQL

En Transact-SQL, los comentarios están delimitados por pares /* */ y pueden anidarse. Ahora Transact-SQL también admite los comentarios de tipo estándar SQL, que están formados por cualquier cadena de caracteres que empiece por dos signos menos conectados, un comentario y una línea nueva de finalización:

select "hello" -- esto es un comentario

Los comentarios /* */ de Transact-SQL están totalmente admitidos y los signos menos "- -" dentro de los comentarios de Transact-SQL todavía no se reconocen.

Truncado a la derecha de cadenas de caracteres

Una nueva opción de set , string_rtruncation , controla el truncado sin notificación al usuario de cadenas de caracteres para compatibilidad con la norma SQL. Defina esta opción como on (activada) para prohibir el truncado sin notificación al usuario e imponer el comportamiento de la norma SQL.

Permisos necesarios para las instrucciones update y delete

Una opción nueva de set , ansi_permissions , determina los permisos necesarios para las instrucciones delete y update . Cuando esta opción está definida como on , SQL Server utiliza los requisitos de permisos más estrictos de SQL92 para estas instrucciones. Dado que este comportamiento es incompatible con muchas aplicaciones existentes, el valor predeterminado de esta opción es off .

Errores aritméticos

Las opciones de set arithabort y arithignore se han redefinido para permitir la compatibilidad con la norma SQL92:

Page 13: 80575032 Libro de SQL y Tl SQL Excelente

Page 13 of 280

arithabort arith_overflow especifica el comportamiento posterior a un error de división por cero o a una pérdida de precisión. El valor predeterminado, on , revierte toda la transacción o lote en el que se produce el error. Si establece arithabort arith_overflow como off , SQL Server aborta la instrucción que causa el error, pero sigue procesando otras instrucciones de la transacción o del lote. Para el cumplimiento con la norma SQL92, hay que definir set arithabort arith_overflow off .

arithabort numeric_truncation especifica el comportamiento posterior a una pérdida de escala mediante un tipo numérico exacto. El valor predeterminado, on , aborta la instrucción que causa el error, pero sigue procesando otras instrucciones de la transacción o del lote. Si establece arithabort numeric_truncation como off , SQL Server trunca los resultados de la consulta y continúa con el procesamiento. Para el cumplimiento con la norma SQL92, hay que definir set arithabort numeric_truncation on .

arithignore arith_overflow determina si SQL Server muestra un mensaje después de un error de división por cero o de una pérdida de precisión. El valor predeterminado, off , muestra un mensaje de advertencia después de estos errores. El establecimiento de arithignore arith_overflow como on suprime los mensajes de advertencia después de estos errores. Para el cumplimiento con la norma SQL92, hay que definir set arithignore off .

Palabras clave sinónimas

Se han añadido varias palabras clave para compatibilidad con la norma SQL que son sinónimas de palabras clave Transact-SQL existentes.

Tabla 1-3: Palabras clave sinónimas SQL compatibles

Sintaxis actual Sintaxis adicional

tran transaction

work

any some

grant all grant all privileges

revoke all revoke all privileges

max ( expression ) max ([ all | distinct ]) expression

min ( expression ) min ([ all | distinct ]) expression

user_name built-in function user keyword

Tratamiento de valores nulos

Una opción nueva de set , ansinull , determina si la evaluación de los operandos con valor nulo (null) en comparaciones de igualdad (=) o desigualdad (!=) SQL y en funciones agregadas cumple con la norma SQL. Esta opción no afecta al modo en que SQL Server evalúa los valores nulos en otros tipos de instrucciones SQL, como create table .

Uso de Transact-SQL con la utilidad isql

Es posible usar SQL directamente desde el sistema operativo, con el programa de utilidad autónomo isql .

Para utilizar Transact-SQL, debe definir una cuenta, o login, en SQL Server. Cuando se usa isql , es necesario escribir lo siguiente junto al indicador del sistema operativo:

isql

Aparece en pantalla esta solicitud de información:

Password:

Escriba la contraseña junto a la solicitud y oprima la tecla de retorno. La contraseña no aparece en pantalla mientras se escribe. Observe que los nombres de login y las contraseñas distinguen las mayúsculas de las minúsculas. Esto es lo que verá:

1>

Ahora puede comenzar a emitir comandos Transact-SQL.

Para obtener información detallada sobre el uso de isql , consulte el manual Programas de Utilidad de SQL Server correspondiente al sistema operativo.

Page 14: 80575032 Libro de SQL y Tl SQL Excelente

Page 14 of 280

Selección de la contraseña

Una vez realizada la conexión, puede cambiar la contraseña en cualquier momento con el procedimiento del sistema sp_password . A continuación se indica cómo cambiar la contraseña "terrible2" a "3blindmice":

1> sp_password terrible2, 3blindmice

2> go

Observe que la palabra "go" aparece en una línea independiente y que no debe ir precedido de espacios en blanco ni tabuladores. Se trata del terminador de comando, que indica a SQL Server que el usuario ya ha terminado de introducir datos y que está listo para la ejecución del comando.

La contraseña es la primera línea de defensa frente al acceso a SQL Server de personas no autorizadas. Las contraseñas de SQL Server deben tener al menos seis bytes de longitud y pueden contener cualquier carácter imprimible. Cuando cree su propia contraseña, elija una que no pueda adivinarse. No use información personal, nombres de mascotas o seres queridos, ni palabras que aparezcan en el diccionario.

Las contraseñas más difíciles de adivinar son aquellas que combinan mayúsculas y minúsculas o números y letras. Una vez seleccionada la contraseña, su protección es responsabilidad del usuario. No proporcione a nadie su contraseña ni la anote en algún sitio donde la puedan ver.

Para obtener más información sobre sp_password , consulte el Manual de Referencia de SQL Server . Cuando ejecute un procedimiento almacenado, al final de la ejecución aparecerá un estado de retorno. Un estado de retorno de "0" significa que la ejecución se ha realizado correctamente.

Bases de datos predeterminadas

Al crear la cuenta de SQL Server, es posible que se le haya asignado una base de datos predeterminada, a la que se conecta cuando introduce el login. Por ejemplo, la base de datos predeterminada podría ser pubs2 , la de muestra. Si no se le ha asignado ninguna base de datos predeterminada, estará conectado a la base de datos master .

Puede sustituir la base de datos predeterminada por otra a la que tenga acceso (permiso) de uso o que admita usuarios invitados. Cualquier usuario con un login a SQL Server, es decir, que aparezca en master..syslogins , puede ser un invitado. Para cambiar la base de datos predeterminada, utilice el procedimiento del sistema sp_modifylogin . Para obtener información sobre este procedimiento, consulte el Manual de Referencia de SQL Server .

En cualquier caso, para cerciorarse de que se encuentra en pubs2 , ejecute este comando:

1> use pubs2

2> go

Ahora está listo para seguir los ejemplos proporcionados en el Capítulo 2, "Consultas: selección de datos de una tabla".

Con un par de excepciones, los ejemplos de instrucciones Transact-SQL mostrados en el resto del manual no incluyen las solicitudes de línea usadas por la utilidad isql , ni el terminador go . Para obtener más detalles sobre la utilidad isql , consulte el manual Programas de Utilidad de SQL Server del sistema operativo.

Uso de la base de datos de muestra pubs2

La base de datos de muestra pubs2 se utiliza en casi todos los ejemplos de este manual. Puede probar cualquiera de los ejemplos en su propia estación de trabajo.

Los resultados de consulta que aparecen en pantalla pueden no tener el mismo aspecto que los del manual. Esto es porque a algunos de los ejemplos que aparecen aquí se les ha dado otro formato (por ejemplo, realineación de columnas) a fin de proporcionar mayor claridad visual u ocupar menos espacio en la página.

Es posible que tenga que obtener permisos adicionales para cambiar la base de datos de muestra mediante create o instrucciones de modificación de datos. El administrador del sistema puede otorgar estos permisos. Si cambia la base de datos de muestra, compruebe que vuelve a asignarle su estado original para los futuros usuarios y usos. Si necesita ayuda para restaurar la base de datos de muestra, diríjase al administrador del sistema.

Contenido de la base de datos de muestra

Page 15: 80575032 Libro de SQL y Tl SQL Excelente

Page 15 of 280

La base de datos de muestra, pubs2 , se compone de las siguientes tablas: publishers, authors, titles, titleauthor, roysched, sales, salesdetail, stores, discounts, au_pix y blurbs . La mayoría de los ejemplos se toman de las primeras cuatro tablas. A continuación se describe brevemente cada tabla:

publishers contiene los números de identificación, nombres, ciudades y estados de tres editoriales.

authors contiene un número de identificación, nombre y apellido, dirección y tipo de contrato de cada autor. Para cada libro que se ha publicado o se va a publicar, la tabla titles contiene su número de identificación, nombre, tipo, número de identificación del editor, precio, anticipos, derechos de autor, ventas anuales hasta la fecha, comentarios y fecha de publicación.

titleauthor enlaza las tablas titles y authors . Para cada libro, contiene la ID del autor, la ID del título, el pedido del autor y la división de los derechos de autor entre los autores de un libro.

roysched enumera los rangos de ventas de unidades y los derechos de autor conectados a cada rango. Los derechos de autor son un porcentaje de los ingresos netos procedentes de las ventas.

sales registra la ID de la tienda, el número de pedido y la fecha de ventas del libro. Hace la función de la tabla master para las filas detalladas en salesdetail.

salesdetail registra las ventas en librerías de los títulos que aparecen en la tabla titles .

stores enumera las librerías por ID de tienda.

discounts enumera tres tipos de descuentos para librerías.

au_pix contiene imágenes de los autores en formato binario y el tipo de datos image .

blurbs contiene largas descripciones de los libros en el tipo de datos text .

La base de datos de muestra aparece en el Suplemento de Referencia de SQL Server .

Chapter 2

Consultas: selección de datos de una tabla

El comando select sirve para consultar la información de la base de datos. Puede utilizarse para recuperar un subconjunto de filas de una o varias tablas y un subconjunto de columnas de una o varias tablas.

En este capítulo se trata lo siguiente:

Selección de todas las columnas de una tabla

Selección de columnas especificadas de una tabla

Modificación de los formatos de resultados de la instrucción select cambiando el nombre de los encabezados de las columnas y añadiendo cadenas de caracteres

Inclusión de valores calculados simples en una instrucción select

Eliminación de filas duplicadas con distinct

Uso de la cláusula from para especificar tablas y vistas

Uso de la cláusula where con operadores de comparación, operadores lógicos, between , in , any y like

Uso de null y not null

Este capítulo se centra en instrucciones select básicas de una sola tabla. La información sobre los usos avanzados de select está disponible en capítulos posteriores de este libro.

Definición de consulta

Selección de columnas en una consulta

Eliminación de resultados de consulta duplicados con distinct

Especificación de tablas: la cláusula from

Selección de filas: la cláusula where

Definición de consulta

Una consulta es el proceso de solicitar datos de la base de datos y recibir resultados en respuesta. Este proceso también se conoce como recuperación de datos . Todas las consultas SQL se expresan mediante la instrucción select . Las consultas pueden usarse para realizar selecciones , que recuperan un subconjunto de filas de una o más tablas, y proyecciones , que recuperan un subconjunto de columnas de una o más tablas.

Esta es una versión simplificada de la instrucción select :

Page 16: 80575032 Libro de SQL y Tl SQL Excelente

Page 16 of 280

select select_list

from table_list

where search_conditions

La cláusula select especifica las columnas que desea recuperar. La cláusula from especifica las tablas de donde se deben extraer las columnas. La cláusula where especifica las filas de las tablas que se desean ver. Por ejemplo, la siguiente instrucción select busca el nombre y los apellidos de los escritores que viven en Oakland en la tabla authors .

select au_fname, au_lname

from authors

where city = "Oakland"

Los resultados de la instrucción select se muestran en formato de columna, como a continuación:

au_fname au_lname

-------------- -----------

Marjorie Green

Dick Straight

Dirk Stringer

Stearns MacFeather

Livia Karsen

(5 rows affected)

Sintaxis de select

La sintaxis de select es al mismo tiempo más sencilla y más compleja que la del ejemplo mostrado anteriormente. Es más sencilla en cuanto que la cláusula select es la única que se requiere en una instrucción select . La cláusula from se incluye casi siempre, pero técnicamente sólo es necesaria en las instrucciones select que recuperan datos de tablas. La cláusula where es opcional, al igual que todas las demás cláusulas. Por otro lado, la sintaxis completa de la instrucción select incluye las siguientes frases y palabras clave:

select [all | distinct] select_list

[into [[ database .]owner.] table_name ]

[from [[ database .] owner .]{ view_name | table_name

[(index index_name [ prefetch size ][lru|mru])]}

[holdlock | noholdlock] [shared]

[,[[ database .] owner .]{ view_name | table_name

[(index index_name [ prefetch size ][lru|mru])]}

[holdlock | noholdlock] [shared]]... ]

[where search_conditions ]

[group by [all] aggregate_free_expression

[, aggregate_free_expression ]... ]

[having search_conditions ]

[order by

{[[[ database .] owner .]{ table_name .| view_name .}]

column_name | select_list_number | expression }

[asc | desc]

[,{[[[ database .] owner .]{ table_name | view_name .}]

column_name | select_list_number | expression }

[asc | desc]]...]

[compute row_aggregate ( column_name )

[, row_aggregate ( column_name )]...

[by column_name [, column_name ]...]]

[for {read only | update [of column_name_list ]}]

[at isolation {read uncommitted | read committed |

serializable}]

[for browse]

Las cláusulas de una instrucción select deben usarse en el orden aquí indicado. Es decir, si la instrucción incluye una cláusula group by y otra order by , group by debe preceder a order by .

Page 17: 80575032 Libro de SQL y Tl SQL Excelente

Page 17 of 280

Tal como se explica en la sección "Identificadores", los nombres de los objetos de base de datos deben calificarse si existe ambigüedad sobre el objeto al que se hace referencia. Por ejemplo, si hay varias columnas llamadas name , es posible que haya que calificar name con el nombre de la base de datos, el del propietario o el de la tabla.

Dado que en los ejemplos de este capítulo se utilizan consultas a una sola tabla, los nombres de columna de los modelos de sintaxis y ejemplos no suelen calificarse con los nombres de las tablas, propietarios y bases de datos a que pertenecen. Estos elementos se han omitido a fin de facilitar la lectura, aunque nunca es incorrecto incluir calificadores. En las siguientes secciones de este capítulo se analiza la sintaxis de la instrucción select con más detalle.

En este capítulo sólo se describen algunas de las cláusulas y palabras clave incluidas en las sintaxis del comando select . Las cláusulas group by , having , order by y compute se describen en el Capítulo 3, "Cómo resumir, agrupar y ordenar resultados de consultas". La cláusula into se describe en el Capítulo 7, "Creación de bases de datos y tablas". La cláusula at isolation se explica en el Capítulo 17, "Transacciones: mantenimiento de la consistencia y recuperación de datos".

Las palabras clave holdlock , noholdlock y shared (que tratan sobre bloqueos en SQL Server), así como la cláusula index , se describen en la Guía de Mejora de Rendimiento y Afinación de SQL Server . Para obtener información sobre las cláusulas for read only y for update , consulte el Manual de Referencia de SQL Server .

Note: La cláusula for browse no se trata en este manual; se usa sólo en las aplicaciones DB-Library(TM). Consulte el Manual de Referencia de Open Client DB-Library/C para obtener más detalles al respecto.

Selección de columnas en una consulta

La lista select se compone con frecuencia de una serie de nombres de columna separados por comas, o de un asterisco para representar todas las columnas en el orden de create table .

Sin embargo, la lista de selección puede incluir una o más expresiones, separadas por comas, siempre que la expresión sea una constante, nombre de columna, función, subconsulta o cualquier combinación de los mismos, conectados mediante operadores aritméticos o basados en bits, y paréntesis. La sintaxis general de la lista de selección es como la siguiente:

select expression [, expression ]...

from table_list

Si alguno de los nombres de tabla o columna de la lista no cumple con las reglas relativas a los identificadores válidos, asegúrese de definir set quoted_identifier como on e incluir el identificador entre comillas dobles.

Selección de todas las columnas: s elect *

El asterisco (*) tiene un significado especial en las instrucciones select : representa todos los nombres de columna de todas las tablas especificadas por la cláusula from . Use el asterisco para ahorrar tiempo al teclear y evitar errores cuando desee ver todas las columnas de una tabla.

Esta es la sintaxis general para seleccionar todas las columnas de una tabla:

select *

from table_list

Dado que select * busca todas las columnas actuales de una tabla, los cambios en la estructura de una tabla, como la adición, supresión o cambio de nombre de columnas, modifican de forma automática los resultados de una instrucción select * . La presentación individual de las columnas proporciona un control más preciso sobre los resultados.

La siguiente instrucción recupera todas las columnas de la tabla publishers y las muestra en el orden en que se definieron al crear la tabla. No se incluye ninguna cláusula where , por lo que esta instrucción también recupera todas las filas.

select *

from publishers

Los resultados tendrán el siguiente aspecto:

pub_id pub_name city state

----- -------------- --------- -----

0736 New Age Books Boston WA

Page 18: 80575032 Libro de SQL y Tl SQL Excelente

Page 18 of 280

0877 Binnet & Hardley Washington DC

1389 Algodata Infosystems Berkeley CA

(3 rows affected)

Los resultados son exactamente los mismos si todos los nombres de columna de la tabla se enumeran por orden después de la palabra clave select :

select pub_id, pub_name, city, state

from publishers

También puede usar * más de una vez en una consulta:

select *, *

from publishers

El efecto es mostrar todos los nombres de columna y todos los datos guardados en las columnas dos veces. Al igual que los nombres de columna, * puede calificarse con un nombre de tabla, como en la siguiente consulta:

select publishers.*

from publishers

Selección de algunas columnas

Para seleccionar algunas, pero no necesariamente todas, las columnas de una tabla, use esta sintaxis:

select column_name [, column_name ]...

from table_name

Cada nombre de columna debe separarse del siguiente con una coma.

Cambio del orden de las columnas

El orden en que se enumeran los nombres de las columnas determina el orden en que éstas aparecen. Los dos ejemplos siguientes muestran cómo se especifica el orden que tendrán las columnas al mostrarlas. En ambos casos se buscan y muestran los nombres de los editores y los números de identificación de las tres filas de la tabla publishers . En el primero se imprime pub_id en primer lugar, seguido de pub_name . En el segundo se invierte este orden. La información es exactamente la misma; lo único que cambia es su organización.

select pub_id, pub_name

from publishers

pub_id pub_name

----- ---------------

0736 New Age Books

0877 Binnet & Hardley

1389 Algodata Infosystems

(3 rows affected)

select pub_name, pub_id

from publishers

pub_name pub_id

--------------------- ------

New Age Books 0736

Binnet & Hardley 0877

Algodata Infosystems 1389

(3 rows affected)

Cambio de los nombres de columna de los resultados de consultas

Cuando se muestran los resultados de las consultas, el encabezado predeterminado de cada columna toma el nombre que se le ha asignado durante su creación. Puede especificar un encabezado de columna mediante:

column_heading = column_name

Page 19: 80575032 Libro de SQL y Tl SQL Excelente

Page 19 of 280

o bien:

column_name column_heading

o bien:

column_name as column_heading

en lugar de indicar sólo el nombre de la columna en la lista de selección. Esto proporciona un nombre nuevo para la columna. Cuando este nombre se muestra en los resultados, funciona como un encabezado de columna, lo que permite producir resultados más fáciles de leer. Por ejemplo, para cambiar pub_name a "Publisher" en la consulta anterior, escriba cualquiera de estas instrucciones:

select Publisher = pub_name, pub_id

from publishers

select pub_name Publisher, pub_id

from publishers

select pub_name as Publisher, pub_id

from publishers

Los resultados de estas instrucciones tendrán este aspecto:

Publisher pub_id

---------------------- ------

New Age Books 0736

Binnet & Hardley 0877

Algodata Infosystems 1389

(3 rows affected)

Cadenas de caracteres entre comillas en los encabezados de columna

En un encabezado de columna se puede incluir cualquier carácter, incluidos espacios en blanco, si se encierra la totalidad del encabezado entre comillas. No es necesario definir la opción quoted_identifier como on . Si no se incluye entre comillas, el encabezado debe cumplir con las reglas correspondientes a los identificadores. Estas dos consultas:

select "Publisher's Name" = pub_name from publishers

y:

select pub_name "Publisher's Name" from publishers

generan este resultado:

Publisher's Name

----------------

New Age Books

Binnet & Hardley

Algodata Infosystems

También puede utilizar palabras reservadas Transact-SQL en los encabezados de columna entre comillas. Por ejemplo, la siguiente consulta, que usa la palabra reservada sum como encabezado de columna, es válida:

select "sum" = sum(total_sales) from titles

Los encabezados de columna incluidos entre comillas no pueden superar los 30 bytes de longitud.

Note: Antes de usar comillas para incluir el nombre de una columna en una instrucción create table , alter table , select into o create view , defina la opción quoted_identifier de set como on .

Cadenas de caracteres en los resultados de las consultas

Page 20: 80575032 Libro de SQL y Tl SQL Excelente

Page 20 of 280

Las instrucciones select vistas hasta ahora generan resultados formados por datos procedentes de las tablas de la cláusula from . En los resultados de las consultas también pueden mostrarse cadenas de caracteres.

Encierre toda la cadena de caracteres entre comillas simples o dobles y sepárela de los demás elementos de la lista de selección con comas. Use comillas dobles si dentro de la cadena hay un apóstrofo, ya que, de lo contrario, éste se interpretará como una comilla simple.

A continuación se muestra un ejemplo de una instrucción con una cadena de caracteres, seguida de sus resultados.

select "The publisher's name is", Publisher = pub_name

from publishers

Publisher

------------------------ --------------------

The publisher's name is New Age Books

The publisher's name is Binnet & Hardley

The publisher's name is Algodata Infosystems

(3 rows affected)

Valores calculados en la lista de selección

Puede llevar a cabo cálculos con datos de columnas numéricas o con constantes numéricas en una lista de selección.

Operadores aritméticos

La tabla siguiente muestra los operadores aritméticos disponibles. Para obtener información sobre los operadores basados en bits, consulte el Manual de Referencia de SQL Server .

Tabla 2-1: Operadores aritméticos

Símbolo Operación

+ Adición

- Sustracción

/ División

* Multiplicación

% Módulo

Los operadores aritméticos (adición, sustracción, división y multiplicación) pueden utilizarse en cualquier columna numérica ( int, smallint, tinyint, numeric, decimal, float o money ). El operador módulo no puede usarse con columnas money . Un módulo es el resto entero de una operación de división entre dos números enteros. Por ejemplo, 21 % 9 = 3, porque 21 dividido por 9 es igual a 2, y sobra 3.

Algunas operaciones aritméticas pueden efectuarse también con columnas datetime , mediante las funciones de fecha. Consulte el Capítulo 10, "Uso de funciones incorporadas en consultas", para obtener información sobre las funciones de fecha. Todos estos operadores pueden usarse en la lista de selección con nombres de columnas y constantes numéricas, en cualquier combinación. Por ejemplo, para ver cómo sería un incremento del 100 por cien de las ventas para todos los libros de la tabla titles, escriba:

select title_id, total_sales, total_sales * 2

from titles

Estos son los resultados:

title_id total_sales

-------- ----------- ---------

BU1032 4095 8190

BU1111 3876 7752

BU2075 18722 37444

BU7832 4095 8190

MC2222 2032 4064

MC3021 22246 44492

MC3026 NULL NULL

PC1035 8780 17560

Page 21: 80575032 Libro de SQL y Tl SQL Excelente

Page 21 of 280

PC8888 4095 8190

PC9999 NULL NULL

PS1372 375 750

PS2091 2045 4090

PS2106 111 222

PS3333 4072 8144

PS7777 3336 6672

TC3218 375 750

TC4203 15096 30192

TC7777 4095 8190

(18 rows affected)

Observe los valores nulos de la columna total_sales y la columna calculada. Los valores nulos no tienen valores explícitos asignados. Cuando se llevan a cabo operaciones aritméticas con un valor nulo (null), el resultado es NULL. Para asignar a la columna calculada un encabezado, como "proj_sales", escriba:

select title_id, total_sales,

proj_sales = total_sales * 2

from titles

Si desea que la visualización sea aún más clara, intente añadir cadenas de caracteres, como "Current sales =" y "Projected sales are", a la instrucción select . La columna a partir de la que se genera la columna calculada no tiene que aparecer en la lista de selección. La columna total_sales , por ejemplo, se muestra en estos ejemplos de consultas sólo para comparar sus valores con los valores de la columna total_sales * 2. Para ver sólo los valores calculados, escriba:

select title_id, total_sales * 2

from titles

Los operadores aritméticos también funcionan directamente con los valores de datos de las columnas especificadas, siempre que no haya ninguna constante. A continuación se muestra un ejemplo:

select title_id, total_sales * price

from titles

title_id

-------- ----------

BU1032 81,859.05

BU1111 46,318.20

BU2075 55,978.78

BU7832 81,859.05

MC2222 40,619.68

MC3021 66,515.54

MC3026 NULL

PC1035 201,501.00

PC8888 81,900.00

PC9999 NULL

PS1372 8,096.25

PS2091 22,392.75

PS2106 777.00

PS3333 81,399.28

PS7777 26,654.64

TC3218 7,856.25

TC4203 180,397.20

TC7777 61,384.05

(18 rows affected)

Por último, las columnas calculadas pueden proceder de varias tablas. Los capítulos sobre combinaciones y subconsultas ofrecen información sobre cómo trabajar con consultas de tablas múltiples.

Esta consulta calcula el producto del número de copias de un libro de psicología vendidas en un establecimiento (la columna qty de la tabla salesdetail ) y el precio del libro (la columna price de la tabla titles ).

select salesdetail.title_id, stor_id, qty * price

from titles, salesdetail

where titles.title_id = salesdetail.title_id

and titles.title_id = "PS2106"

Page 22: 80575032 Libro de SQL y Tl SQL Excelente

Page 22 of 280

title_id stor_id

-----------------------------------

PS2106 8042 210.00

PS2106 8042 350.00

PS2106 8042 217.00

(3 rows affected)

Precedencia de los operadores aritméticos

Cuando hay más de un operador aritmético en una expresión, se calculan primero la multiplicación, división y módulo, seguidos de la sustracción y adición. Cuando todos los operadores aritméticos de una expresión tienen el mismo nivel de precedencia, el orden de ejecución es de izquierda a derecha. Las expresiones entre paréntesis tienen preferencia sobre todas las demás operaciones.

Por ejemplo, la siguiente instrucción select multiplica las ventas totales de un libro por su precio para calcular la cantidad de ingresos totales, y luego resta a esta cantidad el anticipo entregado al autor dividido por la mitad.

El producto de total_sales y price se calcula en primer lugar porque el operador es el de multiplicación. A continuación, el anticipo se divide por 2. Luego, este resultado se resta de total_sales .

select title_id, total_sales * price - advance / 2

from titles

Para evitar malentendidos, utilice paréntesis. La siguiente consulta tiene el mismo significado y produce los mismos resultados que la anterior, pero probablemente resulte más fácil de entender.

select title_id,(total_sales * price)- (advance /2)

from titles

title_id

-------- ----------

BU1032 79,359.05

BU1111 43,818.20

BU2075 50,916.28

BU7832 79,359.05

MC2222 40,619.68

MC3021 59,015.54

MC3026 NULL

PC1035 198,001.00

PC8888 77,900.00

PC9999 NULL

PS1372 4,596.25

PS2091 1,255.25

PS2106 -2,223.00

PS3333 80,399.28

PS7777 24,654.64

TC3218 4,356.25

TC4203 178,397.20

TC7777 57,384.05

(18 rows affected)

Utilice paréntesis para modificar el orden de ejecución; los cálculos entre paréntesis se realizan antes. Si los paréntesis están anidados, el cálculo más interno es el que se realiza primero. Por ejemplo, el resultado y el significado del ejemplo anterior pueden cambiarse si usa paréntesis para que la sustracción se evalúe antes que la división:

select title_id, (total_sales * price - advance) /2

from titles

title_id

-------- -----------------------

BU1032 38,429.53

BU1111 20,659.10

BU2075 22,926.89

BU7832 38,429.53

MC2222 20,309.84

MC3021 25,757.77

MC3026 NULL

PC1035 97,250.50

PC8888 36,950.00

Page 23: 80575032 Libro de SQL y Tl SQL Excelente

Page 23 of 280

PC9999 NULL

PS1372 548.13

PS2091 10,058.88

PS2106 -2,611.50

PS3333 39,699.64

PS7777 11,327.32

TC3218 428.13

TC4203 88,198.60

TC7777 26,692.03

(18 rows affected)

Selección de valores text e image

Cuando la lista de selección incluye valores de tipo text e image , el límite de longitud de los datos devueltos depende del valor de la variable global @@textsize . El valor predeterminado de @@textsize depende del software usado para acceder a SQL Server; el valor predeterminado es de 32 K para isql . Este valor se modifica con el comando set :

set textsize 25

Con este valor de @@ textsize , una instrucción select que incluya una columna text sólo muestra los primeros 25 bytes de datos.

Note: Cuando se seleccionan datos de tipo image , el valor devuelto incluye los caracteres "0x", que indican que los datos son hexadecimales. Estos dos caracteres se cuentan como parte de @@textsize .

Para restablecer el valor predeterminado de @@textsize , use:

set textsize 0

El valor predeterminado mostrado es la longitud real de los datos cuando su tamaño es menor que textsize . Para obtener más información sobre los tipos de datos text e image , consulte el Capítulo 6, "Uso y creación de tipos de datos".

Uso de readtext

El comando readtext proporciona otra forma de recuperar valores text e image . Este comando necesita el nombre de la tabla y la columna, el puntero de texto, un desplazamiento inicial dentro de la columna y el número de caracteres o bytes que deben recuperarse. Este ejemplo busca 6 caracteres en la columna copy de la tabla blurbs :

declare @val varbinary(16)

select @val = textptr(copy) from blurbs

where au_id = "648-92-1872"

readtext blurbs.copy @val 2 6 using chars

En el ejemplo, readtext muestra los caracteres 3 a 8 de la columna copy , ya que el desplazamiento era de 2. La sintaxis completa del comando readtext es:

readtext [[ database .] owner .] table_name . column_name text_ptr offset size [holdlock]

[using {bytes|chars|characters}]

[at isolation {read uncommitted | read committed |

serializable}]

La función textptr devuelve una cadena de caracteres binaria de 16 bytes. Declare una variable local para contener el puntero de texto y luego use la variable con readtext . El indicador holdlock hace que el valor de texto quede bloqueado para las lecturas hasta el final de la transacción. Otros usuarios pueden leer el valor, pero no modificarlo. La cláusula at isolation se describe en el Capítulo 17, "Transacciones: mantenimiento de la consistencia y recuperación de datos".

Si utiliza un juego de caracteres multibyte, la opción using permite elegir si readtext debe interpretar el desplazamiento y el tamaño como bytes o como caracteres. Tanto chars como characters se usan para especificar caracteres. Esta opción no tiene ningún efecto cuando se usa con un juego de caracteres de un solo byte o con valores image ( readtext lee los valores image sólo de byte en byte). Si no se indica la opción using , readtext devuelve el valor como si se hubiesen especificado bytes.

Page 24: 80575032 Libro de SQL y Tl SQL Excelente

Page 24 of 280

SQL Server tiene que determinar el número de bytes que deben enviarse al cliente en respuesta a un comando readtext . Cuando el desplazamiento y el tamaño están en bytes, es sencillo determinar el número de bytes del texto devuelto. Cuando el desplazamiento y el tamaño están en caracteres, SQL Server debe dar un paso más para calcular el número de bytes que van a devolverse al cliente. Como resultado, el rendimiento puede resultar más lento cuando se usan caracteres como desplazamiento y tamaño. using characters sólo es útil cuando SQL Server utiliza un juego de caracteres multibyte. Esta opción garantiza que readtext no devuelva caracteres parciales.

Cuando se usan bytes como desplazamiento, SQL Server puede encontrar caracteres parciales al comienzo o al final de los datos text que deben devolverse. En caso de encontrarlos, el servidor sustituye cada carácter parcial por interrogaciones antes de devolver el texto al cliente.

No es posible usar readtext con columnas text e image de vistas.

Resumen de la lista select

La lista select puede incluir * (todas las columnas en el orden establecido por el comando create-table), una lista de nombres de columnas en cualquier orden, cadenas de caracteres, encabezados de columna y expresiones que incluyan operadores aritméticos. También puede incluir funciones agregadas, que se tratan en la sección sobre group by de este mismo capítulo y en el Capítulo 3, "Cómo resumir, agrupar y ordenar resultados de consultas". A continuación se facilitan algunas listas de selección que pueden probarse con las tablas de la base de datos de muestra pubs2 :

1. select titles.*

from titles

2. select Name = au_fname, Surname = au_lname

from authors

3. select Sales = total_sales * price,

ToAuthor = advance,

ToPublisher = (total_sales * price) - advance

from titles

4. select 'Social security #', au_id

from authors

5. select this_year = advance, next_year = advance

+ advance/10, third_year = advance/2,

'for book title #', title_id

from titles

6. select 'Total income is',

Revenue = price * total_sales,

'for', Book# = title_id

from titles

Eliminación de resultados de consulta duplicados con distinct

La palabra clave opcional distinct elimina las filas duplicadas de los resultados de una instrucción select .

Si no especifica distinct , se obtienen todas las filas, incluidas las duplicadas. De forma opcional, es posible especificar la palabra clave all antes de la lista de selección, en cuyo caso se obtienen todas las filas. all es el valor predeterminado.

Por ejemplo, si busca todos los códigos de identificación de autor de la tabla titleauthor sin distinct, se obtienen estas filas:

select au_id

from titleauthor

au_id

-----------

172-32-1176

213-46-8915

213-46-8915

238-95-7766

267-41-2394

267-41-2394

274-80-9391

409-56-7008

427-17-2319

472-27-2349

486-29-1786

486-29-1786

648-92-1872

672-71-3249

Page 25: 80575032 Libro de SQL y Tl SQL Excelente

Page 25 of 280

712-45-1867

722-51-5454

724-80-9391

724-80-9391

756-30-7391

807-91-6654

846-92-7186

899-46-2035

899-46-2035

998-72-3567

998-72-3567

(25 rows affected)

Si observa los resultados, podrá comprobar que existen varias filas duplicadas. Puede eliminarlas y ver sólo los códigos de ID ( au_id ) únicos, usando distinct .

select distinct au_id

from titleauthor

au_id

-----------

172-32-1176

213-46-8915

238-95-7766

267-41-2394

274-80-9391

409-56-7008

427-17-2319

472-27-2349

486-29-1786

648-92-1872

672-71-3249

712-45-1867

722-51-5454

724-80-9391

756-30-7391

807-91-6654

846-92-7186

899-46-2035

998-72-3567

(19 rows affected)

Note: A fin de mantener la compatibilidad con otras implementaciones de SQL, la sintaxis de SQL Server permite el uso de la palabra clave all para pedir de forma explícita todas las filas. Sin embargo, no existe ninguna razón para usar all , porque "todas las filas" es el valor predeterminado.

La palabra clave distinct considera los valores nulos como duplicados el uno del otro. En otras palabras, cuando distinct se incluye en una instrucción select , se devuelve un solo valor NULL en los resultados, independientemente del número de valores nulos encontrados.

Especificación de tablas: la cláusula from

La cláusula from es necesaria en todas las instrucciones select que usen datos procedentes de tablas o vistas. Utilícela para mostrar todas las tablas y vistas que contengan las columnas incluidas en la lista de selección y en la cláusula where . Si la cláusula from incluye varias tablas o vistas, sepárelas con comas.

El número máximo de tablas y vistas permitidas en una consulta es 16. Este total incluye las tablas indicadas en la cláusula from , las tablas de base a las que hace referencia una definición de vista, todas las tablas a las que se hace referencia en las subconsultas y todas las tablas a las que se hace referencia como parte de las restricciones de integridad referenciales.

La sintaxis de from es la siguiente:

select select_list

[from [[ database .] owner .]{ table_name | view_name }

[holdlock | noholdlock] [shared]

[,[[ database .] owner .]{ table_name | view_name }

[holdlock | noholdlock] [shared]]... ]

Page 26: 80575032 Libro de SQL y Tl SQL Excelente

Page 26 of 280

Los nombres de las tablas pueden tener entre 1 y 30 bytes de longitud. Como primer carácter puede usar una letra, @, # o _. Los siguientes caracteres pueden ser dígitos, letras, @, #, $, _, ¥ o £. Los nombres de las tablas temporales pueden comenzar por # (símbolo de número) si se crean fuera de tempdb o con " tempdb ..". Si crea una tabla temporal fuera de tempdb , su nombre no deberá exceder los 13 bytes, puesto que SQL Server asigna un sufijo numérico interno al nombre a fin de garantizar que éste sea único. Para más información, consulte el Capítulo 7, "Creación de bases de datos y tablas". En la cláusula from , la sintaxis completa de nombres para tablas y vistas siempre está permitida, por ejemplo:

database . owner . table_name

database . owner . view_name

Esto sólo es necesario cuando puede existir confusión entre varios nombres. Es posible asignar nombres de correlación a las tablas a fin de ahorrar tiempo al teclear. Los nombres de correlación se asignan en la cláusula from , indicando el nombre de correlación tras el nombre de la tabla, de la siguiente manera:

select p.pub_id, p.pub_name

from publishers p

Todas las demás referencias a esa tabla, por ejemplo en una cláusula where , deben usar el nombre de correlación. Los nombres de correlación no pueden comenzar por un valor numérico.

Selección de filas: la cláusula where

La cláusula where de una instrucción select especifica los criterios que definen las filas exactas que deben recuperarse. El formato general es:

select select_list

from table_list

where search_conditions

Las condiciones de búsqueda, o calificaciones, de la cláusula where incluyen:

Operadores de comparación (=, <, >, etc.)

where advance * 2 > total_sales * price

Márgenes ( between y not between )

where total_sales between 4095 and 12000

Listas ( in, not in )

where state in ("CA", "IN", "MD")

Coincidencias de caracteres ( like y not like )

where phone not like "415%"

Valores desconocidos ( is null y is not null )

where advance is null

Combinaciones de los anteriores ( and , or )

where advance < 5000 or total_sales between 2000

and 2500

Además, la palabra clave where puede introducir:

Condiciones de combinación (consulte el Capítulo 4, "Combinaciones: recuperación de datos de varias tablas").

Subconsultas (consulte el Capítulo 5, "Subconsultas: uso de consultas dentro de otras consultas").

Page 27: 80575032 Libro de SQL y Tl SQL Excelente

Page 27 of 280

Note: La única condición where que puede usar en las columnas de tipo text es like (o not like ).

Para obtener una lista completa de las condiciones de búsqueda posibles, incluidas algunas que no se mencionan aquí, consulte las secciones sobre las condiciones de búsqueda o la cláusula where del Manual de Referencia de SQL Server .

Operadores de comparación

Transact-SQL utiliza los siguientes operadores de comparación:

Tabla 2-2: Operadores de comparación de SQL

Operador Significado

= Igual que

> Mayor que

< Menor que

>= Mayor o igual que

<= Menor o igual que

!= Distinto de

<> Distinto de

!> No mayor que

!< No menor que

Los operadores se utilizan con la siguiente sintaxis:

where expression comparison_operator expression

donde cada expresión ( expression ) es una constante, nombre de columna, función, subconsulta o cualquier combinación de los mismos conectados mediante operadores aritméticos o basados en bits. En la comparación de datos de caracteres, < significa antes en el criterio de ordenación y > significa después en el criterio de ordenación (use el procedimiento del sistema sp_helpsort para ver el criterio de SQL Server).

Los espacios en blanco finales se ignoran en las comparaciones. Así, "Dirk" es lo mismo que "Dirk ". En la comparación de fechas, < significa antes y > significa después. Asegúrese de incluir entre comillas simples o dobles todos los datos de tipo char , nchar , varchar , nvarchar , text y datetime . Para obtener más información sobre la introducción de datos datetime , consulte el Capítulo 8, "Adición, modificación y eliminación de datos".

A continuación se muestran algunos ejemplos de instrucciones select que emplean operadores de comparación:

select *

from titleauthor

where royaltyper < 50

select authors.au_lname, authors.au_fname

from authors

where au_lname >'McBadden'

select au_id, phone

from authors

where phone !='415 658-9932'

select title_id, newprice = price * $1.15

from pubs2..titles

where advance > 5000

not niega una expresión. Cualquiera de las dos consultas siguientes buscará todos los libros sobre negocios y psicología que no tengan un anticipo superior a $5500. Sin embargo, observe la diferencia en la posición del operador lógico de negación ( not ) y el operador de comparación negativo ( !> ).

select title_id, type, advance

from titles

where (type = "business" or type = "psychology")

and not advance >5500

select title_id, type, advance

from titles

Page 28: 80575032 Libro de SQL y Tl SQL Excelente

Page 28 of 280

where (type = "business" or type = "psychology")

and advance !>5500

title_id type advance

-------- ------------ --------

BU1032 business 5,000.00

BU1111 business 5,000.00

BU7832 business 5,000.00

PS2091 psychology 2,275.00

PS3333 psychology 2,000.00

PS7777 psychology 4,000.00

(6 rows affected)

Márgenes ( between y not between )

Utilice la palabra clave between para especificar un margen incluyente, en el que se busque el valor más bajo y el más alto, así como los valores comprendidos entre éstos.

Por ejemplo, para buscar todos los libros con ventas entre 4095 y 12000, ambas inclusive, puede escribir esta consulta:

select title_id, total_sales

from titles

where total_sales between 4095 and 12000

title_id total_sales

-----------------

BU1032 4095

BU7832 4095

PC1035 8780

PC8888 4095

TC7777 4095

(5 rows affected)

Observe que los libros con ventas de 4095 se incluyen en los resultados. Si hay alguno con ventas de 12000, también se incluye. Puede especificar un margen excluyente con los operadores mayor que (>) y menor que (<). La misma consulta con los operadores mayor que y menor que devuelve los siguientes resultados, ya que estos operadores no son incluyentes:

select title_id, total_sales

from titles

where total_sales > 4095 and total_sales < 12000

title_id total_sales

------ -----------

PC1035 8780

(1 row affected)

not between busca todas las filas que no están dentro del margen. Para buscar todos los libros con ventas fuera del margen de 4095 a 12000, escriba:

select title_id, total_sales

from titles

where total_sales not between 4095 and 12000

title_id total_sales

-------- -----------

BU1111 3876

BU2075 18722

MC2222 2032

MC3021 22246

PS1372 375

PS2091 2045

PS2106 111

PS3333 4072

PS7777 3336

TC3218 375

TC4203 15096

(11 rows affected)

Listas ( in y not in )

Page 29: 80575032 Libro de SQL y Tl SQL Excelente

Page 29 of 280

La palabra clave in permite seleccionar valores que coincidan con los de una lista de valores. Por ejemplo, si no usa in y desea obtener una lista con los nombres y los estados de todos los autores que viven en California, Indiana o Maryland, puede escribir esta consulta:

select au_lname, state

from authors

where state = 'CA' or state = 'IN' or state = 'MD'

Sin embargo, para obtener el mismo resultado sin teclear tanto se usa in . Los elementos que siguen a la palabra clave in deben separarse mediante comas e incluirse entre paréntesis.

select au_lname, state

from authors

where state in('CA', 'IN', 'MD')

Estos son los resultados de ambas consultas:

au_lname state

----------- -----

White CA

Green CA

Carson CA

O'Leary CA

Straight CA

Bennet CA

Dull CA

Gringlesby CA

Locksley CA

Yokomoto CA

DeFrance IN

Stringer CA

MacFeather CA

Karsen CA

Panteley MD

Hunter CA

McBadden CA

(17 rows affected)

Quizás el uso más importante para la palabra clave in sea en las consultas anidadas, también llamadas subconsultas. Para obtener información completa sobre las subconsultas, consulte el Capítulo 5, "Subconsultas: uso de consultas dentro de otras consultas". Sin embargo, el siguiente ejemplo proporciona una idea de lo que puede hacer con las consultas anidadas y la palabra clave in .

Suponga que desea saber los nombres de los autores que reciben menos del 50 por cien de los derechos totales de autor de los libros de los que son coautores. La tabla authors contiene los nombres de los autores y la tabla titleauthor proporciona información sobre los derechos de autor. Uniendo ambas tablas con in , pero sin enumerarlas en la misma cláusula from , es posible extraer la información necesaria. La siguiente consulta se traduce de esta manera: buscar todos los códigos de ID ( au_id s) de la tabla titleauthor en que el autor obtenga menos del 50 por cien de los derechos de autor por cualquier libro. Luego, seleccionar en la tabla authors todos los nombres de autores cuyas au_id s coincidan con los resultados de la consulta titleauthor . Los resultados muestran que hay varios autores incluidos en la categoría inferior al 50 por cien.

select au_lname, au_fname

from authors

where au_id in

(select au_id

from titleauthor

where royaltyper <50)

au_lname au_fname

-------------- ------------

Green Marjorie

O'Leary Michael

O'Leary Michael

Gringlesby Burt

Yokomoto Akiko

MacFeather Stearns

Ringer Anne

(7 rows affected)

Page 30: 80575032 Libro de SQL y Tl SQL Excelente

Page 30 of 280

not in busca los autores que no coinciden con los elementos de la lista. La siguiente consulta busca los nombres de los autores que no obtienen menos del 50 por cien de los derechos de autor en al menos un libro.

select au_lname, au_fname

from authors

where au_id not in

(select au_id

from titleauthor

where royaltyper <50)

au_lname au_fname

--------------- ------------

White Johnson

Carson Cheryl

Straight Dick

Smith Meander

Bennet Abraham

Dull Ann

Locksley Chastity

Greene Morningstar

Blotchet-Halls Reginald

del Castillo Innes

DeFrance Michel

Stringer Dirk

Karsen Livia

Panteley Sylvia

Hunter Sheryl

McBadden Heather

Ringer Albert

(17 rows affected)

Búsqueda de cadenas de caracteres: like

Utilice la palabra clave like para seleccionar las filas con campos que coincidan con partes específicas de cadenas de caracteres. like se usa con los tipos de datos char , varchar , nchar , nvarchar , binary , varbinary , text y datetime .

La columna de datos puede compararse con una "cadena de búsqueda" que puede incluir estos símbolos especiales:

Tabla 2-3: Símbolos especiales para la búsqueda de cadenas de caracteres

Símbolos Significado

% Busca cualquier cadena de cero o más caracteres.

_ Busca cualquier carácter individual.

[ specifier ]

Los corchetes incluyen márgenes o conjuntos, como [a-f] o [abcdef]. El especificador ( specifier ) acepta dos formatos:

rangespec1 - rangespec2 :

rangespec1 indica el comienzo de un margen de caracteres.

- es un carácter especial, que indica un margen.

rangespec2 indica el final de un margen de caracteres.

set :

puede estar compuesto por cualquier conjunto discreto de valores, en cualquier orden, como [a2bR]. Observe que el margen [a-f] y los conjuntos [abcdef] y [fcbdae] devolverán el mismo conjunto de valores.

[^ specifier ]

El acento circunflejo (^) delante de un especificador indica exclusión. [^a-f] significa "no dentro del margen a-f"; [^a2bR] significa "ni a, ni 2, ni b ni R".

Los datos de las columnas pueden coincidir con constantes, variables u otras columnas que contengan estos caracteres comodín . Cuando use constantes, incluya las cadenas de búsqueda y las cadenas de caracteres entre paréntesis. Por ejemplo, si usa like con los datos de la tabla authors :

Page 31: 80575032 Libro de SQL y Tl SQL Excelente

Page 31 of 280

like "Mc%" busca todos los nombres que comiencen con las letras ''Mc'' (McBadden).

l ike "%inger" busca todos los nombres que terminen con ''inger'' (Ringer, Stringer).

like "%en%" busca todos los nombres que incluyan las letras ''en'' (Bennet, Green, McBadden).

like "_heryl" busca todos los nombres de seis letras que terminen con ''heryl'' (Cheryl).

like "[CK]ars[eo]n" busca ''Carsen'', '' Karsen'', ''Carson'' y ''Karson'' (Carson).

like "[M-Z]inger" busca todos los nombres que terminen con ''inger'' y que comiencen con cualquier letra de la M a la Z (Ringer).

like "M[^c]%" busca todos los nombres que empiecen con ''M'' y no tengan ''c'' como segunda letra.

Esta consulta busca todos los números de teléfono de la tabla authors cuyo prefijo sea 415:

select phone

from authors

where phone like "415%"

not like se puede usar con los mismos caracteres comodín. Para buscar todos los números de teléfono de la tabla authors cuyo prefijo no sea 415, puede utilizar cualquiera de las siguientes consultas:

select phone

from authors

where phone not like "415%"

select phone

from authors

where not phone like "415%"

La única condición where que puede usarse en columnas de tipo text es like . Esta consulta busca todas las filas de la tabla blurbs cuya columna copy mencione la palabra "computer":

select * from blurbs

where copy like "%computer%"

Los caracteres comodín utilizados sin like se interpretan como literales y no como un patrón; representan exactamente sus propios valores. La siguiente consulta trata de encontrar los números de teléfono compuestos exclusivamente por los cuatro caracteres "415%". No busca los números de teléfono que comienzan por 415.

select phone

from authors

where phone = "415%"

Uso de caracteres comodín como caracteres literales

Se pueden buscar caracteres comodín propiamente dichos convirtiéndolos en caracteres de escape y buscándolos como literales. Existen dos formas de utilizar los caracteres comodín como literales en una cadena de búsqueda like : corchetes y la cláusula escape .

La cadena de búsqueda también puede ser una variable o un valor de una tabla que contenga un carácter comodín. Para más información sobre like y los caracteres comodín (incluido el uso de like con juegos de caracteres multibyte y criterios de ordenación que no distingan las mayúsculas de las minúsculas), consulte el Manual de Referencia de SQL Server .

Corchetes (extensión Transact-SQL)

Utilice los corchetes como caracteres para el signo de porcentaje, el carácter de subrayado y el corchete inicial. El corchete final no precisa carácter de escape, puede usarse solo. Para buscar un guión, en lugar de emplearlo para especificar un margen de búsqueda, úselo como primer carácter dentro de los corchetes.

Tabla 2-4: Uso de corchetes para la búsqueda de caracteres comodín

Predicado like Significado

like "5%" 5 seguido por cualquier cadena de 0 o más caracteres

like "5[%]" 5%

like "_n" an, in, on, etc.

like "[_]n" _n

Page 32: 80575032 Libro de SQL y Tl SQL Excelente

Page 32 of 280

like "[a-cdf]" a, b, c, d, o bien f

like "[-acdf]" -, a, c, d, o bien f

like "[[ ]" [

like "]" ]

Cláusula escape (compatible con la norma SQL)

Use la cláusula escape para especificar un carácter de escape en el predicado like :

Tabla 2-5: Uso de la cláusula escape

Predicado l ike Significado

like "5@%" escape "@" 5%

like "*_n" escape "*" _n

like "%80@%%" escape "@" cadena que contiene 80%

like "*_sql**%" escape "*" cadena que contiene _sql*

like "%#####_#%%" escape "#" cadena que contiene ##_%

Un carácter de escape debe ser una cadena de un solo carácter. Es posible utilizar cualquier carácter del juego de caracteres predeterminado del servidor. La especificación de más de un carácter de escape genera una condición de error SQLSTATE y SQL Server muestra un mensaje de error.Por ejemplo, las siguientes cláusulas de escape originan esta condición de error:

like "%XX_%" escape "XX"

like "%XX%X_%" escape "XX"

Los caracteres de escape sólo son válidos dentro de su predicado like y no tienen ningún efecto sobre otros predicados like contenidos en la misma instrucción.

Los únicos caracteres que son válidos tras un carácter de escape son los caracteres comodín ( _, %, [, ] o [^] ) y el propio carácter de escape. El carácter de escape afecta sólo al carácter que le sigue, y no a los caracteres subsiguientes. Si el patrón contiene dos apariciones literales de un carácter que resulta ser un carácter de escape, la cadena debe contener cuatro caracteres de escape consecutivos (consulte el quinto ejemplo de la Tabla 2-5: Uso de la cláusula escape). De lo contrario, SQL Server genera una condición de error SQLSTATE y muestra un mensaje de error.Por ejemplo, las siguientes cláusulas de escape originan esta condición de error:

like "P%X%%X" escape "X"

like "%X%%Xd_%" escape "X"

like "%?X%" escape "?"

like "_e%&u%" escape "&"

Interacción de los corchetes y la cláusula escape

El carácter de escape conserva su significado especial dentro de los corchetes, a diferencia de lo que ocurre con los caracteres comodín, como el carácter de subrayado, el signo de porcentaje y el corchete inicial.

Conviene no utilizar los caracteres comodín existentes como caracteres de escape por las siguientes razones:

Si especifica el carácter de subrayado ( _ ) o el signo de porcentaje (%) como caracteres de escape, ambos pierden su significado especial dentro de ese predicado like y sólo actúan como caracteres de escape.

Si especifica el corchete inicial o el final ( [ o ] ) como caracteres de escape, el significado del corchete para Transact-SQL queda desactivado dentro de ese predicado like .

Si especifica - o [^] como caracteres de escape, ambos pierden el significado especial que suelen tener dentro de los corchetes y sólo actúan como caracteres de escape.

Espacios finales en blanco y %

Los espacios finales en blanco que siguen al signo "%" de una cláusula like se truncan a un solo espacio en blanco. like ''% '' (porcentaje seguido de 2 espacios) coincide con ''X '' (un espacio), ''X '' (dos espacios), ''X '' (tres espacios) o cualquier número de espacios finales.

Page 33: 80575032 Libro de SQL y Tl SQL Excelente

Page 33 of 280

Uso de caracteres comodín en columnas

Es posible usar caracteres comodín en las columnas, y los nombres de columnas, a su vez, en las cláusulas like . Puede crearse una tabla special_discounts en la base de datos pubs2 para ejecutar una proyección de precios para una venta especial:

id_type discount

------- -----------

BU% 10

PS% 12

MC% 15

La siguiente consulta usa los caracteres comodín de id_type en la cláusula where :

select title_id, discount, price, price - (price*discount/100)

from special_discounts, titles

where title_id like id_type

Los resultados de esa consulta son:

title_id discount price

-------- ----------- -------------- --------------

BU1032 10 19.99 17.99

BU1111 10 11.95 10.76

BU2075 10 2.99 2.69

BU7832 10 19.99 17.99

PS1372 12 21.59 19.00

PS2091 12 10.95 9.64

PS2106 12 7.00 6.16

PS3333 12 19.99 17.59

PS7777 12 7.99 7.03

MC2222 15 19.99 16.99

MC3021 15 2.99 2.54

MC3026 15 NULL NULL

(12 rows affected)

Esto permite la búsqueda de patrones sofisticados sin tener que crear una serie de cláusulas or .

Cadenas de caracteres y comillas

Cuando se introducen o buscan datos de caracteres y de fecha (tipos de datos char , nchar, varchar, nvarchar , datetime y smalldatetime ), es necesario incluirlos entre comillas simples o dobles.

Note: Si la opción quoted_identifier está definida como on, no utilice comillas dobles con datos de caracteres ni de fecha. Use comillas simples, ya que, de lo contrario, SQL Server considerará los datos como identificadores.

Existen dos formas de especificar comillas literales dentro de una entrada de datos de caracteres. El primer método consiste en usar dos comillas consecutivas. Por ejemplo, si comenzó la introducción de datos de caracteres con una sola comilla y desea incluir una comilla simple como parte de la entrada, use dos comillas simples seguidas:

'I don´´t understand.'

Con comillas dobles:

"He said, ""It is not really confusing."""

El segundo método consiste en encerrar una comilla en el otro tipo de comilla. En otras palabras, incluya una entrada que contenga comillas dobles entre comillas simples, o viceversa. He aquí algunos ejemplos:

'George said, "There must be a better way."' "Isn't there a better way?" 'George asked, "Isn´´t there a better way?"'

Page 34: 80575032 Libro de SQL y Tl SQL Excelente

Page 34 of 280

Para continuar una cadena de caracteres que sobrepase el final de una línea de la pantalla, introduzca una barra invertida (\) antes de pasar a la siguiente línea.

Valores "desconocidos": NULL

Cuando aparece NULL en una columna, significa que ni el usuario ni la aplicación han realizado ninguna entrada en esa columna. El valor de datos de esa columna es "desconocido" o "no disponible".

NULL no es sinónimo de "cero" (valores numéricos) ni de "espacio en blanco" (valores de caracteres). Los valores nulos permiten establecer una distinción entre introducir deliberadamente un cero para las columnas numéricas o un espacio en blanco para las columnas de caracteres, y no introducir nada, lo cual tiene el valor NULL tanto para las columnas numéricas como para las de caracteres.

NULL puede introducirse en una columna que admite valores nulos, según se haya especificado en la instrucción create table , de dos formas:

Si no se introducen datos, SQL Server introduce de forma automática el valor NULL.

El usuario puede introducir explícitamente el valor NULL tecleando la palabra "NULL" o "null" sin comillas simples ni dobles.

Si la palabra "NULL" se teclea en una columna de caracteres con comillas simples o dobles, se tratará como datos y no como un valor nulo.

Cuando se recuperan valores nulos, la presentación de los resultados de las consultas muestran la palabra NULL en la posición adecuada. Por ejemplo, la columna advance de la tabla titles permite valores nulos. Si examina los datos de dicha columna, podrá determinar si un libro no ha tenido ningún pago anticipado porque así se ha acordado (cero en la columna advance como en la fila correspondiente a MC2222), o bien si el importe del anticipo no se conocía cuando se introdujeron los datos (NULL en la columna advance, como en la fila correspondiente a MC3026).

select title_id, type, advance

from titles

where pub_id = "0877"

title_id type advance

-------- ---------- ---------

MC2222 mod_cook 0.00

MC3021 mod_cook 15,000.00

MC3026 UNDECIDED NULL

PS1372 psychology 7,000.00

TC3218 trad_cook 7,000.00

TC4203 trad_cook 4,000.00

TC7777 trad_cook 8,000.00

(7 rows affected)

Transact-SQL trata los valores nulos de diversas formas, según los operadores que se utilicen y el tipo de valores que se esté comparando. Los siguientes operadores devolverán resultados cuando se usen con un valor NULL:

= devuelve todas las filas que contienen NULL.

!= o <> devuelve todas las filas que no contienen NULL.

Sin embargo, cuando set ansinull está definido como on para cumplir con la norma SQL, los operadores = y != no devolverán ningún resultado cuando se usen con un valor NULL. Cualquiera que sea el valor de la opción set ansinull , los siguientes operadores nunca devolverán valores cuando se utilicen con NULL: <, <=, !<, >, >=, !>.

SQL Server puede determinar si un valor de columna es NULL. Así:

column1 = NULL

puede considerarse verdadero. Sin embargo, la comparación:

where column1 > null

Page 35: 80575032 Libro de SQL y Tl SQL Excelente

Page 35 of 280

nunca puede determinarse, ya que NULL significa "tener valor desconocido". No hay ningún motivo para suponer que dos valores desconocidos son iguales.

Esta lógica es también aplicable cuando se usan dos nombres de columnas en una cláusula where , es decir, cuando se combinan dos tablas. Una cláusula como "where column1 = column2" nunca devuelve filas en las que las columnas contengan valores nulos.

También puede buscar valores nulos o valores no nulos en la base de datos con este patrón:

where column_name is [not] null

Si trata de buscar valores nulos en columnas definidas como NOT NULL, SQL Server muestra un mensaje de error.

Algunas de las filas de la tabla titles contienen datos incompletos. Por ejemplo, se ha propuesto un libro titulado The Psychology of Computer Cooking y se han introducido su título, número de identificación de título y editor probable. Sin embargo, dado que el autor todavía no tiene un contrato como tal y aún hay algunos detalles por determinar, aparecen valores nulos en las columnas price , advance , royalty , total_sales y notes . Como los valores nulos no coinciden con nada en una comparación, una consulta para todos los números de identificación de títulos y los anticipos por libros con anticipos moderados (inferiores a $5000) no encontrará la fila de The Psychology of Computer Cooking que tiene el número de identificación MC3026.

select title_id, advance

from titles

where advance < $5000

title_id advance

---------- --------

MC2222 0.00

PS2091 2,275.00

PS3333 2,000.00

PS7777 4,000.00

TC4203 4,000.00

(5 rows affected)

A continuación se muestra una consulta para libros que tengan un anticipo inferior a $5000 o un valor nulo en la columna advance :

select title_id, advance

from titles

where advance < $5000

or advance is null

title_id advance

---------- --------

MC2222 0.00

MC3026 NULL

PC9999 NULL

PS2091 2,275.00

PS3333 2,000.00

PS7777 4,000.00

TC4203 4,000.00

(7 rows affected)

Consulte el Capítulo 7, "Creación de bases de datos y tablas", para obtener información sobre NULL en la instrucción create table , y sobre la relación existente entre NULL y los valores predeterminados. Consulte el Capítulo 8, "Adición, modificación y eliminación de datos", para obtener información sobre la inserción de valores nulos en una tabla. Consulte la sección sobre valores nulos del Manual de Referencia de SQL Server para obtener más información al respecto.

Conexión de condiciones con operadores lógicos

Los operadores lógicos and , or y not se utilizan para conectar condiciones de búsqueda en las cláusulas where .

and combina dos o más condiciones y devuelve resultados sólo cuando todas las condiciones se cumplen. Por ejemplo, la siguiente consulta busca sólo las filas en las que el apellido del autor es Ringer y el nombre es Anne. No encontrará la fila correspondiente a Albert Ringer.

Page 36: 80575032 Libro de SQL y Tl SQL Excelente

Page 36 of 280

select *

from authors

where au_lname = 'Ringer' and au_fname = 'Anne'

or también conecta dos o más condiciones, pero devuelve resultados cuando se cumple cualquiera de las condiciones. La siguiente consulta busca filas que contengan Anne o Ann en la columna au_fname.

select *

from authors

where au_fname = 'Anne' or au_fname = 'Ann'

not niega la expresión a la que precede. La siguiente consulta selecciona todos los autores que no viven en California:

select * from authors

where not state = "CA"

Precedencia de los operadores lógicos

Los operadores aritméticos y basados en bits se evalúan antes que los lógicos. Cuando se usa más de un operador lógico en una instrucción, not se evalúa primero, luego and , y, por último, or . Consulte el Manual de Referencia de SQL Server para obtener información sobre los operadores basados en bits.

Por ejemplo, la siguiente consulta busca todos los libros de negocios de la tabla titles, independientemente de sus anticipos, así como todos los libros de psicología cuyo anticipo sea superior a $5500. La condición del anticipo corresponde a libros de psicología y no de negocios porque el operador and se evalúa antes que el operador or .

select title_id, type, advance

from titles

where type = "business" or type = "psychology"

and advance >5500

title_id type advance

---------- ------------------

BU1032 business 5,000.00

BU1111 business 5,000.00

BU2075 business 10,125.00

BU7832 business 5,000.00

PS1372 psychology 7,000.00

PS2106 psychology 6,000.00

(6 rows affected)

Es posible cambiar el significado de la consulta añadiendo paréntesis para forzar la evaluación de or en primer lugar. Esta consulta encuentra todos los libros de negocios y de psicología cuyo avance sea superior a $5500:

select title_id, type, advance

from titles

where (type = "business" or type = "psychology")

and advance >5500

title_id type advance

-------- ---------- ---------

BU2075 business 10,125.00

PS1372 psychology 7,000.00

PS2106 psychology 6,000.00

(3 rows affected)

Chapter 3

Cómo resumir, agrupar y ordenar resultados de consultas

Los resultados de consultas se pueden resumir, agrupar y ordenar utilizando funciones agregadas y las cláusulas group by , having y order by con la instrucción select . También se puede usar la cláusula compute (una extensión Transact-SQL) con funciones agregadas para generar un informe con filas detalladas y resumidas. El operador union permite combinar los resultados de las consultas.

Page 37: 80575032 Libro de SQL y Tl SQL Excelente

Page 37 of 280

En este capítulo se trata lo siguiente:

Cómo resumir resultados de consultas mediante funciones agregadas

Organización de resultados de consultas en grupos

Selección de grupos de datos

Ordenación de resultados de consultas

Cómo resumir grupos de datos

Combinación de resultados de consultas

Si el SQL Server que utiliza no distingue mayúsculas de minúsculas, consulte group by y compute en el Manual de Referencia de SQL Server para obtener ejemplos de cómo la distinción entre mayúsculas y minúsculas afecta a los datos devueltos por estas cláusulas.

Cómo resumir resultados de consultas mediante funciones agregadas

Organización de resultados de consultas en grupos: la cláusula group by

Selección de grupos de datos: la cláusula having

Ordenación de resultados de consultas: la cláusula order by

Cómo resumir grupos de datos: la cláusula compute

Combinación de consultas: el operador union

Cómo resumir resultados de consultas mediante funciones agregadas

Las funciones agregadas calculan valores sumarios a partir de datos de una columna concreta.

Las funciones agregadas pueden aplicarse a todas las filas de una tabla, a un subconjunto de la tabla especificada por una cláusula where o a uno o más grupos de filas de la tabla. De cada conjunto de filas al que se aplica una función agregada se genera un solo valor.

Este ejemplo calcula la suma de ventas anuales hasta la fecha para todos los libros de la tabla titles :

select sum(total_sales)

from titles

-------------

97446

(1 row affected)

Observe que para utilizar las funciones agregadas hay que proporcionar el nombre de la función seguido del nombre de la columna cuyos valores serán objeto de la función. Incluya el nombre de columna, que es el argumento de la función, entre paréntesis.

Esta es la sintaxis general de las funciones agregadas:

aggregate_function ([all|distinct] expression)

Los operadores agregados son sum , avg , max , min , count y count(*) . La palabra clave opcional distinct puede utilizarse con sum , avg y count para eliminar valores duplicados antes de aplicar la función agregada. No se permite el uso de distinct con max , min ni count (*). Para sum , avg y count , el valor predeterminado es all , que realiza la operación en todas las filas. La palabra clave all es opcional.

La "expresión" a la que hace referencia la instrucción de sintaxis es generalmente un nombre de columna. También puede ser una constante, una función o cualquier combinación de nombres de columna, constantes y funciones conectadas por operadores aritméticos o basados en bits. Una expresión también puede ser una subconsulta.

Por ejemplo, podría calcular el precio promedio de todos los libros si se duplicaran los precios con esta instrucción:

select avg(price * 2)

from titles

-------------

29.53

Page 38: 80575032 Libro de SQL y Tl SQL Excelente

Page 38 of 280

(1 row affected)

La sintaxis y los resultados de las funciones agregadas son:

Tabla 3-1: Sintaxis y resultados de las funciones agregadas

Función agregada Resultado

sum([all | distinct] expression ) Total de los valores (distintos) de la expresión

avg([all | distinct] expression ) Promedio de los valores (distintos) de la expresión

count([all | distinct] expression ) Número de valores (distintos) no nulos de la expresión

count(*) Número de filas seleccionadas

max( expression ) Valor máximo de la expresión

min( expression ) Valor mínimo de la expresión

Las funciones agregadas pueden utilizarse en una lista de selección, como en los ejemplos anteriores, o en la cláusula having de una instrucción select que incluya una cláusula group by . Para obtener información sobre la cláusula having , consulte "Selección de grupos de datos: la cláusula having".

Las funciones agregadas no pueden utilizarse en una cláusula where .

Sin embargo, una instrucción select con funciones agregadas en su lista de selección incluye con frecuencia una cláusula where que restringe las filas a las que se aplica la función agregada. En los ejemplos anteriores, cada función agregada generaba un solo valor sumario para toda la tabla.

Si una instrucción select incluye una cláusula where , pero no una cláusula group by , una función agregada genera un solo valor para el subconjunto de filas especificado por la cláusula where . Sin embargo, select también puede incluir una columna en su lista de selección (una extensión Transact-SQL), que repetiría el valor único para cada fila en la tabla de resultados. En ese caso, es posible calificar las filas con la cláusula having , que se describe en "Selección de grupos de datos: la cláusula having".

Esta consulta devuelve el promedio de anticipos y la suma de ventas anuales hasta la fecha sólo para libros de negocios:

select avg(advance), sum(total_sales)

from titles

where type = "business"

------------- ---------

6,281.25 30788

(1 row affected)

Cuando una función agregada se utiliza en una instrucción select que no incluye una cláusula group by , se genera un solo valor. Esto se cumple tanto si la función se aplica a todas las filas de una tabla o a un subconjunto de filas definidas por una cláusula where . En este caso, el valor se denomina agregado escalar .

Observe que puede utilizar más de una función agregada en la misma lista de selección y generar más de un agregado escalar en una sola instrucción select .

Funciones agregadas y tipos de datos

sum y avg sólo pueden utilizarse con columnas numéricas: int , smallint , tinyint, decimal, numeric, float y money .

min y max no pueden usarse con tipos de datos bit .

Las funciones agregadas distintas de count(*) no pueden utilizarse con los tipos de datos text e image .

Con estas excepciones, las funciones agregadas pueden utilizarse con cualquier tipo de columna. Por ejemplo, puede emplear min (mínimo) para hallar el valor mínimo (el más cercano al principio del alfabeto) de una columna de tipo de caracteres:

select min(au_lname)

from authors

Page 39: 80575032 Libro de SQL y Tl SQL Excelente

Page 39 of 280

--------------------------

Bennet

(1 row affected)

Uso de count (* )

count(*) no requiere ninguna expresión como argumento porque, por definición, no emplea información sobre ninguna columna concreta. count(*) se utiliza para hallar el número total de filas de una tabla. Esta instrucción halla el número total de libros:

select count(*)

from titles

------------------

18

(1 row affected)

count(*) devuelve el número de filas de la tabla especificada sin eliminar las duplicadas. Cuenta cada fila de forma independiente, incluidas las que contienen valores nulos.

Al igual que otras funciones agregadas, count(*) puede combinarse con otros agregados en la lista de selección, con cláusulas where , etc.:

select count(*), avg(price)

from titles

where advance > 1000

---------- ---------

15 14.42

(1 row affected)

Uso de funciones agregadas con distinct

La palabra clave distinct es opcional con sum , avg y count , y no se permite con min , max ni count(*) . Cuando se utiliza distinct , los valores duplicados se eliminan antes de calcular la suma, el promedio o el conteo.

Si utiliza distinct , el argumento no puede incluir una expresión aritmética, sólo debe componerse de un nombre de columna.

Cuando se utiliza distinct , esta palabra clave aparece entre paréntesis y antes del nombre de la columna. Por ejemplo, para hallar el número de ciudades diferentes en las que hay autores, escriba:

select count(distinct city)

from authors

-------------

16

(1 row affected)

La siguiente instrucción devuelve el promedio de los distintos precios de los libros de negocios:

select avg(distinct price)

from titles

where type = "business"

-------------

11.64

(1 row affected)

Si hay dos o más libros con el mismo precio y utiliza la palabra clave distinct , el precio compartido se incluye sólo una vez en el cálculo. Para obtener un cálculo exacto del precio promedio de los libros de negocios, tendría que omitir distinct :

select avg(price)

from titles

where type = "business"

Page 40: 80575032 Libro de SQL y Tl SQL Excelente

Page 40 of 280

-------------

13.73

(1 row affected)

Valores nulos y funciones agregadas

Los valores nulos de las columnas donde se aplica la función agregada se ignoran para fines de la función. Si se definió ansinull como on , SQL Server mostrará un mensaje de error cada vez que se ignore un valor nulo. Para obtener más información, consulte el comando set en el Manual de Referencia de SQL Server .

Si todos los valores de una columna son nulos, count ( column_name ) devuelve cero. Por ejemplo, si solicita el conteo ( count ) de los anticipos de la tabla titles , la respuesta no será la misma que si solicita el conteo de los nombres de títulos, debido a los valores nulos de la columna advance :

select count(advance)

from titles

-------------

16

(1 row affected)

select count(title)

from titles

-------------

18

(1 row affected)

La excepción a esta regla es count(*) , que cuenta cada fila, aunque cada campo de la misma sea nulo (NULL).

Si ninguna fila cumple las condiciones especificadas en la cláusula where , count devolverá un valor de cero. Todas las demás funciones devuelven NULL. A continuación se muestran unos ejemplos:

select count(distinct title)

from titles

where type = "poetry"

-------------

0

(1 row affected)

select avg(advance)

from titles

where type = "poetry"

-------------

NULL

(1 row affected)

Organización de resultados de consultas en grupos: la cláusula group by

La cláusula group by se utiliza en las instrucciones select para dividir la salida de una tabla en grupos. Puede formar grupos según uno o varios nombres de columna, o según los resultados de las columnas calculadas utilizando tipos de datos numéricos en una expresión. Para group by , el número máximo de columnas o expresiones es 16.

Note: No es posible formar grupos por columnas con tipos de datos text o image .

La cláusula group by aparece casi siempre en instrucciones que también incluyen funciones agregadas, en cuyo caso el agregado genera un valor para cada grupo. A estos valores se les llama agregados vectoriales . No hay que olvidar que un agregado escalar es un solo valor generado por una función agregada sin una cláusula group by .

En este ejemplo de un agregado vectorial, la instrucción halla el promedio de anticipo y la suma de ventas anuales hasta la fecha para cada tipo de libro:

Page 41: 80575032 Libro de SQL y Tl SQL Excelente

Page 41 of 280

select type, avg(advance), sum(total_sales)

from titles

group by type

type

------------ --------- -------

UNDECIDED NULL NULL

business 6,281.25 30788

mod_cook 7,500.00 24278

popular_comp 7,500.00 12875

psychology 4,255.00 9939

trad_cook 6,333.33 19566

(6 rows affected)

Los valores sumarios (agregados vectoriales) generados por las instrucciones select con agregados y una cláusula group by aparecen como columnas en cada fila de los resultados. Por el contrario, los valores sumarios (agregados escalares) generados por las instrucciones select con agregados y sin cláusulas group by también aparecen como columnas, pero sólo en una fila. Por ejemplo:

select avg(advance), sum(total_sales)

from titles

--------- -------

5,962.50 97446

(1 row affected)

Mientras sea posible utilizar group by sin agregados, dicha construcción tiene una funcionalidad muy limitada y algunas veces genera resultados confusos. El siguiente ejemplo intenta agrupar los resultados por tipo de título:

select type, advance

from titles

group by type

type advance

------------ ---------

business 5,000.00

business 5,000.00

business 10,125.00

business 5,000.00

mod_cook 0.00

mod_cook 15,000.00

UNDECIDED NULL

popular_comp 7,000.00

popular_comp 8,000.00

popular_comp NULL

psychology 7,000.00

psychology 2,275.00

psychology 6,000.00

psychology 2,000.00

psychology 4,000.00

trad_cook 7,000.00

trad_cook 4,000.00

trad_cook 8,000.00

(18 rows affected)

Sin un agregado para la columna advance , la consulta devuelve valores para cada fila de la tabla.

Sintaxis de group by

La sintaxis completa de la instrucción select se repite aquí para ilustrar la cláusula group by en contexto:

select [all | distinct] select_list

[into [[ database .] owner .] table_name ]

[from [[ database .] owner .]{ view_name | table_name

[(index index_name [ prefetch size ][lru|mru])]}

[holdlock | noholdlock] [shared]

[,[[ database .] owner .]{ view_name | table_name

[(index index_name [ prefetch size ][lru|mru])]}

[holdlock | noholdlock] [shared]]... ]

Page 42: 80575032 Libro de SQL y Tl SQL Excelente

Page 42 of 280

[where search_conditions ]

[group by [all] aggregate_free_expression

[, aggregate_free_expression ]... ]

[having search_conditions ]

[order by

{[[[ database .] owner .]{ table_name .| view_name .}]

column_name | select_list_number | expression }

[asc | desc]

[,{[[[ database .] owner .]{ table_name | view_name .}]

column_name | select_list_number | expression }

[asc | desc]]...]

[compute row_aggregate ( column_name )

[, row_aggregate ( column_name )]...

[by column_name [, column_name ]...]]

[for {read only | update [of column_name_list ]}]

[at isolation {read uncommitted | read committed |

serializable}]

[for browse]

Recuerde que el orden de las cláusulas en la instrucción select es importante. Se puede omitir cualquiera de las cláusulas opcionales, pero cuando las utilice, deben aparecer en el orden mostrado aquí.

Las normas SQL para group by son más restrictivas de lo que parece en la sintaxis anterior. La norma exige que:

Las columnas de la lista de selección también deben aparecer en la expresión group by o ser argumentos de funciones agregadas.

La expresión group by sólo puede contener los nombres de columna especificados en la lista de selección, pero no los usados únicamente como argumentos de agregados vectoriales.

El resultado de una cláusula group by estándar con funciones agregadas vectoriales es una fila y un valor sumario por grupo. Algunas extensiones Transact-SQL (descritas en las secciones siguientes) reducen estas restricciones, pero a costa de resultados más complejos. Si prefiere no usar las extensiones, puede definir la opción fipsflagger según se indica a continuación:

set fipsflagger on

Esta opción muestra un mensaje de advertencia cada vez que se usan las extensiones Transact-SQL. Para obtener más información sobre la opción fipsflagger y el comando set , consulte el Manual de Referencia de SQL Server.

Se puede incluir más de una columna en la cláusula group by a fin de anidar grupos, es decir, se puede agrupar una tabla mediante cualquier combinación de columnas. Por ejemplo, a continuación se muestra una instrucción que halla el precio promedio y la suma de las ventas anuales hasta la fecha, agrupados primero por número de ID del editor y luego por tipo:

select pub_id, type, avg(price), sum(total_sales) from titles group by pub_id, type pub_id type ------ ------------ ------ ------- 0736 business 2.99 18722 0736 psychology 11.48 9564 0877 UNDECIDED NULL NULL 0877 mod_cook 11.49 24278 0877 psychology 21.59 375 0877 trad_cook 15.96 19566 1389 business 17.31 12066 1389 popular_comp 21.48 12875 (8 rows affected)

Page 43: 80575032 Libro de SQL y Tl SQL Excelente

Page 43 of 280

Con group by , es posible anidar muchos grupos dentro de otros grupos, hasta un máximo de 16 columnas o expresiones especificadas.

Referencia a otras columnas en consultas mediante group by

Con las extensiones de las normas SQL, Transact-SQL no impone ninguna restricción sobre lo que puede incluirse u omitirse en la lista de selección de una instrucción select que incluya la cláusula group by :

1. Las columnas de la lista de selección no se limitan a las columnas de agrupación ni a columnas usadas con los agregados vectoriales.

2. Las columnas especificadas por group by no se limitan a las columnas no agregadas de la lista de selección.

El agregado vectorial requiere que haya una o más columnas en la cláusula group by . Las normas SQL requieren que las columnas no agregadas de la lista de selección coincidan con las columnas de group by . Sin embargo, la primera extensión descrita con anterioridad permite especificar columnas "extendidas" adicionales en la lista de selección de la consulta.

Por ejemplo, la inclusión de la columna extendida title_id en la lista de selección no se permitiría en muchas versiones de SQL, pero es perfectamente válida en Transact-SQL:

select type, title_id, avg(price), avg(advance) from titles group by type type title_id ------------ -------- ----- --------- business BU1032 13.73 6,281.25 business BU1111 13.73 6,281.25 business BU2075 13.73 6,281.25 business BU7832 13.73 6,281.25 mod_cook MC2222 11.49 7,500.00 mod_cook MC3021 11.49 7,500.00 UNDECIDED MC3026 NULL NULL popular_comp PC1035 21.48 7,500.00 popular_comp PC8888 21.48 7,500.00 popular_comp PC9999 21.48 7,500.00 psychology PS1372 13.50 4,255.00 psychology PS2091 13.50 4,255.00 psychology PS2106 13.50 4,255.00 psychology PS3333 13.50 4,255.00 psychology PS7777 13.50 4,255.00 trad_cook TC3218 15.96 6,333.33 trad_cook TC4203 15.96 6,333.33 trad_cook TC7777 15.96 6,333.33 (18 rows affected)

El ejemplo anterior todavía agrega las columnas price y advance , según la columna type , pero sus resultados también muestran el número de ID del título ( title_id ) de los libros incluidos en cada grupo.

La segunda extensión descrita anteriormente permite agrupar columnas que no están especificadas como tal en la lista de selección de la consulta. Estas columnas no aparecen en los resultados, pero los agregados vectoriales calculan sus valores sumarios. Por ejemplo:

select state, count(au_id)

from authors

group by state, city

state

----- --------

AU 1

CA 2

CA 1

CA 5

CA 2

CA 1

CA 1

CA 1

CA 1

Page 44: 80575032 Libro de SQL y Tl SQL Excelente

Page 44 of 280

IN 1

KS 1

MD 1

MI 1

OR 1

TN 1

UT 2

(16 rows affected)

Este ejemplo agrupa los resultados de los agregados vectoriales por state y city , aunque no muestre qué ciudad pertenece a cada grupo.

Como puede ver, los resultados de las consultas usadas con estas extensiones son más complejos. Para realizar estas consultas, es necesario estar familiarizado con la forma en que SQL Server trata estas extensiones para poder entender los resultados. Por ejemplo, puede suponerse que la siguiente consulta generará resultados similares a los de la consulta anterior, ya que parece que sólo el agregado vectorial registra el número de cada ciudad correspondiente a cada fila:

select state, count(au_id)

from authors

group by city

Sin embargo, sus resultados son muy distintos (y engañosos). Al no usar group by con ambas columnas ( state y city ), la consulta lleva la cuenta de cada ciudad, pero muestra la cuenta de cada fila de esa ciudad en authors en lugar de agruparla en una única fila de resultados por ciudad.

Cuando se usan las extensiones Transact-SQL en consultas complejas que incluyen la cláusula where o combinaciones, los resultados pueden ser todavía más difíciles de entender. Para evitar resultados confusos o engañosos con group by , no utilice la extensión con ligereza. Emplee la opción fipsflagger (consulte la ) para identificar las consultas que usan estas extensiones.

Para obtener más información sobre estas extensiones Transact-SQL de group by y la forma en que funcionan, consulte el Manual de Referencia de SQL Server .

Expresiones y group by

Otra extensión Transact-SQL para SQL permite agrupar por expresiones que no incluyan funciones agregadas. Con SQL estándar sólo es posible realizar agrupaciones por nombres de columna. Por ejemplo:

select avg(total_sales), total_sales * price

from titles

group by total_sales * price

--------- -----------------

111 777.00

375 7,856.25

375 8,096.25

2045 22,392.75

3336 26,654.64

2032 40,619.68

3876 46,318.20

18722 55,978.78

4095 61,384.05

22246 66,515.54

4072 81,399.28

4095 81,859.05

4095 81,900.00

15096 180,397.20

8780 201,501.00

(15 rows affected)

No es posible agrupar ( group by) por encabezados de columna ni alias , aunque pueden utilizarse alias en la lista de selección. Esta instrucción genera un mensaje de error:

select Category = type, title_id, avg(price), avg(advance)

from titles

group by Category /* Uso incorrecto del encabezado

** de columna */

Page 45: 80575032 Libro de SQL y Tl SQL Excelente

Page 45 of 280

Use group by type para corregir esta consulta.

Anidación de agregados mediante group by

Otro tipo de anidación, la anidación de un agregado vectorial dentro de otro escalar, es una extensión Transact-SQL. Por ejemplo, para hallar el precio promedio de todos los tipos de libros, la consulta es:

select avg(price)

from titles

group by type

---------------

NULL

13.73

11.49

21.48

13.50

15.96

(6 rows affected)

El precio promedio máximo de un grupo de libros, agrupado por tipo, se puede establecer en una sola consulta anidando el precio promedio dentro la función max :

select max(avg(price))

from titles

group by type

-------------

21.48

(1 row affected)

Por definición, la cláusula group by se aplica al agregado más interno, que, en este caso, es avg .

Valores nulos y group by

Si la columna de agrupación contiene un valor nulo, la fila pertinente se convierte en un grupo en los resultados. Si la columna de agrupación contiene más de un valor nulo, los valores nulos se ponen en un solo grupo.

La columna advance de la tabla titles contiene algunos valores nulos. A continuación se muestra un ejemplo que utiliza group by y la columna advance :

select advance, avg(price * 2)

from titles

group by advance

advance

------------------ -----------------

NULL NULL

0.00 39.98

2,000.00 39.98

2,275.00 21.90

4,000.00 19.94

5,000.00 34.62

6,000.00 14.00

7,000.00 43.66

8,000.00 34.99

10,125.00 5.98

15,000.00 5.98

(11 rows affected)

Si utiliza la función agregada count( column_name ) , la agrupación por una columna que contenga valores nulos devolverá un conteo de cero para la fila de agrupación, ya que count( column_name ) no cuenta valores nulos. En la mayoría de los casos, conviene utilizar count(*) . Este ejemplo aplica la agrupación y el conteo a la columna price de la tabla titles , que contiene valores nulos, y muestra count(*) a título de la comparación:

Page 46: 80575032 Libro de SQL y Tl SQL Excelente

Page 46 of 280

select price, count(price), count(*)

from titles

group by price

price

------------- ----- -----

NULL 0 2

2.99 2 2

7.00 1 1

7.99 1 1

10.95 1 1

11.95 2 2

14.99 1 1

19.99 4 4

20.00 1 1

20.95 1 1

21.59 1 1

22.95 1 1

(12 rows affected)

Cláusula where y group by

En una instrucción con group by se puede utilizar una cláusula where . Las filas que no cumplen las condiciones de la cláusula where se eliminan antes de que se realice la agrupación. Por ejemplo:

select type, avg(price)

from titles

where advance > 5000

group by type

type

------------- --------

business 2.99

mod_cook 2.99

popular_comp 21.48

psychology 14.30

trad_cook 17.97

(5 rows affected)

Sólo las filas con anticipos superiores a $5000 se incluyen en los grupos usados para generar resultados de consultas. Los valores son muy diferentes cuando la consulta se ejecuta sin la cláusula where .

Sin embargo, la forma en que SQL Server manipula las columnas adicionales de la lista de selección y la cláusula where , puede parecer contradictoria. Por ejemplo:

select type, advance, avg(price)

from titles

where advance > 5000

group by type

type advance

------------- --------- --------

business 5,000.00 2.99

business 5,000.00 2.99

business 10,125.00 2.99

business 5,000.00 2.99

mod_cook 0.00 2.99

mod_cook 15,000.00 2.99

popular_comp 7,000.00 21.48

popular_comp 8,000.00 21.48

popular_comp NULL 21.48

psychology 7,000.00 14.30

psychology 2,275.00 14.30

psychology 6,000.00 14.30

psychology 2,000.00 14.30

psychology 4,000.00 14.30

trad_cook 7,000.00 17.97

trad_cook 4,000.00 17.97

trad_cook 8,000.00 17.97

(17 rows affected)

Page 47: 80575032 Libro de SQL y Tl SQL Excelente

Page 47 of 280

Al observar los resultados de la columna (extendida) advance , parece que la consulta está ignorando la cláusula where . SQL Server calcula el agregado vectorial a partir de las filas que satisfacen la cláusula where , pero también muestra todas las filas de las columnas extendidas incluidas en la lista de selección. Para restringir el número de filas incluidas en los resultados, es necesario usar una cláusula having (descrita más adelante en este capítulo).

Para obtener información sobre la forma en que SQL Server manipula la cláusula where y group by , consulte el Manual de Referencia de SQL Server .

group by y all

La palabra clave all en la cláusula group by es una mejora de Transact-SQL para SQL. Sólo es significativa si la instrucción select en la que se utiliza también incluye una cláusula where .

Si utiliza all , los resultados de la consulta incluirán todos los grupos generados por la cláusula group by , aunque algunos de los grupos no tengan filas que cumplan con las condiciones de búsqueda. Sin all , una instrucción select que incluya group by no mostrará los grupos que carecen de filas calificadas.

A continuación se muestra un ejemplo:

select type, avg(advance)

from titles

where advance > 1000 and advance < 10000

group by type

type

------------ ------------------------

business 5,000.00

popular_comp 7,500.00

psychology 4,255.00

trad_cook 6,333.33

(4 rows affected)

select type, avg(advance)

from titles

where advance > 1000 and advance < 10000

group by all type

type

------------ ------------------------

UNDECIDED NULL

business 5,000.00

mod_cook NULL

popular_comp 7,500.00

psychology 4,255.00

trad_cook 6,333.33

(6 rows affected)

La primera instrucción sólo genera grupos para libros con anticipos superiores a $1000, pero inferiores a $10000. Dado que no hay ningún libro de cocina con un anticipo dentro de dicho margen, los resultados no muestran ningún grupo para el tipo mod_cook .

La segunda instrucción genera grupos para todos los tipos, incluidos cocina moderna y "UNDECIDED", aunque el grupo de cocina moderna no incluya ninguna fila que cumpla con la calificación especificada en la cláusula where . SQL Server devuelve un valor NULL para dichas filas.

La columna que contiene el valor agregado (el promedio de anticipos) es para los grupos que carecen de filas calificadas.

Uso de agregados sin group by

Por definición, los agregados escalares se aplican a todas las filas de una tabla, generando un solo valor para toda la tabla, para cada función. La extensión Transact-SQL, que permite incluir columnas extendidas con agregados vectoriales, también lo permite con agregados escalares. Por ejemplo:

select pub_id, count(pub_id)

from publishers

pub_id

---------- ---------

Page 48: 80575032 Libro de SQL y Tl SQL Excelente

Page 48 of 280

0736 3

0877 3

1389 3

(3 rows affected)

SQL Server trata publishers como un grupo único y el agregado escalar se aplica a la tabla (grupo único). Los resultados muestran todas las filas de la tabla correspondientes a las columnas incluidas en la lista de selección en adición al agregado escalar.

La cláusula where actúa de la misma forma tanto para los agregados escalares como para los vectoriales. where restringe las columnas incluidas en los valores sumarios agregados, pero no tiene efecto sobre las filas que aparecen en los resultados para cada columna extendida especificada en la lista de selección. Por ejemplo:

select pub_id, count(pub_id)

from publishers

where pub_id < "1000"

pub_id

-------------- -----------

0736 2

0877 2

1389 2

(3 rows affected)

Al igual que las demás extensiones Transact-SQL de group by , esta extensión de los agregados escalares proporciona resultados que pueden ser difíciles de entender, sobre todo si se trata de consultas a tablas grandes o con combinaciones de varias tablas.

Selección de grupos de datos: la cláusula having

La cláusula having establece condiciones para la cláusula group by similares al modo en que where establece condiciones para la cláusula select .

Las condiciones de búsqueda de having son idénticas a las de where , con una excepción: las condiciones de búsqueda de where no pueden incluir agregados, mientras que las de having lo hacen a menudo. Las cláusulas having pueden hacer referencia a cualquiera de los elementos que aparecen en la lista de selección. Existe un límite de 128 condiciones que pueden incluirse en una cláusula having .

Esta instrucción es un ejemplo de una cláusula having con una función agregada. Agrupa las filas de la tabla titles por tipo, pero elimina los grupos que sólo incluyen un libro:

select type

from titles

group by type

having count(*) > 1

type

----------------

business

mod_cook

popular_comp

psychology

trad_cook

(5 rows affected)

A continuación se muestra un ejemplo de una cláusula having sin agregados. Agrupa la tabla titles por tipo y elimina los tipos que no empiezan por la letra "p":

select type

from titles

group by type

having type like 'p%'

type

------------

popular_comp

psychology

Page 49: 80575032 Libro de SQL y Tl SQL Excelente

Page 49 of 280

(2 rows affected)

Cuando se incluyen varias condiciones en la cláusula having , éstas se combinan con and , or o not . Por ejemplo, para agrupar la tabla titles por editor e incluir sólo aquellos editores con números de identificación mayores que 0800, que han pagado más de $15000 en anticipos totales y cuyos libros dan un promedio inferior a $18 en precio, la instrucción es:

select pub_id, sum(advance), avg(price)

from titles

group by pub_id

having sum(advance) > 15000

and avg(price) < 18

and pub_id > "0800"

pub_id

------ ---------------- ----------------

0877 41,000.00 15.41

(1 row affected)

Interactuación entre las cláusulas having , group by y where

Cuando se incluyen las cláusulas having , group by y where en una consulta, la secuencia en que cada cláusula afecta a las filas de la tabla es importante en la determinación de los resultados finales:

La cláusula where excluye las filas que no cumplen con sus condiciones de búsqueda.

La cláusula group by incluye las filas restantes en un grupo para cada valor único de la expresión group by .

Las funciones agregadas especificadas en la lista de selección calculan valores sumarios para cada grupo.

La cláusula having excluye de los resultados finales las filas que no cumplen con sus condiciones de búsqueda.

La siguiente consulta ilustra el uso de las cláusulas where , group by y having en una instrucción select :

select stor_id, title_id, sum(qty)

from salesdetail

where title_id like "PS%"

group by stor_id, title_id

having sum(qty) > 200

stor_id title_id

------- -------- -----------

5023 PS1372 375

5023 PS2091 1845

5023 PS3333 3437

5023 PS7777 2206

6380 PS7777 500

7067 PS3333 345

7067 PS7777 250

(7 rows affected)

La cláusula where incluye sólo las filas cuya title_id comience por "PS" (libros de psicología), antes de que group by reúna las filas con stor_id y title_id comunes. El agregado sum calcula el número total de libros vendidos para cada grupo y, a continuación, la cláusula having excluye de los resultados finales los grupo cuyos totales no sobrepasan los 200 libros.

Todos los ejemplos anteriores de having satisfacen las normas SQL, que especifican que las columnas de una expresión having deben tener un solo valor y encontrarse en la lista de selección o la cláusula group by . Sin embargo, las extensiones Transact-SQL para having permiten columnas o expresiones que no están en la lista de selección ni en la cláusula group by .

El siguiente ejemplo utiliza esta extensión. Calcula el precio promedio para cada tipo de título, pero excluye los tipos cuyas ventas totales no son superiores a 10000, aunque la función sum no aparezca en los resultados.

select type, avg(price)

from titles

group by type

having sum(total_sales) > 10000

type

------------ ----------

business 13.73

Page 50: 80575032 Libro de SQL y Tl SQL Excelente

Page 50 of 280

mod_cook 11.49

popular_comp 21.48

trad_cook 15.96

(4 rows affected)

La extensión actúa como si la columna o expresión formara parte de la lista de selección, pero no de los resultados mostrados. Si se incluye una columna no agregada con having , pero la columna no forma parte de la lista de selección ni de la cláusula group by , la consulta genera resultados similares a la extensión de columna "extendida" descrita anteriormente en este capítulo. Por ejemplo:

select type, avg(price)

from titles

group by type

having total_sales > 4000

type

------------ ----------

business 13.73

business 13.73

business 13.73

mod_cook 11.49

popular_comp 21.48

popular_comp 21.48

psychology 13.50

trad_cook 15.96

trad_cook 15.96

(9 rows affected)

A diferencia de la columna extendida, la columna total_sales no aparece en los resultados finales, aunque el número de filas mostradas para cada tipo depende de las ventas totales ( total_sales ) de cada título. La consulta indica que 3 títulos de business , 1 de mod_cook , 2 de popular_comp , 1 de psychology y 2 de trad_cook han tenido ventas totales superiores a 4000.

Como se indicó anteriormente, la forma en que SQL Server manipula las columnas extendidas puede hacer creer que la consulta está ignorando la cláusula where en los resultados finales. Para que las condiciones de where tengan efecto sobre los resultados de la columna extendida, es necesario repetir las condiciones en la cláusula having . Por ejemplo:

select type, advance, avg(price)

from titles

where advance > 5000

group by type

having advance > 5000

type advance

------------- --------- --------

business 10,125.00 2.99

mod_cook 15,000.00 2.99

popular_comp 7,000.00 21.48

popular_comp 8,000.00 21.48

psychology 7,000.00 14.30

psychology 6,000.00 14.30

trad_cook 7,000.00 17.97

trad_cook 8,000.00 17.97

(8 rows affected)

Uso de having sin group by

Una consulta con una cláusula having también debe tener una cláusula group by . Si ésta se omite, todas las filas no excluidas por la cláusula where se consideran un solo grupo.

Dado que no hay ninguna agrupación entre las cláusulas where y having , no pueden actuar independientemente una de la otra. having actúa como where porque afecta a las filas de un solo grupo en lugar de varios grupos, salvo que la cláusula having todavía puede utilizar agregados.

El siguiente ejemplo utiliza la cláusula having para excluir de los resultados las filas de la tabla titles (grupo único) cuyos precios no sobrepasen el precio promedio de todos los títulos, después de que la cláusula where excluya los títulos con anticipo superior a $4000 del cálculo del precio promedio:

Page 51: 80575032 Libro de SQL y Tl SQL Excelente

Page 51 of 280

select title_id, advance, price

from titles

where advance < 4000

having price > avg(price)

title_id advance price

------------- --------- --------

BU1032 5,000.00 19.99

BU7832 5,000.00 19.99

MC2222 0.00 19.99

PC1035 7,000.00 22.95

PC8888 8,000.00 20.00

PS1372 7,000.00 21.59

PS3333 2,000.00 19.99

TC3218 7,000.00 20.95

(8 rows affected)

También puede usar la cláusula having con la extensión Transact-SQL que permite omitir la cláusula group by de una consulta que incluye un agregado en su lista de selección. Estas funciones agregadas escalares calculan los valores para la tabla como un grupo único, no para grupos de la tabla.

En este ejemplo, la omisión de la cláusula group by hace que la función agregada calcule un valor para toda la tabla. La cláusula having excluye filas del grupo de resultados, filas de la tabla única.

select pub_id, count(pub_id)

from publishers

having pub_id < "1000"

pub_id

------ ----------------

0736 3

0877 3

(2 rows affected)

Para obtener más información sobre las consultas que utilizan having pero omiten group by , consulte el Manual de Referencia de SQL Server.

Ordenación de resultados de consultas: la cláusula order by

La cláusula order by permite la ordenación de resultados de consultas por una o más columnas. El número máximo de columnas es 16. Cada ordenación puede ser ascendente ( asc ) o descendente ( desc ). Si no se especifica ninguna, se utiliza la ascendente. La siguiente consulta devuelve resultados ordenados por pub_id :

select pub_id, type, title_id

from titles

order by pub_id

pub_id type title_id

------ ------------ --------

0736 business BU2075

0736 psychology PS2091

0736 psychology PS2106

0736 psychology PS3333

0736 psychology PS7777

0877 UNDECIDED MC3026

0877 mod_cook MC2222

0877 mod_cook MC3021

0877 psychology PS1372

0877 trad_cook TC3218

0877 trad_cook TC4203

0877 trad_cook TC7777

1389 business BU1032

1389 business BU1111

1389 business BU7832

1389 popular_comp PC1035

1389 popular_comp PC8888

1389 popular_comp PC9999

(18 rows affected)

Page 52: 80575032 Libro de SQL y Tl SQL Excelente

Page 52 of 280

Si se indica más de una columna en la cláusula order by , las ordenaciones quedan anidadas. La siguiente instrucción ordena las filas de la tabla titles primero por editor en orden descendente, después por tipo (ascendente) dentro de cada editor y, finalmente, por número de título (también ascendente, puesto que no se ha especificado desc). Los valores nulos se ordenan en primer lugar dentro de cualquier grupo.

select pub_id, type, title_id

from titles

order by pub_id desc, type, title_id

pub_id type title_id

------ ---------- --------

1389 business BU1032

1389 business BU1111

1389 business BU7832

1389 popular_comp PC1035

1389 popular_comp PC8888

1389 popular_comp PC9999

0877 UNDECIDED MC3026

0877 mod_cook MC2222

0877 mod_cook MC3021

0877 psychology PS1372

0877 trad_cook TC3218

0877 trad_cook TC4203

0877 trad_cook TC7777

0736 business BU2075

0736 psychology PS2091

0736 psychology PS2106

0736 psychology PS3333

0736 psychology PS7777

(18 rows affected)

El número de posición de una columna en una lista de selección puede utilizarse en lugar del nombre de la columna. Los nombres de columnas y los números de lista pueden mezclarse. Las siguientes instrucciones generan los mismos resultados que la anterior.

select pub_id, type, title_id

from titles

order by 1 desc, 2, 3

select pub_id, type, title_id

from titles

order by 1 desc, type, 3

La mayoría de las versiones de SQL requieren que los elementos de order by aparezcan en la lista de selección, pero Transact-SQL no tiene esta restricción. Los resultados de la consulta anterior podrían ordenarse por title , aunque esta columna no aparezca en la lista de selección.

Note: No es posible usar order by con columnas text o image .

Las subconsultas, agregados, variables y expresiones constantes no se permiten en la lista order by .

Los efectos de una cláusula order by en datos con mayúsculas y minúsculas mezcladas dependen del criterio de ordenación instalado en SQL Server. Las opciones básicas son binario, orden de diccionario y sin distinción de mayúsculas y minúsculas. El procedimiento del sistema sp_helpsort muestra el criterio de ordenación del servidor. Consulte order by en el Manual de Referencia de SQL Server para obtener información completa sobre los criterios de ordenación.

order by y group by

Cuando desee ordenar los resultados de una cláusula group by de un modo concreto, puede utilizar una cláusula order by .

Sitúe la cláusula order by después de la cláusula group by . Por ejemplo, para hallar el precio promedio de cada tipo de libro y ordenar los resultados por precio promedio, la instrucción es:

select type, avg(price)

from titles

group by type

order by avg(price)

Page 53: 80575032 Libro de SQL y Tl SQL Excelente

Page 53 of 280

type

---------- ------------

UNDECIDED NULL

mod_cook 11.49

psychology 13.50

business 13.73

trad_cook 15.96

popular_comp 21.48

(6 rows affected)

Cómo resumir grupos de datos: la cláusula compute

La cláusula compute es una extensión Transact-SQL de SQL. Utilícela con agregados de fila para generar informes que totalicen valores siempre que cambie el valor de una columna especificada. Tales informes, normalmente creados por un generador de informes, se llaman informes de cortes de control, ya que los valores sumarios aparecen en el informe, bajo el control de las agrupaciones ("cortes") especificadas en la cláusula compute .

Estos valores sumarios aparecen como filas adicionales en los resultados de consultas, a diferencia de los resultados agregados de una cláusula group by , que aparecen como columnas nuevas.

Una cláusula compute permite ver las filas detalladas y resumidas con una instrucción select . Es posible calcular valores sumarios para subgrupos y calcular más de un agregado de fila para el mismo grupo.

Esta es la sintaxis general de compute :

compute row_aggregate ( column_name )

[, row_aggregate ( column_name )]...

[by column_name [, column_name ]...]

Los agregados de fila que pueden utilizarse con compute son sum , avg , min , max y count . sum y avg sólo se emplean con columnas numéricas. A diferencia de la cláusula order by , no es posible usar el número de posición de una columna de la lista de selección en lugar del nombre de la columna.

Note: No se pueden utilizar columnas text o image en una cláusula compute .

A continuación se muestran dos consultas y sus resultados. La primera utiliza group by y agregados. La segunda utiliza compute y agregados de fila. Observe las diferencias:

select type, sum(price), sum(advance)

from titles

group by type

type

------------ ------- ----------

UNDECIDED NULL NULL

business 54.92 25,125.00

mod_cook 22.98 15,000.00

popular_comp 42.95 15,000.00

psychology 67.52 21,275.00

trad_cook 47.89 19,000.00

(6 rows affected)

select type, price, advance

from titles

order by type

compute sum(price), sum(advance) by type

type price advance

------------- ------------ ----------

UNDECIDED NULL NULL

sum sum

------------ ----------

NULL NULL

type price advance

------------- ------------ ----------

business 2.99 10,125.00

business 11.95 5,000.00

business 19.99 5,000.00

business 19.99 5,000.00

Page 54: 80575032 Libro de SQL y Tl SQL Excelente

Page 54 of 280

sum sum

------------ ---------

54.92 25,125.00

type price advance

------------- ------------ ---------

mod_cook 2.99 15,000.00

mod_cook 19.99 0.00

sum sum

------------ ---------

22.98 15,000.00

type price advance

------------- ------------ ---------

popular_comp NULL NULL

popular_comp 20.00 8,000.00

popular_comp 22.95 7,000.00

sum sum

------------ ---------

42.95 15,000.00

type price advance

------------- ------------ ---------

psychology 7.00 6,000.00

psychology 7.99 4,000.00

psychology 10.95 2,275.00

psychology 19.99 2,000.00

psychology 21.59 7,000.00

sum sum

------------ ---------

67.52 21,275.00

type price advance

------------- ------------ ---------

trad_cook 11.95 4,000.00

trad_cook 14.99 8,000.00

trad_cook 20.95 7,000.00

sum sum

------------ ---------

47.89 19,000.00

(24 rows affected)

Los valores sumarios se tratan como filas nuevas, razón por la cual el mensaje de SQL Server dice "24 rows affected".

Agregados de fila y compute

Los agregados de fila usados con compute se enumeran en la siguiente tabla:

Tabla 3-2: Agregados de fila usados con instrucciones compute

Agregado de fila Resultado

sum Total de los valores de la expresión

avg Promedio de los valores de la expresión

max Valor máximo de la expresión

min Valor mínimo de la expresión

count Número de filas seleccionadas

Estos agregados de fila son los mismos agregados que pueden utilizarse con group by , excepto que no hay ninguna función agregada de fila que equivalga a count(*) . Para obtener la información sumaria generada por group by y count(*) , emplee una cláusula compute sin by .

Reglas para las cláusulas compute

La palabra clave distinct no está permitida con los agregados de fila.

Las columnas de la cláusula compute deben aparecer en la lista de selección de la instrucción.

No es posible utilizar select into en la misma instrucción que una cláusula compute porque las instrucciones que incluyen compute no generan filas normales.

Si utiliza compute con la palabra clave by , también deberá usar una cláusula order by . Las columnas mostradas después de by deben ser idénticas a, o un subconjunto de, las que aparecen después de order by , y además estar

Page 55: 80575032 Libro de SQL y Tl SQL Excelente

Page 55 of 280

en el mismo orden de izquierda a derecha, empezar con la misma expresión y no omitir ninguna expresión. Por ejemplo, suponga que ésta es la cláusula order by :

order by a, b , c

La cláusula compute puede ser cualquiera o todas las que aparecen a continuación:

compute row_aggregate ( column_name ) by a, b, c

compute row_aggregate ( column_name ) by a, b

compute row_aggregate ( column_name ) by a

La cláusula compute no puede ser ninguna de las siguientes:

compute row_aggregate ( column_name ) by b, c

compute row_aggregate ( column_name ) by a, c

compute row_aggregate ( column_name ) by c

Debe utilizar un nombre de columna o una expresión en la cláusula order by ; no es posible ordenar por encabezado de columna.

La palabra clave compute puede utilizarse sin by para generar totales generales, conteos generales, etc.. order by es opcional si la palabra clave compute se usa sin by . compute sin by se explica más adelante.

Especificación de más de una columna después de compute

La inclusión de más de una columna después de la palabra clave by divide un grupo en subgrupos y aplica el agregado de fila especificado en cada nivel de agrupación. Por ejemplo, a continuación se muestra una consulta que halla la suma de los precios de los libros de psicología de cada editor:

select type, pub_id, price

from titles

where type = "psychology"

order by type, pub_id, price

compute sum(price) by type, pub_id

type pub_id price

----------- ------- -------------

psychology 0736 7.00

psychology 0736 7.99

psychology 0736 10.95

psychology 0736 19.99

sum

------------

45.93

type pub_id price

----------- ------- -------------

psychology 0877 21.59

sum

------------

21.59

(7 rows affected)

Uso de más de una cláusula compute

Se pueden utilizar agregados diferentes en la misma instrucción, incluyendo más de una cláusula compute . A continuación se muestra una consulta similar a la anterior que halla la suma de los precios de todos los libros de psicología, así como la suma de los precios de los libros de psicología por editor:

select type, pub_id, price

from titles

where type = "psychology"

order by type, pub_id, price

compute sum(price) by type, pub_id

compute sum(price) by type

type pub_id price

----------- ------- --------------

Page 56: 80575032 Libro de SQL y Tl SQL Excelente

Page 56 of 280

psychology 0736 7.00

psychology 0736 7.99

psychology 0736 10.95

psychology 0736 19.99

sum

-------------

45.93

type pub_id price

---------- ------- --------------

psychology 0877 21.59

sum

-------------

21.59

sum

-------------

67.52

(8 rows affected)

Aplicación de un agregado a más de una columna

Una cláusula compute puede aplicar el mismo agregado a varias columnas. Esta consulta halla la suma de los precios y los anticipos para cada tipo de libro de cocina:

select type, price, advance

from titles

where type like "%cook"

order by type

compute sum(price), sum(advance) by type

type price advance

--------- ---------------- ---------------

mod_cook 2.99 15,000.00

mod_cook 19.99 0.00

sum sum

---------------- ---------------

22.98 15,000.00

type price advance

--------- ---------------- ---------------

trad_cook 11.95 4,000.00

trad_cook 14.99 8,000.00

trad_cook 20.95 7,000.00

sum sum

---------------- ---------------

47.89 19,000.00

(7 rows affected)

No hay que olvidar que las columnas a las que se aplican los agregados también deben estar en la lista de selección.

Uso de agregados diferentes en la misma cláusula compute

Se pueden utilizar agregados diferentes en la misma cláusula compute :

select type, pub_id, price

from titles

where type like "%cook"

order by type, pub_id

compute sum(price), max(pub_id) by type

type pub_id price

----------- ------- --------------

mod_cook 0877 2.99

mod_cook 0877 19.99

sum

--------------

22.98

max

-----

0877

type pub_id price

Page 57: 80575032 Libro de SQL y Tl SQL Excelente

Page 57 of 280

----------- ------- --------------

trad_cook 0877 11.95

trad_cook 0877 14.99

trad_cook 0877 20.95

sum

--------------

47.89

max

-----

0877

(7 rows affected)

Valores generales: compute sin by

La palabra clave compute puede utilizarse sin by para generar totales generales, conteos generales, etc..

Esta instrucción halla el total general de los precios y los anticipos de todos los tipos de libros por encima de $20:

select type, price, advance

from titles

where price > $20

compute sum(price), sum(advance)

type price advance

------------ ---------------- -------------

popular_comp 22.95 7,000.00

psychology 21.59 7,000.00

trad_cook 20.95 7,000.00

sum sum

=============== ==============

65.49 21,000.00

(4 rows affected)

Se puede utilizar una palabra clave compute con by y otra sin by en la misma consulta. La siguiente consulta halla la suma de los precios y los anticipos por tipo, y después calcula el total general de los precios y los anticipos para todos los tipos de libros.

select type, price, advance

from titles

where type like "%cook"

order by type

compute sum(price), sum(advance) by type

compute sum(price), sum(advance)

type price advance

----------- ----------------- ------------

mod_ cook 2.99 15,000.00

mod_cook 19.99 0.00

sum sum

----------------- ------------

22.98 15,000.00

type price advance

----------- ----------------- ------------

trad_cook 11.95 4,000.00

trad_cook 14.99 8,000.00

trad_cook 20.95 7,000.00

sum sum

----------------- ------------

47.89 19,000.00

sum sum

================= ============

70.87 34,000.00

(8 rows affected)

Combinación de consultas: el operador union

El operador union de Transact-SQL permite manipular los resultados de dos o más consultas mediante la combinación de los resultados de cada consulta en un solo conjunto de resultados. La sintaxis es la siguiente:

Page 58: 80575032 Libro de SQL y Tl SQL Excelente

Page 58 of 280

query1

[union [all] queryN ] ...

[order by clause]

[compute clause]

donde query1 es:

select select_list

[into clause ]

[from clause ]

[where clause ]

[group by clause ]

[having clause ]

y queryN es:

select select_list

[from clause ]

[where clause ]

[group by clause ]

[having clause ]

Por ejemplo, suponga que tiene las siguientes dos tablas con estos

datos:

La siguiente consulta crea una union entre las dos tablas:

select * from T1

union

select * from T2

El conjunto de resultados es el siguiente:

a b

char(4) int

abc 1

def 2

ghi 3

jkl 4

mno 5

Observe que, de forma predeterminada, el operador union quita filas duplicadas del conjunto de resultados. Si utiliza la opción all , se incluyen todas la filas en los resultados; las duplicadas no se quitan. Observe también que las columnas del conjunto de resultados tienen los mismos nombres que las columnas de T1 . En una instrucción Transact-SQL puede aparecer cualquier número de operadores union . Por ejemplo:

x union y union z

Page 59: 80575032 Libro de SQL y Tl SQL Excelente

Page 59 of 280

De forma predeterminada, SQL Server evalúa una instrucción con operadores union de izquierda a derecha. Es posible usar paréntesis para especificar el orden de la evaluación. Por ejemplo, las expresiones:

x union all ( y union z )

y:

( x union all y ) union z

no son equivalentes. En el primer ejemplo, los duplicados se eliminan de la unión entre y y z . Después, en la unión entre dicho conjunto y x , los duplicados no se eliminan. En el segundo ejemplo, los duplicados se incluyen en la unión entre x e y , pero después se eliminan en la unión posterior con z ; all no tienen ningún efecto en el resultado final de esta instrucción.

Directrices para consultas con union

A continuación se indican las directrices que deben tenerse en cuenta al usar instrucciones union :

Todas las listas de selección de la instrucción union deben tener el mismo número de expresiones (como los nombres de columnas, expresiones aritméticas y funciones agregadas). La siguiente instrucción no es válida porque la primera lista de selección tiene una longitud superior a la segunda:

select stor_id, date, ord_num from stores

union

select stor_id, ord_num from stores_east

Las columnas correspondientes de todas las tablas, o cualquier subconjunto de columnas utilizadas en las consultas individuales, deben ser del mismo tipo de datos, o una conversión de datos implícita debe ser posible entre los dos tipos de datos, o se debe facilitar una conversión explícita. Por ejemplo, no es posible establecer una unión ( union) entre una columna de tipo de datos char y otra de tipo de datos int , a menos que se facilite una conversión explícita. Sin embargo, es posible realizar una unión entre una columna de tipo de datos money y otra de tipo de datos int . Consulte union y "Funciones de conversión de tipos de datos" en el Manual de Referencia de SQL Server para obtener más información sobre la comparación de tipos de datos en una instrucción union .

Las columnas correspondientes en las consultas individuales de una instrucción union deben estar en el mismo orden, porque union compara las columnas una a una en el orden dado en las consultas individuales. Por ejemplo, suponga que tiene estas

tablas: La siguiente consulta:

select a, b from T3

union

select b, a from T4

genera este conjunto de resultados:

a b

1 abc

2 def

3 ghi

Page 60: 80575032 Libro de SQL y Tl SQL Excelente

Page 60 of 280

La siguiente consulta:

select a, b from T3

union

select a, b from T4

genera un mensaje de error, porque los tipos de datos de las columnas correspondientes no son compatibles. Cuando se combinan distintos tipos de datos (pero compatibles), como float e int , en una instrucción union , se convierten al tipo de datos que tenga la mayor precisión.

Los nombres de columnas de la tabla resultante de union se toman de la primera consulta individual de la instrucción union . Por lo tanto, si quiere definir un nuevo encabezado de columna para el conjunto de resultados, debe hacerlo en la primera consulta. Además, si quiere hacer referencia a una columna del conjunto de resultados utilizando un nombre nuevo, por ejemplo, en una instrucción order by , debe hacerlo de este modo en la primera instrucción select . La siguiente consulta es correcta:

select Cities = city from stores

union

select city from authors

order by Cities

Uso de union con otros comandos Transact-SQL

A continuación se muestran algunas directrices que deben tenerse en cuenta al usar las instrucciones union con otros comandos Transact-SQL:

La primera consulta de la instrucción union puede contener una cláusula into que cree una tabla para el conjunto de

resultados finales. Por ejemplo, la siguiente instrucción crea una tabla llamada results que contiene la unión de tablas publishers , stores y salesdetail:

select pub_id, pub_name, city into results from

publishers

union

select stor_id, stor_name, city from stores

union

select stor_id, title_id, ord_num from salesdetail

La cláusula into sólo puede utilizarse en la primera consulta; si aparece en cualquier otro lugar, se muestra un mensaje de error.

Las cláusulas order by y compute sólo se permiten al final de la instrucción union para definir el orden de los resultados finales o para calcular valores sumarios. No pueden utilizarse dentro de las consultas individuales que conforman la instrucción union .

Las cláusulas group by y having sólo pueden usarse dentro de consultas individuales; no pueden utilizarse para afectar al conjunto de resultados final.

El operador union también puede utilizarse dentro de una instrucción insert . Por ejemplo:

insert into tour

select city, state from stores

union

select city, state from authors

El operador union no puede utilizarse dentro de una instrucción create view .

La cláusula for browse no puede utilizarse en instrucciones que incluyan el operador union .

Chapter 4

Combinaciones: recuperación de datos de varias tablas

Este capítulo inicia la explicación sobre las operaciones de recuperación de datos de dos o más tablas. Estas tablas pueden estar en la misma base de datos o en bases de datos diferentes. Hasta ahora, la explicación se ha limitado a ejemplos de recuperación de datos de una sola tabla.

Page 61: 80575032 Libro de SQL y Tl SQL Excelente

Page 61 of 280

La operación multitabla explicada en este capítulo es la combinación. Las subconsultas, que también pueden incluir dos o más tablas, se tratan en el Capítulo 5, "Subconsultas: uso de consultas dentro de otras consultas". Muchas combinaciones pueden considerarse como subconsultas.

En este capítulo se trata lo siguiente:

Introducción general a las operaciones de combinación

Combinación de tablas en una consulta

Modo en que SQL Server procesa las combinaciones

Modo en que los valores afectan a las combinaciones

Modo de determinar las columnas que deben combinarse

Definición de combinación

Combinación de tablas en las consultas

Procesamiento de combinaciones

Efecto de los valores nulos sobre las combinaciones

Determinación de las columnas de tabla que deben combinarse

Definición de combinación

La combinación de dos o más tablas es un proceso que compara los datos de campos especificados y usa los resultados de la comparación para crear una tabla nueva a partir de las filas que cumplen los requisitos de calificación. Una instrucción de combinación especifica una columna de cada tabla, compara los valores de dichas columnas fila a fila y combina las filas calificadas en filas nuevas. La comparación es generalmente de igualdad (valores totalmente coincidentes), pero pueden especificarse otros tipos de combinaciones. Si una combinación ha de tener resultados significativos, las columnas que van a compararse deben tener valores similares, es decir, valores que puedan compararse porque sus tipos de datos son iguales o similares.

La operación de combinación tiene una jerga propia. La palabra "join" (combinación) se utiliza como verbo y como nombre, en referencia a la operación en sí, a la consulta o a sus resultados.

Existen diversas variedades de combinaciones: equicombinaciones, combinaciones naturales, combinaciones externas, etc..

La variedad más común es la combinación basada en la igualdad. A continuación se muestra un ejemplo de una combinación que busca los nombres de autores y editores ubicados en la misma ciudad:

select au_fname, au_lname, pub_name

from authors, publishers

where authors.city = publishers.city

au_fname au_lname pub_name

-------- -------- --------------------

Cheryl Carson Algodata Infosystems

Abraham Bennet Algodata Infosystems

(2 rows affected)

Dado que la consulta se realiza a partir de información contenida en dos tablas distintas, publishers y authors , se precisa una combinación para recuperar la información solicitada.

Las combinaciones y el modelo relacional

La operación de combinación es el sello del modelo relacional de administración de bases de datos. Más que ninguna otra función, la combinación distingue los sistemas de administración de bases de datos relacionales de otros tipos de DBMS.

En los sistemas de administración de bases de datos estructurados, a menudo conocidos como sistemas de redes y jerárquicos, las relaciones entre los valores de datos están predefinidas. Una vez que se ha configurado una base de datos, es difícil realizar consultas sobre relaciones no anticipadas entre los datos.

Por otro lado, en un sistema de administración de bases de datos relacionales, las relaciones entre los valores de datos quedan sin determinar en la definición de una base de datos y pasan a ser explícitas cuando los datos se manipulan, es decir, cuando la

Page 62: 80575032 Libro de SQL y Tl SQL Excelente

Page 62 of 280

base de datos se consulta , no cuando se crea. El usuario puede realizar cualquier pregunta que se le ocurra sobre los datos almacenados en la base de datos, independientemente de lo previsto al configurar la base de datos.

Según las reglas de buen diseño de bases de datos, llamadas reglas de normalización , cada tabla debe describir un tipo de entidad: una persona, lugar, evento o cosa. Este es el motivo por el que, al comparar información sobre dos o más tipos de entidades, se necesita la operación de combinación. Las relaciones entre los datos almacenados en tablas diferentes se descubren al combinar las tablas.

Un corolario de esta regla es que la operación de combinación proporciona una flexibilidad ilimitada al añadir nuevos tipos de datos a la base de datos. Siempre se puede crear una tabla nueva que contenga datos sobre un tipo de entidad distinto. Si la tabla nueva tiene un campo con valores similares a los de otro campo de una tabla o tablas existentes, puede vincularse a las tablas existentes mediante una combinación.

Combinación de tablas en las consultas

La instrucción de combinación, al igual que la instrucción de selección, comienza con la palabra clave select . Las columnas incluidas después de select son las columnas que deben insertarse en los resultados de la consulta, en el orden deseado. El ejemplo anterior especificaba las columnas que contenían los nombres de autores y editores.

Las columnas pub_name , au_lname y au_fname no tenían que calificarse mediante un nombre de tabla, dado que no hay ninguna ambigüedad sobre la tabla a la que pertenecen. Pero la columna city utilizada para la comparación de combinación sí tenía que calificarse, ya que las tablas publishers y authors también contienen columnas con ese nombre . Aunque en este ejemplo ninguna de las columnas city aparece en los resultados, SQL Server necesita el nombre de la tabla a fin de realizar la comparación.

Al igual que en la instrucción select , se puede especificar que todas las columnas de las tablas usadas en la consulta se incluyan en los resultados con la abreviatura " * ". Por ejemplo, para incluir todas las columnas de publishers y authors en la consulta de combinación anterior, la instrucción es:

select *

from authors, publishers

where authors.city = publishers.city

au_id au_lname au_fname phone address

city state postalcode contract pub_id pub_name

city state

----------- -------- -------- ------------ ---------------------

---------- ----- ---------- -------- ------ --------------------

---------- -----

238-95-7766 Carson Cheryl 415 548-7723 589 Darwin Ln.

Berkeley CA 94705 1 1389 Algodata Infosystems

Berkeley CA

409-56-7008 Bennet Abraham 415 658-9932 223 Bateman St

Berkeley CA 94705 1 1389 Algodata Infosystems

Berkeley CA

(2 rows affected)

La pantalla muestra un total de dos filas con trece columnas cada una. Debido a su longitud, cada fila ocupa varias líneas horizontales. Siempre que se utilice "*", las columnas de resultados aparecen en el orden de la instrucción create de la tabla.

La lista de selección y los resultados de una combinación no tienen que incluir necesariamente columnas de las dos tablas de la combinación. Por ejemplo, para encontrar los nombres de los autores que viven en la misma ciudad de uno de los editores, no es necesario que la consulta incluya columnas de la tabla publishers :

select au_lname, au_fname

from authors, publishers

where authors.city = publishers.city

No hay que olvidar, que al igual que en cualquier instrucción select , los nombres de columna de la lista de selección y los nombres de tabla de la cláusula from deben estar separados por comas.

La cláusula from

La cláusula from de una instrucción de combinación contiene todas las tablas o vistas implicadas en la combinación. Esta es la cláusula que realmente indica a SQL Server que se desea una combinación. Las tablas o vistas pueden especificarse en

Page 63: 80575032 Libro de SQL y Tl SQL Excelente

Page 63 of 280

cualquier orden. El orden de las tablas afecta a los resultados mostrados sólo cuando se utiliza select * para especificar la lista de selección.

Es posible especificar más de dos tablas o vistas en la cláusula from . Como máximo, una consulta puede hacer referencia a 16 tablas. Este máximo incluye:

Tablas (o vistas de tablas) especificadas en la cláusula from

Cada ejemplo de referencias múltiples a la misma tabla (autocombinaciones)

Tablas referenciadas en subconsultas

Tablas base referenciadas por las vistas especificadas en la cláusula from

Las combinaciones que implican el uso de más de dos tablas o vistas se explican más adelante en este capítulo en "Combinación de más de dos tablas".

Tal como se explicó en el Capítulo 2, "Consultas: selección de datos de una tabla", los nombres de tabla o vista pueden calificarse con los nombres del propietario y la base de datos, y puede asignárseles nombres de correlación según se considere conveniente.

Las vistas pueden combinarse exactamente del mismo modo que las tablas y utilizarse dondequiera se usen tablas. En el Chapter 9 se explican las vistas; este capítulo sólo emplea tablas en sus ejemplos.

La cláusula where

La cláusula where especifica la conexión entre las tablas especificadas en la cláusula from , restringiendo las filas que deben incluirse en los resultados. where proporciona los nombres de las columnas que van a combinarse, calificados por nombres de tablas si fuera necesario y el operador de combinación, a menudo de igualdad y a veces "mayor que" o "menor que". Para obtener más detalles sobre la sintaxis de la cláusula where , consulte el Chapter 2 de esta guía o la sección "Cláusula where" del Manual de Referencia de SQL Server .

Note: Si no se incluye la cláusula where , los resultados de una combinación serán imprevistos. Sin una cláusula where , cualquiera de las consultas de combinación explicadas hasta ahora generará 27 filas en lugar de 2. En la siguiente sección se explica por qué ocurre tal cosa.

Las combinaciones que comparan columnas según igualdad reciben el nombre de equicombinaciones . Más adelante en este capítulo encontrará una definición más precisa de equicombinación, junto con ejemplos de combinaciones no basadas en igualdad.

Los operadores de combinación que determinan la base de comparación de las columnas son los operadores relacionales:

Tabla 4-1: Operadores de combinación

Operador Significado

= Igual que

> Mayor que

>= Mayor o igual que

< Menor que

<= Menor o igual que

!= Distinto de

!> Menor o igual que

!< Mayor o igual que

Las combinaciones que usan operadores relacionales se denominan colectivamente combinaciones theta . Otro conjunto de operadores de combinación se utiliza para combinaciones externas , también explicadas en detalle más adelante en este capítulo. Los operadores de combinación externa son:

Tabla 4-2: Operaciones de combinación externa

Operador Acción

*= Incluye en los resultados todas las filas de la primera tabla, no sólo las filas donde coinciden las

Page 64: 80575032 Libro de SQL y Tl SQL Excelente

Page 64 of 280

columnas combinadas.

=* Incluye en los resultados todas las filas de la segunda tabla, no sólo las filas donde coinciden las columnas combinadas.

Las columnas que van a combinarse no necesitan tener el mismo nombre, aunque a menudo lo tengan. Además, tampoco necesitan tener el mismo tipo de datos (consulte el Chapter 7).

Sin embargo, si los tipos de datos no son idénticos, deben ser compatibles , es decir, tipos que SQL Server pueda convertir de forma automática. Por ejemplo, SQL Server convierte automáticamente cualquiera de las columnas de tipo numérico ( int, smallint, tinyint, decimal o float ) y cualquiera de las columnas de tipo de caracteres y de fecha ( char, varchar, nchar, nvarchar y datetime ). Para obtener información detallada sobre la conversión de tipo de datos, consulte el Capítulo 10, "Uso de funciones incorporadas en consultas", y la sección "Funciones de conversión de tipos de datos"del Manual de Referencia de SQL Server.

Note: No pueden combinarse tablas a partir de columnas text o image . Sin embargo, se pueden comparar las longitudes de columnas de texto de dos tablas con una cláusula where , como: where datalength(textab_1.textcol) >

datalength(textab_2.textcol)

La cláusula where de una instrucción de combinación puede incluir otras condiciones además de la que enlaza columnas de tablas diferentes. En otras palabras, es posible incluir una operación de combinación y una operación select en la misma instrucción SQL. Encontrará un ejemplo más adelante en este capítulo.

Procesamiento de combinaciones

Conocer el modo en que se procesan las combinaciones ayuda a entenderlas y a descubrir el motivo, cuando se define una combinación de forma incorrecta, por el que a veces se obtienen resultados imprevistos. En esta sección se describe el procesamiento de combinaciones en términos conceptuales. El procedimiento real de SQL Server es más sofisticado.

En términos conceptuales, el primer paso del procesamiento de una combinación es formar el producto cartesiano de las tablas, es decir, todas las combinaciones posibles de las filas de cada una de las tablas. El número de filas de un producto cartesiano de dos tablas es igual al número de filas de la primera tabla por el número de filas de la segunda tabla.

El producto cartesiano de la tabla authors y la tabla publishers es 69 (23 autores multiplicados por 3 editores). Se puede ver un producto cartesiano con cualquier consulta que incluya columnas de más de una tabla en la lista de selección, más de una tabla en la cláusula from y ninguna cláusula where . Por ejemplo si se omite la cláusula where de la combinación utilizada en los ejemplos anteriores, SQL Server combinará cada uno de los 23 autores con cada uno de los 3 editores, y devolverá 69 filas.

Este producto cartesiano no contiene ninguna información particularmente útil. De hecho, llevaría a una conclusión totalmente errónea, puesto que parece implicar que cada autor de la base de datos tiene una relación con cada editor de la base de datos, lo cual no es cierto en absoluto.

Este es el motivo por el que una combinación debe incluir una cláusula where , que especifica las columnas que deben compararse y en base a qué compararlas. También pueden incluirse otras restricciones. Una vez obtenido el producto cartesiano, las filas que no se ajustan a la combinación se eliminan según las condiciones de la cláusula where .

La cláusula where incluida en el ejemplo anterior elimina de los resultados todas las filas en las que la ciudad del autor no coincide con la del editor.

Equicombinaciones y combinaciones naturales

Una equicombinación es una combinación en la que los valores de las columnas combinadas se comparan para establecer su igualdad, y todas las columnas de las tablas de la combinación se incluyen en los resultados.

La consulta anterior:

select *

from authors, publishers

where authors.city = publishers.city

es una ejemplo de equicombinación. En los resultados de esta instrucción, la columna city aparece dos veces. Por definición, los resultados de una equicombinación contienen dos columnas idénticas. Puesto que generalmente no tiene ningún sentido repetir

Page 65: 80575032 Libro de SQL y Tl SQL Excelente

Page 65 of 280

la misma información, una de estas columnas pueden eliminarse volviéndose a definir la consulta. El resultado se llama combinación natural .

La consulta que da como resultado la combinación natural de publishers y authors a partir de la columna city es:

select publishers.pub_id, publishers.pub_name,

publishers.state, authors.*

from publishers, authors

where publishers.city = authors.city

La columna publishers.city no aparece en los resultados.

Combinaciones con condiciones adicionales

La cláusula where de una consulta de combinación puede incluir criterios de selección, así como especificar la condición de combinación. Por ejemplo, para recuperar los nombres y editores de todos los libros cuyos anticipos pagados son superiores a $7500, la instrucción es:

select title, pub_name, advance

from titles, publishers

where titles.pub_id = publishers.pub_id

and advance > $7500

title pub_name advance

----------------------------- -------------------- ---------

You Can Combat Computer Stress! New Age Books 10,125.00

The Gourmet Microwave Binnet & Hardley 15,000.00

Secrets of Silicon Valley Algodata Infosystems 8,000.00

Sushi, Anyone? Binnet & Hardley 8,000.00

(4 rows affected)

Observe que las columnas combinadas no necesitan aparecer en la lista de selección y, por lo tanto, no aparecen en los resultados.

En una instrucción de combinación se pueden incluir tantos criterios de selección como se deseen. El orden de los criterios de selección y la condición de combinación no es importante.

Combinaciones no basadas en la igualdad

La condición para combinar los valores de dos columnas no tiene que ser necesariamente la de igualdad. Es posible utilizar cualquiera de los demás operadores de comparación: distinto de (!=), mayor que (>), menor que (<), mayor o igual que (>=) y menor o igual que (<=). Transact-SQL también proporciona los operadores !> y !<, que son equivalentes a <= y >=, respectivamente.

Este ejemplo de una combinación mayor que (>) busca autores de New Age que vivan en estados que correspondan al estado de New Age Books , Massachusetts, en orden alfabético.

select pub_name, publishers.state,

au_lname, au_fname, authors.state

from publishers, authors

where authors.state > publishers.state

and pub_name = "New Age Books"

pub_name state au_lname au_fname state

------------- ------ -------------- ----------- -----

New Age Books MA Greene Morningstar TN

New Age Books MA Blotchet-Halls Reginald OR

New Age Books MA del Castillo Innes MI

New Age Books MA Panteley Sylvia MD

New Age Books MA Ringer Anne UT

New Age Books MA Ringer Albert UT

(6 rows affected)

El siguiente ejemplo utiliza una combinación ">=" y otra "<" para buscar el royalty correcto de la tabla roysched , basándose en las ventas totales del libro.

Page 66: 80575032 Libro de SQL y Tl SQL Excelente

Page 66 of 280

select t.title_id, t.total_sales, r.royalty

from titles t, roysched r

where t.title_id = r.title_id

and t.total_sales >= r.lorange and

t.total_sales < r.hirange

title_id total_sales royalty

-------- ----------- -------

BU1032 4095 10

BU1111 3876 10

BU2075 1872 24

BU7832 4095 10

MC2222 2032 12

MC3021 22246 24

PC1035 8780 16

PC8888 4095 10

PS1372 375 10

PS2091 2045 12

PS2106 111 10

PS3333 4072 10

PS7777 3336 10

TC3218 375 10

TC4203 15096 14

TC7777 4095 10

(16 rows affected)

Autocombinaciones y nombres de correlación

Se pueden comparar los valores de la columna de una tabla con la autocombinación . Por ejemplo, se puede hacer una autocombinación para averiguar qué autores de Oakland, California, tienen el mismo código postal.

Dado que esta consulta implica una combinación de la tabla authors consigo misma, esta tabla aparece en dos roles. Para distinguir estos roles, pueden asignarse temporal y arbitrariamente dos nombres de correlación diferentes a la tabla authors , como au1 y au2 , en la cláusula from . Estos nombres de correlación se utilizan para calificar los nombres de columna del resto de la consulta. La instrucción de autocombinación tiene el siguiente aspecto:

select au1.au_fname, au1.au_lname,

au2.au_fname, au2.au_lname

from authors au1, authors au2

where au1.city = "Oakland" and au2.city = "Oakland"

and au1.state = "CA" and au2.state = "CA"

and au1.postalcode = au2.postalcode

au_fname au_lname au_fname au_lname

--------- ----------- -------- --------

Marjorie Green Marjorie Green

Dick Straight Dick Straight

Dick Straight Dirk Stringer

Dick Straight Livia Karsen

Dirk Stringer Dick Straight

Dirk Stringer Dirk Stringer

Dirk Stringer Livia Karsen

Stearns MacFeather Stearns MacFeather

Livia Karsen Dick Straight

Livia Karsen Dirk Stringer

Livia Karsen Livia Karsen

(11 rows affected)

Para eliminar las filas de los resultados donde los autores coinciden consigo mismos y eliminar las filas que son idénticas, pero con el orden de los autores invertido, puede realizar esta adición a la consulta de autocombinación:

select au1.au_fname, au1.au_lname,

au2.au_fname, au2.au_lname

from authors au1, authors au2

where au1.city = "Oakland" and au2.city = "Oakland"

and au1.state = "CA" and au2.state = "CA"

and au1.postalcode = au2.postalcode

and au1.au_id < au2.au_id

au_fname au_lname au_fname au_lname

--------- ----------- --------- ---------

Page 67: 80575032 Libro de SQL y Tl SQL Excelente

Page 67 of 280

Dick Straight Dirk Stringer

Dick Straight Livia Karsen

Dirk Stringer Livia Karsen

(3 rows affected)

Ahora está claro que Dick Straight, Dirk Stringer y Livia Karsen tienen el mismo código postal.

La combinación de desigualdad

La combinación de desigualdad es particularmente útil para restringir filas devueltas por una autocombinación. Por ejemplo, una combinación de desigualdad y una autocombinación se utiliza para hallar las categorías donde haya dos o más libros baratos (menos de $15) de diferentes precios:

select distinct t1.type, t1.price

from titles t1, titles t2

where t1.price <$15 and t2.price <$15

and t1.type = t2.type

and t1.price != t2.price

type price

---------- -----

business 2.99

business 11.95

psychology 7.00

psychology 7.99

psychology 10.95

trad_cook 11.95

trad_cook 14.99

(7 rows affected)

Note: La expresión "not column_name = column_name" equivale a "column_name != column_name".

El siguiente ejemplo utiliza una combinación de desigualdad con una autocombinación: busca todas las filas de la tabla titleauthor donde hay dos o más filas con el mismo código title_id , pero con números de au_id diferentes, es decir, libros que tienen más de un autor.

select distinct t1.au_id, t1.title_id

from titleauthor t1, titleauthor t2

where t1.title_id = t2.title_id

and t1.au_id != t2.au_id

order by t1.title_id

au_id title_id

----------- --------

213-46-8915 BU1032

409-56-7008 BU1032

267-41-2394 BU1111

724-80-9391 BU1111

722-51-5454 MC3021

899-46-2035 MC3021

427-17-2319 PC8888

846-92-7186 PC8888

724-80-9391 PS1372

756-30-7391 PS1372

899-46-2035 PS2091

998-72-3567 PS2091

267-41-2394 TC7777

472-27-2349 TC7777

672-71-3249 TC7777

(15 rows affected)

Combinaciones de desigualdad y subconsultas

Algunas veces una consulta de combinación de desigualdad no es suficientemente restrictiva y necesita ser sustituida por una subconsulta. Por ejemplo, suponga que quiere enumerar los nombres de los autores que viven en una ciudad en la que no hay ningún editor. Para mayor claridad, podemos restringir la consulta a los autores cuyos apellidos empiecen con "A", "B" o "C". Una consulta de combinación de desigualdad podría ser:

Page 68: 80575032 Libro de SQL y Tl SQL Excelente

Page 68 of 280

select distinct au_lname, authors.city

from publishers, authors

where au_lname like "[ABC]%"

and publishers.city != authors.city

Pero los resultados no responden a la pregunta formulada.

au_lname city

---------------- ------------

Bennet Berkeley

Carson Berkeley

Blotchet-Halls Corvallis

(3 rows affected)

El sistema interpreta esta versión de la instrucción SQL con el siguiente significado: "buscar los nombres de los autores que vivan en una ciudad donde no hay ningún editor". Todos los autores excluidos cumplen con esta condición, incluidos los que viven en Berkeley, sede de la editorial Algodata Infosystems.

En este caso, el modo en que el sistema manipula las combinaciones (buscando todas las combinaciones seleccionables antes de evaluar otras condiciones) hace que la consulta devuelva resultados no deseados. En estos casos, es necesario utilizar una subconsulta para obtener los resultados deseados. Una subconsulta puede eliminar primero las filas no seleccionables y después realizar las restantes restricciones.

A continuación se muestra la instrucción correcta:

select distinct au_lname, city

from authors

where au_lname like "[ABC]%"

and city not in

(select city from publishers

where authors.city = publishers.city)

Ahora los resultados son los deseados:

au_lname city

------------- ------------

Blotchet-Halls Corvallis

(1 row affected)

Las subconsultas se explican con mayor detalle en el Chapter 5.

Combinación de más de dos tablas

La tabla titleauthor de pubs2 ofrece un buen ejemplo de una situación en la que resulta útil la combinación de más de dos tablas. Para buscar los títulos de todos los libros de un tipo concreto y los nombres de sus autores, la consulta es:

select au_lname, au_fname, title

from authors, titles, titleauthor

where authors.au_id = titleauthor.au_id

and titles.title_id = titleauthor.title_id

and titles.type = "trad_cook"

au_lname au_fname title

-------------- ----------- ------------------------

Panteley Sylvia Onions, Leeks, and Garlic: Cooking

Secrets of the Mediterranean

Blotchet-Halls Reginald Fifty Years in Buckingham Palace

Kitchens

O'Leary Michael Sushi, Anyone?

Gringlesby Burt Sushi, Anyone?

Yokomoto Akiko Sushi, Anyone?

(5 rows affected)

Page 69: 80575032 Libro de SQL y Tl SQL Excelente

Page 69 of 280

Observe que una de las tablas de la cláusula from , titleauthor , no contribuye ninguna columna a los resultados. Ni tampoco ninguna de las columnas que se combinan, au_id y title_id , aparecen en los resultados. No obstante, esta combinación es posible únicamente mediante el uso de titleauthor como tabla intermedia.

También pueden combinarse más de dos pares de columnas en la misma instrucción. Por ejemplo, a continuación se muestra una consulta que indica la title_id , sus ventas totales y el margen al que corresponden, y los derechos de autor resultantes.

select titles.title_id, total_sales, lorange, hirange, royalty

from titles, roysched

where titles.title_id = roysched.title_id

and total_sales >= lorange and total_sales < hirange

title_id total_sales lorange hirange royalty

-------- ----------- ------- ------- -------

BU1032 4095 0 5000 10

BU1111 3876 0 4000 10

BU2075 18722 14001 50000 24

BU7832 4095 0 5000 10

MC2222 2032 2001 4000 12

MC3021 2224 12001 50000 24

PC1035 8780 4001 10000 16

PC8888 4095 0 5000 10

PS1372 375 0 10000 10

PS2091 2045 1001 5000 12

PS2106 111 0 2000 10

PS3333 4072 0 5000 10

PS7777 3336 0 5000 10

TC3218 375 0 2000 10

TC4203 15096 8001 16000 14

TC7777 4095 0 5000 10

(16 rows affected)

Cuando hay varios operadores de combinación en la misma instrucción, para combinar más de dos tablas o más de dos pares de columnas, las "expresiones de combinación" están casi siempre conectadas por and , como en los ejemplos anteriores. Sin embargo, también es legal conectarlas mediante or.

Combinaciones externas

En las combinaciones que se han explicado, sólo las filas coincidentes, es decir, las filas con valores en las columnas especificadas que satisfacen la condición de combinación, se incluyen en los resultados. En cierto modo, estas operaciones de combinación eliminan la información contenida en las filas que no coinciden.

Algunas veces es preferible conservar dicha información mediante la inclusión de filas no coincidentes en los resultados de una combinación. En tales ocasiones, la combinación externa es la operación de elección. Transact-SQL es una de las pocas versiones de SQL que soporta la combinación externa.

Estos son los operadores de combinación externa proporcionados por Transact-SQL:

Tabla 4-3: Resumen de los operadores de combinación externa

Operador Acción

*= Incluye todas las filas de la primera tabla especificada

=* Incluye todas las filas de la segunda tabla especificada

Recuerde que la consulta sobre autores que viven en la misma ciudad que un editor devuelve dos nombres: Abraham Bennett y Cheryl Carson. Para incluir todos los autores en los resultados, independientemente de si un editor está ubicado en la misma ciudad, utilice una combinación externa. A continuación se muestra la consulta y los resultados de la combinación externa:

select au_fname, au_lname, pub_name

from authors, publishers

where authors.city *= publishers.city

au_fname au_lname pub_name

--------- -------------- ---------------

Johnson White NULL

Marjorie Green NULL

Cheryl Carson Algodata Infosystems

Page 70: 80575032 Libro de SQL y Tl SQL Excelente

Page 70 of 280

Michael O'Leary NULL

Dick Straight NULL

Meander Smith NULL

Abraham Bennet Algodata Infosystems

Ann Dull NULL

Burt Gringlesby NULL

Chastity Locksley NULL

Morningstar Greene NULL

Reginald Blotche-Halls NULL

Akiko Yokomoto NULL

Innes del Castillo NULL

Michel DeFrance NULL

Dirk Stringer NULL

Stearns MacFeather NULL

Livia Karsen NULL

Sylvia Panteley NULL

Sheryl Hunter NULL

Heather McBadden NULL

Anne Ringer NULL

Albert Ringer NULL

(23 rows affected)

El operador de comparación "*=" distingue la combinación externa de una ordinaria. Esta combinación externa "izquierda" indica a SQL Server que incluya todas las filas de la tabla authors en los resultados, exista o no una coincidencia en la columna city de la tabla publishers . Observe que en los resultados no existen datos coincidentes para la mayoría de los autores mostrados, por lo que estas filas contienen NULL en la columna pub_name .

Note: Dado que las columnas de bits no permiten valores nulos, cuando no existe correspondencia para una columna de bits en la tabla interna, aparece un valor de "0" en una combinación externa.

La combinación externa "derecha" se especifica con el operador de comparación "=*", que indica que en los resultados deben incluirse todas las filas de la segunda tabla, independientemente de si existen datos coincidentes en la primera tabla.

La sustitución de este operador en la consulta de combinación externa anterior da este resultado:

select au_fname, au_lname, pub_name

from authors, publishers

where authors.city =* publishers.city

au_fname au_lname pub_name

--------- --------- ---------------

NULL NULL New Age Books

NULL NULL Binnet & Hardley

Cheryl Carson Algodata Infosystems

Abraham Bennet Algodata Infosystems

(4 rows affected)

Una combinación externa puede restringirse todavía más si se compara con una constante. Esto significa que puede enfocarse de forma precisa en el valor o valores realmente deseados y utilizar la combinación externa para mostrar las filas que no entraron en el corte. Primero observe la equicombinación y luego compárela con la combinación externa. Por ejemplo, si desea averiguar qué títulos vendieron más de 500 copias en cualquier librería, tendría que usar esta consulta:

elect distinct salesdetail.stor_id, title

from titles, salesdetail

where qty > 500

and salesdetail.title_id = titles.title_id

stor_id title

------- --------------------------------------------

5023 Sushi, Anyone?

5023 Is Anger the Enemy?

5023 The Gourmet Microwave

5023 But Is It User Friendly?

5023 Secrets of Silicon Valley

5023 Straight Talk About Computers

5023 You Can Combat Computer Stress!

5023 Silicon Valley Gastronomic Treats

5023 Emotional Security: A New Algorithm

5023 The Busy Executive's Database Guide

Page 71: 80575032 Libro de SQL y Tl SQL Excelente

Page 71 of 280

5023 Fifty Years in Buckingham Palace Kitchens

5023 Prolonged Data Deprivation: Four Case Studies

5023 Cooking with Computers: Surreptitious Balance Sheets

7067 Fifty Years in Buckingham Palace Kitchens

(14 rows affected)

Para mostrar, además, los títulos que no vendieron más de 500 copias en cualquier librería, puede utilizar una consulta de combinación externa:

select distinct salesdetail.stor_id, title

from titles, salesdetail

where qty > 500

and salesdetail.title_id =* titles.title_id

stor_id title

------- -------------------------------------------

NULL Net Etiquette

NULL Life Without Fear

5023 Sushi, Anyone?

5023 Is Anger the Enemy?

5023 The Gourmet Microwave

5023 But Is It User Friendly?

5023 Secrets of Silicon Valley

5023 Straight Talk About Computers

5023 You Can Combat Computer Stress!

5023 Silicon Valley Gastronomic Treats

5023 Emotional Security: A New Algorithm

5023 The Busy Executive's Database Guide

5023 Fifty Years in Buckingham Palace Kitchens

7067 Fifty Years in Buckingham Palace Kitchens

5023 Prolonged Data Deprivation: Four Case Studies

5023 Cooking with Computers: Surreptitious Balance Sheets

NULL Computer Phobic and Non-Phobic Individuals: Behavior

Variations

NULL Onions, Leeks, and Garlic: Cooking Secrets of the

Mediterranean

(18 rows affected)

Restricciones de las combinaciones externas

En Transact-SQL, una tabla no puede participar en una cláusula de combinación externa y en otra de combinación regular. La siguiente consulta fracasa porque se pide a la tabla salesdetail que realice una doble tarea:

select distinct sales.stor_id, stor_name, title

from sales, stores, titles, salesdetail

where qty > 500

and salesdetail.title_id =* titles.title_id

and sales.stor_id = salesdetail.stor_id

and sales.stor_id = stores.stor_id

Msg 303, Level 16, State 1:

Server 'RAW', Line 1:

La tabla 'salesdetail' es un miembro interno de una cláusula de combinación externa. Esto no

se permite si la tabla participa además en una cláusula de combinación normal.

Si quisiera saber el nombre de la librería que vendió más de 500 copias de algún libro, tendría que utilizar una segunda consulta. Si ejecuta una consulta con una combinación externa y una calificación en una columna de la tabla interna de la combinación externa, los resultados pueden ser distintos de los esperados. La calificación de la consulta no restringe el número de filas devueltas, sino que afecta a las filas que contienen el valor nulo. Para las filas que no cumplen la calificación, aparece un valor nulo en las columnas de la tabla interna de dichas filas.

Efecto de los valores nulos sobre las combinaciones

Si las columnas de las tablas combinadas contienen valores nulos, éstos nunca pueden coincidir. Además, el resultado de una combinación de NULL con cualquier otro valor, es NULL. Dado que los valores nulos representan valores desconocidos o inaplicables, Transact-SQL no tiene ningún motivo para creer que un valor desconocido coincide con otro.

Page 72: 80575032 Libro de SQL y Tl SQL Excelente

Page 72 of 280

Sólo se puede detectar la presencia de valores nulos en una columna de una de las tablas de la combinación si se usa una combinación externa. A continuación se muestran dos tablas, cada una de las cuales tiene un valor NULL en la columna que va a formar parte de la combinación. Una combinación externa izquierda muestra el valor NULL en la primera tabla.

Tabla 1:

a b

--------- ------

1 one

NULL three

4 join4

Tabla 2:

c d

--------- ------

NULL two

4 four

Combinación externa izquierda:

select *

from t1, t2

where a *= c

a b c d

----------- ------ ----------- ------

1 one NULL NULL

NULL three NULL NULL

4 join4 4 four

Observe que los resultados no facilitan la distinción entre un valor NULL en los datos y uno NULL que representa un fallo de la combinación. Cuando hay valores nulos en los datos que van a combinarse, generalmente es preferible omitirlos de los resultados mediante el uso de una combinación regular.

Determinación de las columnas de tabla que deben combinarse

El procedimiento del sistema sp_helpjoins muestra las columnas de dos tablas o vistas que son posibles candidatos a la combinación. Su sintaxis es:

sp_helpjoins table1 , table2

Por ejemplo, a continuación se muestra cómo utilizar sp_helpjoins para localizar las columnas posibles de combinar entre titleauthor y titles :

sp_helpjoins titleauthor, titles

Los pares de columnas que sp_helpjoins muestra proceden de dos fuentes. Primero sp_helpjoins verifica la tabla syskeys de la base de datos actual para ver si se definió alguna clave externa en las dos tablas con sp_foreignkeye y después comprueba si se definió alguna clave común en las dos tablas con sp_commonkey . Si no encuentra ninguna clave común, el procedimiento aplica criterios menos restrictivos para proponer cualquier clave que pueda combinarse de forma razonable; busca las claves con los mismos tipos de datos de usuario y, si falla, busca las columnas con el mismo nombre y tipo de datos.

Para obtener información completa sobre los procedimientos del sistema, consulte el Manual de Referencia de SQL Server .

Chapter 5

Subconsultas: uso de consultas dentro de otras consultas

Una subconsulta es una instrucción select anidada dentro de otra instrucción select , insert , update o delete , dentro de una instrucción condicional o dentro de otra subconsulta.

En este capítulo se trata lo siguiente:

Page 73: 80575032 Libro de SQL y Tl SQL Excelente

Page 73 of 280

Definición de consulta

Tipos de subconsultas

Subconsultas de expresión

Subconsultas de predicado cuantificado

Subconsultas correlacionadas

Definición de subconsulta

Tipos de subconsultas

Subconsultas de expresión

Subconsultas de predicado cuantificado

Uso de subconsultas correlacionadas

Definición de subconsulta

Las subconsultas son consultas que aparecen en la cláusula where o having de otra instrucción SQL o en la lista de selección de una instrucción. Las subconsultas pueden utilizarse para manipular las solicitudes de consulta que se expresan como el resultado de otras consultas. Las instrucciones que incluyen subconsultas operan sobre las filas de una tabla, de acuerdo a su evaluación de la lista select de la subconsulta, que puede hacer referencia a la misma tabla como una consulta externa, o bien a una tabla distinta. En Transact-SQL, una subconsulta puede usarse prácticamente en cualquier lugar donde se permita una expresión, siempre que la subconsulta devuelva un valor único.

Las instrucciones select que contienen una o más subconsultas a veces se denominan consultas anidadas o instrucciones select anidadas. La práctica de anidar una instrucción select en otra explica que se incluya el término "structured" (estructurado) en SQL (Structured Query Language).

Muchas instrucciones SQL que incluyen subconsultas, también llamadas consultas internas , pueden formularse alternativamente como combinaciones. Otras preguntas sólo pueden formularse con subconsultas. Algunos prefieren las subconsultas a las formulaciones alternativas porque son más fáciles de entender. Otros usuarios de SQL evitan las consultas siempre que sea posible. Usted puede elegir la formulación que prefiera (SQL Server convierte algunas subconsultas en combinaciones antes de procesarlas).

Ejemplo del uso de una subconsulta

Si desea encontrar todos los libros con el mismo precio que Straight Talk About Computers , puede hacerlo en dos pasos. En primer lugar, busque el precio de Straight Talk :

select price

from titles

where title = "Straight Talk About Computers"

price

-------------

$19.99

(1 row affected)

Ahora use dicho resultado en otra consulta para buscar todos los libros cuyo precio sea idéntico al de Straight Talk :

select title, price

from titles

where price = $19.99

title price

------------------------------------------ -----

The Busy Executive's Database Guide 19.99

Straight Talk About Computers 19.99

Silicon Valley Gastronomic Treats 19.99

Prolonged Data Deprivation: Four Case Studies 19.99

(4 rows affected)

La subconsulta resuelve el problema con una sola instrucción:

select title, price

from titles

where price =

Page 74: 80575032 Libro de SQL y Tl SQL Excelente

Page 74 of 280

(select price

from titles

where title = "Straight Talk About Computers")

title price

--------------------------------------- -----

The Busy Executive's Database Guide 19.99

Straight Talk About Computers 19.99

Silicon Valley Gastronomic Treats 19.99

Prolonged Data Deprivation: Four Case Studies 19.99

(4 rows affected)

Sintaxis y reglas generales de las subconsultas

Incluya siempre la instrucción select de una subconsulta entre paréntesis. La instrucción select de la consulta tiene una sintaxis select algo restringida, como puede verse en este ejemplo.

(select [distinct] subquery_select_list

[from [[ database .] owner .]{ table_name | view_name }

[({index index_name | prefetch size |[lru|mru]})]}

[holdlock | noholdlock] [shared]

[,[[ database .] owner .]{ table_name | view_name }

[({index index_name | prefetch size |[lru|mru]})]}

[holdlock | noholdlock] [shared]]... ]

[where search_conditions ]

[group by aggregate_free_expression [,

aggregate_free_expression ]... ]

[having search_conditions ])

Las subconsultas pueden anidarse dentro de la cláusula where o having de una instrucción externa select , insert , update o delete , dentro de otra subconsulta, o en una lista de selección.

En Transact-SQL, una subconsulta puede aparecer prácticamente en cualquier lugar donde pueda usarse una expresión, siempre que devuelva un solo valor.

Restricciones de las subconsultas

Las subconsultas están sujetas a estas restricciones:

Las subconsultas no pueden usarse en una lista order by , group by ni compute by .

Las subconsultas no pueden incluir cláusulas for browse ni uniones ( union ).

La lista de selección de una subconsulta interna con un operador de comparación puede incluir sólo una expresión o nombre de columna, y la subconsulta debe devolver un solo valor. La columna especificada en la cláusula where de la instrucción externa debe ser compatible en cuanto a sus combinaciones con la columna especificada en la lista de selección de la subconsulta.

No se permiten tipos de datos text e image en las subconsultas.

Las subconsultas no pueden manipular sus resultados internamente, es decir, una subconsulta no puede incluir la cláusula order by, la cláusula compute ni la palabra clave into .

Las subconsultas correlacionadas (repetidas) no se permiten en la cláusula select de un cursor actualizable definido por declare cursor .

Hay un límite de 16 niveles de anidación.

El número máximo de subconsultas a cada lado de una unión es de 16.

Calificación de nombres de columna

En el siguiente ejemplo, la columna pub_id de la cláusula where , de la consulta externa, está implícitamente calificada por el nombre de tabla publishers de la cláusula from , de la consulta externa. La referencia a pub_id en la lista de selección de la subconsulta está calificada por la cláusula from de la subconsulta, es decir, por la tabla titles :

select pub_name

from publishers

where pub_id in

(select pub_id

from titles

where type = "business")

Page 75: 80575032 Libro de SQL y Tl SQL Excelente

Page 75 of 280

La regla general es que los nombres de columna de una instrucción están implícitamente calificados por la tabla referenciada en la cláusula from del mismo nivel.

Este es el aspecto de la consulta cuando se detallan todas estas suposiciones implícitas:

select pub_name

from publishers

where publishers.pub_id in

(select titles.pub_id

from titles

where type = "business")

Nunca es incorrecto indicar explícitamente el nombre de una tabla, y siempre es posible ignorar las suposiciones implícitas relativas a los nombres de las tablas calificando dichos nombres de forma explícita.

Subconsultas con nombres de correlación

Como se explicó en el Capítulo 4, "Combinaciones: recuperación de datos de varias tablas", los nombres de correlación de tabla en las autocombinaciones son necesarios porque la tabla autocombinada aparece en dos roles distintos. Los nombres de correlación también pueden emplearse en consultas anidadas que hacen referencia a la misma tabla en una consulta interna y en otra externa.

Por ejemplo, los autores que viven en la misma ciudad que Livia Karsen pueden encontrarse mediante esta subconsulta:

select au1.au_lname, au1.au_fname, au1.city

from authors au1

where au1.city in

(select au2.city

from authors au2

where au2.au_fname = "Livia"

and au2.au_lname = "Karsen")

au_lname au_fname city

----------- --------- -------

Green Marjorie Oakland

Straight Dick Oakland

Stringer Dirk Oakland

MacFeather Stearns Oakland

Karsen Livia Oakland

(5 rows affected)

Los nombres de correlación explícita dejan claro que la referencia a authors en la subconsulta no tiene el mismo significado que la referencia a authors en la consulta externa.

Sin la correlación explícita, la subconsulta tiene este aspecto:

select au_lname, au_fname, city

from authors

where city in

(select city

from authors

where au_fname = "Livia"

and au_lname = "Karsen")

La consulta anterior, y otras instrucciones en las que la subconsulta y la consulta externa hacen referencia a la misma tabla, puede definirse de forma alternativa como una autocombinación:

select au1.au_lname, au1.au_fname, au1.city

from authors au1, authors au2

where au1.city = au2.city

and au2.au_lname = "Karsen"

and au2.au_fname = "Livia"

Es posible que los resultados de una subconsulta redefinida como una combinación no aparezcan en el mismo orden, y la combinación puede necesitar la palabra clave distinct para eliminar los duplicados.

Page 76: 80575032 Libro de SQL y Tl SQL Excelente

Page 76 of 280

Niveles múltiples de anidación

Una subconsulta puede incluir otra subconsulta o varias. En una instrucción es posible anidar hasta 16 subconsultas.

Un ejemplo de problema que puede resolverse usando una instrucción con múltiples niveles de consultas anidadas es "buscar los nombres de los autores que hayan participado en la redacción de al menos un libro conocido de informática".

select au_lname, au_fname

from authors

where au_id in

(select au_id

from titleauthor

where title_id in

(select title_id

from titles

where type = "popular_comp") )

au_lname au_fname

---------------------- ------------

Carson Cheryl

Dull Ann

Hunter Sheryl

Locksley Chastity

(4 rows affected)

La consulta más externa selecciona los nombres de todos los autores, la siguiente busca las IDs de los autores y la más interna devuelve los números de ID de título PC1035, PC8888 y PC9999.

Esta consulta también puede expresarse como una combinación:

select au_lname, au_fname

from authors, titles, titleauthor

where authors.au_id = titleauthor.au_id

and titles.title_id = titleauthor.title_id

and type = "popular_comp"

Subconsulta en instrucciones update , delete e insert

Las subconsultas pueden anidarse en instrucciones update , delete e insert , así como en instrucciones select .

Note: La ejecución de estos ejemplos de consulta cambiará la base de datos pubs2 . Para obtener una copia limpia de la base de datos de muestra, es necesario solicitarla al administrador del sistema.

La siguiente consulta dobla el precio de todos los libros publicados por New Age Books. La instrucción actualiza la tabla titles ; su subconsulta hace referencia a la tabla publishers .

update titles

set price = price * 2

where pub_id in

(select pub_id

from publishers

where pub_name = "New Age Books")

Una instrucción update equivalente que usa una combinación es:

update titles

set price = price * 2

from titles, publishers

where titles.pub_id = publishers.pub_id

and pub_name = "New Age Books"

Con esta instrucción select anidada pueden quitarse todos los registros de ventas de libros de negocios:

delete salesdetail

where title_id in

(select title_id

Page 77: 80575032 Libro de SQL y Tl SQL Excelente

Page 77 of 280

from titles

where type = "business")

Una instrucción delete equivalente que usa una combinación es:

delete salesdetail

from salesdetail, titles

where salesdetail.title_id = titles.title_id

and type = "business"

Subconsultas en instrucciones condicionales

Las subconsultas también pueden utilizarse en instrucciones condicionales. La subconsulta anterior que eliminó todos los registros de ventas de libros de negocios podría volver a escribirse, como se muestra en el ejemplo siguiente, para verificar los registros antes de eliminarlos:

if exists (select title_id

from titles

where type = "business")

begin

delete salesdetail

where title_id in

(select title_id

from titles

where type = "business")

end

Uso de subconsultas en lugar de una expresión

En Transact-SQL, una subconsulta puede usarse prácticamente en cualquier lugar que permita una expresión en las instrucciones select , update , insert o delete . No es posible utilizar subconsultas en una lista order by . A continuación se ofrecen algunos ejemplos que ilustran el modo en que puede utilizarse esta mejora de Transact-SQL.

La siguiente instrucción busca los títulos y tipos de libros escritos por autores residentes en California y publicados en ese mismo estado:

select title, type

from titles

where title in

(select title

from titles, titleauthor, authors

where titles.title_id = titleauthor.title_id

and titleauthor.au_id = authors.au_id

and authors.state = "CA")

and title in

(select title

from titles, publishers

where titles.pub_id = publishers.pub_id

and publishers.state = "CA")

title type

----------------------------------- ----------

The Busy Executive's Database Guide business

Cooking with Computers:

Surreptitious Balance Sheets business

Straight Talk About Computers business

But Is It User Friendly? popular_comp

Secrets of Silicon Valley popular_comp

Net Etiquette popular_comp

(6 rows affected)

La siguiente instrucción selecciona los títulos de libros que vendieron más de 5000 copias, muestra sus precios y el precio del libro más caro:

select title, price,

(select max(price) from titles)

Page 78: 80575032 Libro de SQL y Tl SQL Excelente

Page 78 of 280

from titles

where total_sales > 5000

title price

----------------------------------- ----- ------

You Can Combat Computer Stress! 2.99 22.95

The Gourmet Microwave 2.99 22.95

But Is It User Friendly? 22.95 22.95

Fifty Years in Buckingham Palace

Kitchens 11.95 22.95

Tipos de subconsultas

Existen dos tipos básicos de subconsultas:

Las subconsultas introducidas con un operador de comparación sin modificar y que deben devolver un solo valor se conocen como subconsultas de expresión .

Las subconsultas que operan en listas introducidas con in o con un operador de comparación modificado por any o all , o bien las subconsultas que constituyen una prueba de existencia, introducidas con exists , se conocen como subconsultas de predicado cuantificado .

Las subconsultas de ambos tipos pueden ser correlacionadas (repetidas) o no correlacionadas.

Una subconsulta no correlacionada puede evaluarse como una consulta independiente. En términos conceptuales, los resultados de la subconsulta se usan en la instrucción principal, o consulta externa. Esta no es la forma real en que SQL Server procesa las instrucciones con subconsultas. Las subconsultas no correlacionadas pueden definirse alternativamente como combinaciones y SQL Server las procesa como combinaciones.

Una subconsulta correlacionada no puede evaluarse como una consulta independiente, pero puede hacer referencia a las columnas de la tabla especificada en la lista from de la consulta externa. Las subconsultas correlacionadas se explican en detalle al final de este capítulo.

Las siguientes secciones explican los distintos tipos de subconsultas.

Subconsultas de expresión

Las subconsultas de expresión se introducen con uno de los operadores de comparación = , != , <> , > , >= , < , !> , !< o < , y su formato general es el siguiente:

[Comienzo de instrucción o subconsulta select , insert , update , delete ]

where expression comparison_operator ( subquery )

[Fin de instrucción o subconsulta select , insert , update , delete ]

Las subconsultas introducidas con un operador de comparación sin modificar, es decir, un operador de comparación que no va seguido de any ni all , deben tener como resultado un solo valor. Si una subconsulta de este tipo devuelve más de un valor, SQL Server genera un mensaje de error.

Lo ideal es que, para usar una subconsulta introducida con un operador de comparación sin modificar, el usuario esté suficientemente familiarizado con sus datos y con la naturaleza del problema para tener la certeza de que la subconsulta va a devolver un valor.

Por ejemplo, supongamos que cada editor está ubicado en una sola ciudad. Para buscar los nombres de los autores que viven en la ciudad donde se encuentra Algodata Infosystems, escribiremos una instrucción con una subconsulta introducida con el operador de comparación = :

select au_lname, au_fname

from authors

where city =

(select city

from publishers

where pub_name = "Algodata Infosystems")

au_lname au_fname

-------------- --------------

Carson Cheryl

Page 79: 80575032 Libro de SQL y Tl SQL Excelente

Page 79 of 280

Bennet Abraham

(2 rows affected)

Uso de funciones agregadas escalares para garantizar un solo valor

Las subconsultas introducidas con operadores de comparación sin modificar incluyen frecuentemente funciones agregadas escalares, ya que las mismas devuelven un solo valor.

Por ejemplo, esta instrucción busca los nombres de todos los libros cuyo precio es superior al precio mínimo actual:

select title

from titles

where price >

(select min(price)

from titles)

title

---------------------------------------------------

The Busy Executive's Database Guide

Cooking with Computers: Surreptitious Balance

Sheets

Straight Talk About Computers

Silicon Valley Gastronomic Treats

But Is It User Friendly?

Secrets of Silicon Valley

Computer Phobic and Non-Phobic Individuals:

Behavior Variations

Is Anger the Enemy?

Life Without Fear

Prolonged Data Deprivation: Four Case Studies

Emotional Security: A New Algorithm

Onions, Leeks, and Garlic: Cooking Secrets of the

Mediterranean

Fifty Years in Buckingham Palace Kitchens

Sushi, Anyone?

(14 rows affected)

group by y having en subconsultas de expresión

Dado que las subconsultas introducidas con operadores de comparación sin modificar deben devolver un solo valor, no pueden incluir cláusulas group by y having , a no ser que se sepa con certeza que estas cláusulas devolverán un valor único.

Por ejemplo, esta consulta busca los libros cuyo precio es superior al del libro con el precio más bajo dentro de la categoría trad_cook :

select title

from titles

where price >

(select min(price)

from titles

group by type

having type = "trad_cook")

Uso de distinct con subconsultas de expresión

Las subconsultas introducidas con operadores de comparación sin modificar, a menudo incluyen la palabra clave distinct para devolver un solo valor.

Por ejemplo, sin distinct , la siguiente subconsulta no se ejecutaría de forma correcta porque devolvería más de un valor:

select pub_name from publishers

where pub_id =

(select distinct pub_id

from titles

where pub_id = publishers.pub_id)

Page 80: 80575032 Libro de SQL y Tl SQL Excelente

Page 80 of 280

Subconsultas de predicado cuantificado

Las subconsultas de predicado cuantificado, que devuelven 0 o un valor superior, son subconsultas en una cláusula where o having que están conectadas por any , all , in o exists . Los operadores de subconsulta any o all modifican los operadores de comparación.

Las subconsultas introducidas con un operador de comparación modificado, que pueden incluir una cláusula group by o having , tienen este formato general: [Comienzo de instrucción o subconsulta select , insert , update , delete ]

where expression comparison_operator [any | all]

( subquery )

[Final de instrucción o subconsulta select , insert , update , delete ]

Las subconsultas introducidas con in o not in tienen este formato general:[Comienzo de instrucción o subconsulta select , insert , update , delete ]

where expression [not] in ( subquery )

[Final de instrucción o subconsulta select , insert , update , delete ]

Las subconsultas introducidas con exists o not exists constituyen pruebas de existencia cuyo formato general es el siguiente: [Comienzo de instrucción o subconsulta select , insert , update , delete ]

where [not] exists ( subquery )

[Final de instrucción o subconsulta select , insert , update , delete ]

Aunque las subconsultas de predicado cuantificado permiten el uso de la palabra clave distinct , la subconsulta siempre se procesa como si distinct no estuviera incluido.

Subconsultas con any y all

Las palabras clave all y any modifican un operador de comparación que introduce una subconsulta.

Tomando el operador de comparación > como ejemplo:

>all significa mayor que todos los valores o mayor que el valor máximo. Por ejemplo, >all (1, 2, 3) significa mayor que 3.

>any significa mayor que algún valor o mayor que el valor mínimo. Por ejemplo, >any (1, 2, 3) significa mayor que 1.

Si una subconsulta se introduce con all y un operador de comparación no devuelve ningún valor, toda la consulta fracasa.

El uso de all y any puede resultar complicado porque las computadoras no toleran la ambigüedad que estas palabras a veces tienen en inglés. Por ejemplo, podría formularse la pregunta "¿Qué libros tuvieron un anticipo superior al de cualquier libro editado por New Age Books?".

Esta pregunta puede parafrasearse para que su "traducción" en SQL sea más clara: "¿Qué libros tuvieron un anticipo superior al máximo anticipo pagado por New Age Books?". En este caso se necesita la palabra clave all , y no any :

select title

from titles

where advance > all

(select advance

from publishers, titles

where titles.pub_id = publishers.pub_id

and pub_name = "New Age Books")

title

----------------------------------------

The Gourmet Microwave

Page 81: 80575032 Libro de SQL y Tl SQL Excelente

Page 81 of 280

(1 row affected)

Para cada título, la consulta externa obtiene los títulos y anticipos de la tabla titles y los compara con los anticipos pagados por New Age Books devueltos por la subconsulta. La consulta externa examina el valor máximo de la lista y determina si el título en cuestión ha tenido un anticipo todavía mayor.

> all significa mayor que todos los valores

En el contexto de una subconsulta, >all significa que, para que una fila cumpla una condición específica en la consulta externa, el valor de la columna que introduce la subconsulta debe ser mayor que todos los valores devueltos por la subconsulta.

Por ejemplo, para buscar los libros cuyo precio es superior al del libro con el precio máximo dentro de la categoría mod_cook :

select title from titles where price > all

(select price from titles

where type = "mod_cook")

title

---------------------------------------------------

But Is It User Friendly?

Secrets of Silicon Valley

Computer Phobic and Non-Phobic Individuals:

Behavior Variations

Onions, Leeks, and Garlic: Cooking Secrets of

the Mediterranean

(4 rows affected)

Sin embargo, si el conjunto devuelto por la consulta interna contiene un valor NULL, la consulta devuelve 0 filas. Esto se debe a que NULL significa "valor desconocido", y es imposible saber si el valor que se está comparando es mayor que un valor desconocido.

Por ejemplo, intente encontrar aquellos libros cuyo precio es superior al del libro con el precio máximo dentro de la categoría popular_comp :

select title from titles where price > all

(select price from titles

where title_id = "popular_comp")

title

---------------------------------------------------

(0 rows affected)

El resultado es 0 filas porque la subconsulta encontró un libro, Net Etiquette , con precio nulo.

=all significa igual a todos los valores

El operador =all significa igual a todos los valores. Para que una fila cumpla con la condición especificada en la consulta externa, el valor de la columna que introduce la subconsulta debe ser igual a todos los valores de la lista devuelta por la subconsulta.

Por ejemplo, la siguiente consulta busca los autores que viven en la misma ciudad examinando el código postal:

select au_fname, au_lname, city

from authors

where city = all

(select city

from authors

where postalcode like "946%")

> any significa mayor que algún valor

>any significa que, para que una fila cumpla la condición especificada en la consulta externa, el valor de la columna que introduce la subconsulta debe ser mayor que al menos uno de los valores de la lista de valores devueltos por la subconsulta.

Page 82: 80575032 Libro de SQL y Tl SQL Excelente

Page 82 of 280

La siguiente consulta proporciona un ejemplo de una subconsulta introducida por un operador de comparación modificado por any . La consulta busca todos los títulos con anticipo superior a los importes pagados en concepto de anticipos por New Age Books.

select title

from titles

where advance > any

(select advance

from titles, publishers

where titles.pub_id = publishers.pub_id

and pub_name = "New Age Books")

title

---------------------------------------------------

Sushi, Anyone?

Life Without Fear

Is Anger the Enemy?

The Gourmet Microwave

But Is It User Friendly?

Secrets of Silicon Valley

Straight Talk About Computers

You Can Combat Computer Stress!

Emotional Security: A New Algorithm

The Busy Executive's Database Guide

Fifty Years in Buckingham Palace Kitchens

Cooking with Computers: Surreptitious Balance

Sheets

Computer Phobic and Non-Phobic Individuals:

Behavior Variations

Onions, Leeks, and Garlic: Cooking Secrets of

the Mediterranean

(14 rows affected)

Por cada título seleccionado por la consulta externa, la consulta interna busca una lista de importes de los anticipos pagados por New Age Books. La consulta externa examina todos los valores de la lista y determina si el título en cuestión ha recibido un anticipo superior a cualquiera de dichos valores. En otras palabras, el ejemplo busca los títulos con anticipos iguales o superiores al valor mínimo pagado por New Age Books.

Si la subconsulta no devuelve ningún valor, toda la consulta fracasa.

=any significa igual que alguno de los valores

El operador =any es una verificación de existencia que equivale a in . Por ejemplo, para buscar los autores que viven en la misma ciudad que cualquier editor, puede usar =any o in :

select au_lname, au_fname

from authors

where city = any

(select city

from publishers)

select au_lname, au_fname

from authors

where city in

(select city

from publishers)

au_lname au_fname

-------------- --------------

Carson Cheryl

Bennet Abraham

(2 rows affected)

Sin embargo, el operador !=any es diferente a not in . !=any significa "no = a o no = b o no = c". not in significa "no = a y no = b y no = c".

Por ejemplo, digamos que se desea buscar todos los autores que viven en una ciudad donde no hay ningún editor. En tal caso, podría probarse con esta consulta:

Page 83: 80575032 Libro de SQL y Tl SQL Excelente

Page 83 of 280

select au_lname, au_fname

from authors

where city != any

(select city

from publishers)

Los resultados incluyen los 23 autores. Esto se debe a que todos los autores viven en alguna ciudad en la que no hay ningún editor, y cada autor vive en una sola ciudad.

Lo que ocurre es que la consulta interna busca todas las ciudades donde hay editores y luego, para cada ciudad, la consulta externa busca los autores que no viven ahí.

A continuación se ilustra lo que ocurre cuando se usa not in en la misma consulta:

select au_lname, au_fname

from authors

where city not in

(select city

from publishers)

au_lname au_fname

-------------- ------------

del Castillo Innes

Blotchet-Halls Reginald

Gringlesby Burt

DeFrance Michel

Smith Meander

White Johnson

Greene Morningstar

Green Marjorie

Straight Dick

Stringer Dirk

MacFeather Stearns

Karsen Livia

Dull Ann

Hunter Sheryl

Panteley Sylvia

Ringer Anne

Ringer Albert

Locksley Chastity

O'Leary Michael

McBadden Heather

Yokomoto Akiko

(21 rows affected)

Estos son los resultados deseados. Incluyen todos los autores, excepto Cheryl Carson y Abraham Bennet, que viven en Berkeley, donde está la sede de Algodata Infosystems.

Los resultados son los mismos que en el ejemplo anterior si se usa el operador !=all , que equivale a not in :

select au_lname, au_fname

from authors

where city != all

(select city

from publishers)

Uso de subconsultas con in

Las subconsultas introducidas con la palabra clave in devuelven una lista con 0 y valores superiores. Por ejemplo, esta consulta busca los nombres de los editores que publicaron libros de negocios:

select pub_name

from publishers

where pub_id in

(select pub_id

from titles

where type = "business")

Page 84: 80575032 Libro de SQL y Tl SQL Excelente

Page 84 of 280

pub_name

----------------------------------------

New Age Books

Algodata Infosystems

(2 rows affected)

Esta instrucción se evalúa en dos pasos. En primer lugar, la consulta interna devuelve los números de identificación de los editores que publicaron libros de negocios, 1389 y 0736. En segundo lugar, estos valores se usan en la consulta externa, que busca los nombres correspondientes a los números de identificación en la tabla publishers . Este es el aspecto de la consulta:

select pub_name

from publishers

where pub_id in ("1389", "0736")

Esta es otra manera de formular la consulta mediante una subconsulta:

select pub_name

from publishers

where "business" in

(select type

from titles

where pub_id = publishers.pub_id)

Tenga presente que la expresión que sigue a la palabra clave where de la consulta externa puede ser una constante, además de un nombre de columna. Es posible utilizar otros tipos de expresiones, como las combinaciones de constantes y nombres de columna.

Las consultas anteriores, al igual que muchas otras subconsultas, pueden formularse alternativamente como consultas de combinación:

select distinct pub_name

from publishers, titles

where publishers.pub_id = titles.pub_id

and type = "business"

Tanto esta consulta como las versiones de subconsulta encuentran editores que publicaron libros de negocios. Todas son correctas y generan los mismos resultados, pero quizás sea necesario usar la palabra clave distinct para eliminar los duplicados.

Sin embargo, una ventaja del uso de una consulta de combinación, para este problema y otros similares, en lugar de una subconsulta, es que la consulta de combinación muestra columnas de varias tablas en los resultados. Por ejemplo, para incluir los títulos de los libros de negocios en el resultado, tendría que emplear esta combinación:

select pub_name, title

from publishers, titles

where publishers.pub_id = titles.pub_id

and type = "business"

pub_name title

-------------------- ----------------------------------------

Algodata Infosystems The Busy Executive's Database Guide

Algodata Infosystems Cooking with Computers: Surreptitious

Balance Sheets

New Age Books You Can Combat Computer Stress!

Algodata Infosystems Straight Talk About Computers

(4 rows affected)

El siguiente es otro ejemplo de instrucción que puede formularse con una subconsulta o con una consulta de combinación. La versión de la consulta es: "buscar los nombres de todos los autores secundarios que vivan en California y reciban menos del 30 por cien de los derechos de autor por un libro". Con una subconsulta, la instrucción es:

select au_lname, au_fname

from authors

where state = "CA"

and au_id in

(select au_id

Page 85: 80575032 Libro de SQL y Tl SQL Excelente

Page 85 of 280

from titleauthor

where royaltyper < 30

and au_ord = 2)

au_lname au_fname

------------------------ ------------

MacFeather Stearns

(1 row affected)

La consulta externa genera una lista de los 15 autores que viven en California. A continuación, se evalúa la consulta interna que genera una lista con las IDs de los autores que cumplen con las calificaciones.

Observe que es posible incluir más de una condición en la cláusula where , tanto de la consulta interna como de la externa.

Con una combinación, la consulta se expresa de esta manera:

select au_lname, au_fname

from authors, titleauthor

where state = "CA"

and authors.au_id = titleauthor.au_id

and royaltyper < 30

and au_ord = 2

Una combinación siempre puede expresarse como una subconsulta. Una subconsulta puede expresarse frecuentemente como una combinación.

Uso de subconsultas con not in

Las subconsultas introducidas por la frase de palabras clave not in también devuelven una lista con 0 y valores superiores. not in significa "no = a y no = b y not = c".

Esta consulta busca los nombres de los editores que no han editado libros de negocios, lo contrario del ejemplo de "Uso de subconsultas con in":

select pub_name from publishers

where pub_id not in

(select pub_id

from titles

where type = "business")

pub_name

----------------------------------------

Binnet & Hardley

(1 row affected)

La consulta es exactamente igual a la anterior, con la excepción de que not in sustituye a in . S in embargo, esta instrucción no puede convertirse en una combinación. La combinación análoga "no igual" tiene un significado diferente: busca los nombres de los editores que publicaron algún libro que no sea de negocios. Las dificultades para interpretar el significado de las combinaciones no basadas en la igualdad se explican con más detalle en el Capítulo 4, "Combinaciones: recuperación de datos de varias tablas".

Uso de subconsultas con not in y NULL

Una subconsulta que utiliza not in devuelve un conjunto de valores para cada fila de la consulta externa. Si el valor de esta consulta no se encuentra en el conjunto devuelto por la consulta interna, not in da como resultado TRUE (verdadero) y la consulta externa sitúa el registro en cuestión en los resultados.

Sin embargo, si el conjunto devuelto por la consulta interna no contiene ningún valor coincidente, pero contiene uno NULL, not in devuelve UNKNOWN (desconocido). Esto se debe a que NULL significa "valor desconocido" y es imposible saber si el valor que se está buscando se encuentra en un conjunto con un valor desconocido. La consulta externa omite la fila.

Por ejemplo, si se usa la base de datos pubs2 :

select pub_name

from publishers

Page 86: 80575032 Libro de SQL y Tl SQL Excelente

Page 86 of 280

where $100.00 not in

(select price

from titles

where titles.pub_id = publishers.pub_id)

el resultado es:

pub_name

------

New Age Books

New Age Books es el único editor que no publica libros cuyo precio es de $100. Binnet & Handley y Algodata Infosystems no aparecen en los resultados de la consulta porque ambos publican un libro cuyo precio no está decidido.

Uso de subconsultas con exists

Una subconsulta introducida con la palabra clave exists funciona como una prueba de existencia . En otras palabras, la cláusula where de la consulta externa comprueba la existencia de las filas devueltas por la subconsulta. La subconsulta no genera datos reales, sino que devuelve un valor TRUE (verdadero) o FALSE (falso).

Por ejemplo, la siguiente consulta busca los nombres de todos los editores que publican libros de negocios:

select pub_name

from publishers

where exists

(select *

from titles

where pub_id = publishers.pub_id

and type = "business")

pub_name

----------------------------------------

New Age Books

Algodata Infosystems

(2 rows affected)

Para conceptualizar la solución de esta consulta, tenga en cuenta el nombre de cada editor. Este valor, ¿hace que la subconsulta devuelva al menos una fila?. En otras palabras, ¿hace que la prueba de existencia de como resultado TRUE?.

En los resultados de la consulta anterior, el segundo nombre de editor es Algodata Infosystems, cuyo número de identificación es 1389. ¿Hay alguna fila en la tabla titles en la que pub_id sea 1389 y type sea "business"?. En caso afirmativo, "Algodata Infosystems" debería ser uno de los valores seleccionados. El mismo proceso se repite con los nombres de cada uno de los demás editores.

Las subconsultas introducidas por exists se diferencian de otras subconsultas en lo siguiente:

La palabra clave exists no va precedida de nombres de columna, constantes ni otras expresiones.

La subconsulta exists da como resultado TRUE o FALSE en lugar de devolver datos.

La lista de selección de la subconsulta consiste generalmente de un asterisco (*). No es necesario especificar nombres de columna, ya que simplemente se está comprobando la existencia o inexistencia de filas que cumplen las condiciones especificadas en la subconsulta. De lo contrario, las reglas de lista de selección de una subconsulta introducida con exists son idénticas a las de una lista de selección estándar.

La palabra clave exists es muy importante, porque a menudo no hay ninguna formulación alternativa de no subconsulta. En la práctica, una subconsulta introducida con exists siempre es una subconsulta correlacionada (consulte "Uso de subconsultas correlacionadas").

Aunque algunas consultas formuladas con exists no pueden expresarse de ninguna otra forma, todas las consultas que utilizan in o un operador de comparación modificado por any o all pueden expresarse con exists . A continuación se muestran algunos ejemplos de instrucciones que usan exists y sus alternativas equivalentes.

He aquí dos formas de buscar los autores que viven en la misma ciudad que un editor:

Page 87: 80575032 Libro de SQL y Tl SQL Excelente

Page 87 of 280

select au_lname, au_fname

from authors

where city =any

(select city

from publishers)

select au_lname, au_fname

from authors

where exists

(select *

from publishers

where authors.city = publishers.city)

au_lname au_fname

-------------- --------------

Carson Cheryl

Bennet Abraham

(2 rows affected)

He aquí dos consultas que buscan los títulos de libros publicados por cualquier editor ubicado en una ciudad cuya inicial sea "B":

select title

from titles

where exists

(select *

from publishers

where pub_id = titles.pub_id

and city like "B%")

select title

from titles

where pub_id in

(select pub_id

from publishers

where city like "B%")

title

---------------------------------------------------

The Busy Executive's Database Guide

Cooking with Computers: Surreptitious Balance

Sheets

You Can Combat Computer Stress!

Straight Talk About Computers

But Is It User Friendly?

Secrets of Silicon Valley

Net Etiquette

Is Anger the Enemy?

Life Without Fear

Prolonged Data Deprivation: Four Case Studies

Emotional Security: A New Algorithm

(11 rows affected)

Uso de subconsultas con not exist s

not exists es exactamente igual que exists , con la excepción de que la cláusula where donde se usa acepta que la subconsulta no devuelva ninguna fila.

Por ejemplo, para buscar los nombres de los editores que no publican libros de negocios, la consulta es:

select pub_name

from publishers

where not exists

(select *

from titles

where pub_id = publishers.pub_id

and type = "business")

pub_name

----------------------------------------

Binnet & Hardley

(1 row affected)

Page 88: 80575032 Libro de SQL y Tl SQL Excelente

Page 88 of 280

Esta consulta busca los títulos que no registran ninguna venta:

select title

from titles

where not exists

(select title_id

from salesdetail

where title_id = titles.title_id)

title

-----------------------------------------

The Psychology of Computer Cooking

Net Etiquette

(2 rows affected)

Búsqueda de intersecciones y diferencias con exists

Las subconsultas introducidas con exists y not exists pueden usarse para dos operaciones de la teoría de conjuntos: intersección y diferencia. La intersección de dos conjuntos contiene todos los elementos pertenecientes a los dos conjuntos originales. La diferencia contiene los elementos pertenecientes sólo al primero de los dos conjuntos.

La intersección de authors y publishers en la columna city es el conjunto de ciudades en las que hay un autor y un editor:

select distinct city

from authors

where exists

(select *

from publishers

where authors.city = publishers.city)

city

--------------------

Berkeley

(1 row affected)

La diferencia entre authors y publishers en la columna city es el conjunto de ciudades donde vive un autor pero no hay ningún editor, es decir, todas las ciudades excepto Berkeley:

select distinct city

from authors

where not exists

(select *

from publishers

where authors.city = publishers.city)

city

--------------------

Gary

Covelo

Oakland

Lawrence

San Jose

Ann Arbor

Corvallis

Nashville

Palo Alto

Rockville

Vacaville

Menlo Park

Walnut Creek

San Francisco

Salt Lake City

(15 rows affected)

Uso de subconsultas correlacionadas

Muchas de las consultas anteriores podrían evaluarse ejecutando la subconsulta una vez, y usando los valores resultantes en la cláusula where de la consulta externa; se trata de subconsultas no correlacionadas. En las consultas que incluyen una

Page 89: 80575032 Libro de SQL y Tl SQL Excelente

Page 89 of 280

subconsulta repetida, o subconsulta correlacionada , la subconsulta depende de la consulta externa para obtener sus valores. Esto significa que la subconsulta se ejecuta de forma iterativa, una vez para cada una de las filas seleccionadas por la consulta externa.

Con esta consulta pueden buscarse los nombres de todos los autores que ganan un 100% de derechos de autor sobre un libro:

select au_lname, au_fname

from authors

where 100 in

(select royaltyper

from titleauthor

where au_id = authors.au_id)

au_lname au_fname

-------------- ----------

Carson Cheryl

Ringer Albert

Straight Dick

White Johnson

Green Marjorie

Panteley Sylvia

Locksley Chastity

del Castillo Innes

Blotchet-Hall Reginald

(9 rows affected)

Al contrario de lo que ocurre en la mayor parte de las subconsultas anteriores, la subconsulta de esta instrucción no puede resolverse de forma independiente con respecto a la consulta principal. Dicha subconsulta precisa un valor para authors . au_id , pero este valor es una variable: cambia a medida que SQL Server examina las distintas filas de la tabla authors .

Este es el modo en que se evalúa la consulta anterior: Transact-SQL tiene en cuenta todas las filas de la tabla authors para su inclusión en los resultados utilizando el valor de cada fila para la consulta interna. Por ejemplo, supongamos que Transact-SQL examina primero la fila de Cheryl Carson. A continuación, authors.au_id toma el valor "238-95-7766", que Transact-SQL usa para la consulta interna:

select royaltyper

from titleauthor

where au_id = "238-95-7766"

El resultado es 100, de forma que la consulta externa evalúa como:

select au_lname, au_fname

from authors

where 100 in (100)

Dado que la condición where es verdadera, la fila de Cheryl Carson se incluye en los resultados. Si se realiza el mismo procedimiento con la fila de Abraham Bennet, observará que esta fila no aparece en los resultados.

Subconsultas correlacionadas con nombres de correlación

Una subconsulta correlacionada puede usarse para buscar los tipos de libros publicados por más de un editor:

select distinct t1.type

from titles t1

where t1.type in

(select t2.type

from titles t2

where t1.pub_id != t2.pub_id)

type

--------------------

business

psychology

(2 rows affected)

Para distinguir los dos roles donde aparece la tabla titles , son necesarios los nombres de correlación en la consulta siguiente. Esta consulta anidada equivale a la consulta de autocombinación:

Page 90: 80575032 Libro de SQL y Tl SQL Excelente

Page 90 of 280

select distinct t1.type

from titles t1, titles t2

where t1.type = t2.type

and t1.pub_id != t2.pub_id

Subconsultas correlacionadas con operadores de comparación

Las subconsultas de expresión pueden ser subconsultas correlacionadas. Por ejemplo, para buscar las ventas de libros de psicología donde la cantidad es menor que el promedio de ventas de ese título:

select s1.ord_num, s1.title_id, s1.qty

from salesdetail s1

where title_id like "PS%"

and s1.qty <

(select avg(s2.qty)

from salesdetail s2

where s2.title_id = s1.title_id)

A continuación se muestran los resultados de esta consulta:

ord_num title_id qty

------------------ -------- ---

91-A-7 PS3333 90

91-A-7 PS2106 30

55-V-7 PS2106 31

AX-532-FED-452-2Z7 PS7777 125

BA71224 PS7777 200

NB-3.142 PS2091 200

NB-3.142 PS7777 250

NB-3.142 PS3333 345

ZD-123-DFG-752-9G8 PS3333 750

91-A-7 PS7777 180

356921 PS3333 200

(11 rows affected)

La consulta externa selecciona las filas de la tabla sales (o "s1" ) una a una. La subconsulta calcula la cantidad promedio de cada venta considerada para su selección en la consulta externa. Por cada valor posible de s1 , Transact-SQL evalúa la subconsulta e incluye el registro considerado en los resultados, si la cantidad es inferior al promedio calculado.

En algunos casos una subconsulta correlacionada es como una instrucción group by . Para buscar los títulos cuyo precio es mayor que el promedio correspondiente a los libros de su mismo tipo, esta sería la consulta:

select t1.type, t1.title

from titles t1

where t1.price >

(select avg(t2.price)

from titles t2

where t1.type = t2.type)

type title

--------- --------------------------------------

business The Busy Executive's Database Guide

business Straight Talk About Computers

mod_cook Silicon Valley Gastronomic Treats

popular_comp But Is It User Friendly?

psychology Computer Phobic and Non-Phobic

Individuals: Behavior Variations

psychology Prolonged Data Deprivation: Four Case

Studies

trad_cook Onions, Leeks, and Garlic: Cooking

Secrets of the Mediterranean

(7 rows affected)

Por cada valor posible de t1 , Transact-SQL evalúa la subconsulta e incluye la fila en los resultados, si el valor del precio correspondiente a esa fila es mayor que el promedio calculado. No es necesario agrupar por tipos explícitamente, porque las filas para las que se calcula el promedio del precio están restringidas por la cláusula where de la subconsulta.

Page 91: 80575032 Libro de SQL y Tl SQL Excelente

Page 91 of 280

Subconsultas correlacionadas en una cláusula having

Las subconsultas de predicado cuantificado pueden ser subconsultas correlacionadas.

Este ejemplo de una subconsulta correlacionada en la cláusula having de una consulta externa busca los tipos de libros cuyo máximo anticipo es más del doble del promedio de un grupo dado:

select t1.type

from titles t1

group by t1.type

having max(t1.advance) >=any

(select 2 * avg(t2.advance)

from titles t2

where t1.type = t2.type)

type

----------

mod_cook

(1 row affected)

En este caso, la subconsulta se evalúa una vez para cada grupo definido en la consulta externa, es decir, una vez para cada tipo de libro.

Chapter 6

Uso y creación de tipos de datos

Es posible utilizar los tipos de datos del sistema SQL Server al definir una columna en las instrucciones create table o alter table , una variable en la instrucción declare , o un parámetro en la instrucción create procedure . Dichos comandos se describen más adelante en este manual. También es posible crear y utilizar tipos de datos definidos por el usuario en esos comandos.

Este capítulo trata lo siguiente:

Introducción general a los tipos de datos

Los distintos tipos de datos del sistema suministrados por SQL Server

Cómo realizar conversiones entre tipos de datos

Cómo funciona la aritmética de modo mixto en la jerarquía de tipos de datos

Cómo crear tipos de datos definidos por el usuario

Cómo obtener información acerca de un tipo de datos

¿Qué son los tipos de datos Transact-SQL?

Uso de tipos de datos suministrados por el sistema

Conversión de tipos de datos

Aritmética de modo mixto y jerarquía de tipos de datos

Creación de tipos de datos definidos por el usuario

Obtención de información sobre tipos de datos

¿Qué son los tipos de datos Transact-SQL?

En Transact-SQL, los tipos de datos especifican el tipo de información, tamaño y formato de almacenamiento de columnas de tablas, parámetros de procedimientos almacenados y variables locales. Por ejemplo, el tipo de datos entero ( int ) se emplea para guardar números enteros que pertenezcan al margen de más o menos 231, y el tipo de datos entero diminuto ( tinyint ) almacena sólo los números enteros comprendidos entre 0 y 255.

SQL Server suministra algunos tipos de datos del sistema y dos tipos de datos definidos por el usuario: timestamp y sysname . Es posible utilizar el procedimiento del sistema sp_addtype para crear tipos de datos definidos por el usuarios en base a los tipos de datos del sistema (los tipos de datos definidos por el usuario se describen en "Creación de tipos de datos definidos por el usuario").

Page 92: 80575032 Libro de SQL y Tl SQL Excelente

Page 92 of 280

Es preciso especificar un tipo de datos del sistema o uno definido por el usuario al declarar una columna, una variable local o un parámetro. En el siguiente ejemplo, se utilizan los tipos de datos del sistema char , numeric y money para definir las columnas en la instrucción create table :

create table sales_daily

(stor_id char(4)

ord_num numeric(10,0)

ord_amt money)

En el ejemplo siguiente, se utiliza el tipo de datos del sistema bit para definir la variable local en la instrucción declare :

declare @switch bit

En capítulos posteriores se describe con más detalle cómo declarar columnas, variables locales y parámetros utilizando los tipos de datos descritos en este capítulo. Para determinar los tipos de datos definidos para las columnas de tablas existentes, use el procedimiento del sistema sp_help .

Uso de tipos de datos suministrados por el sistema

La tabla siguiente enumera los tipos de datos suministrados por el sistema para distintos tipos de información, los sinónimos reconocidos por SQL Server, y el margen y tamaño de almacenamiento de cada uno. Los tipos de datos del sistema se imprimen en minúsculas, aunque SQL Server permite introducirlos en mayúsculas o en minúsculas. ( timestamp y sysname , como todos los tipos de datos definidos por el usuario, pueden utilizarse en mayúsculas o minúsculas.) La mayoría de los tipos de datos suministrados por SQL Server no son palabras reservadas y pueden utilizarse para asignar nombre a otros objetos.

Tabla 6-1: Tipos de datos del sistema SQL Server

Tipos de datos por categoría

Sinónimos Margen Bytes de almacenamiento

Numéricos exactos: enteros

tinyint

smallint

int

integer

0 a 255

215 -1 (32.767) a -215 (-32.768)

231 -1 (2.147.483.647) a -231 (-2.147.483.648)

1

2

4

Numéricos exactos: decimales

numeric (p, s)

decimal (p, s)

dec

1038 -1 a -1038

1038 -1 a -1038

2 a 17

2 a 17

Numéricos aproximados

float (precision)

double precision

real

dependiente de la máquina

dependiente de la máquina

dependiente de la máquina

4 u 8

8

4

Monetarios

smallmoney

money

214.748,3647 a -214.748,3648

922.337.203.685.477,5807 a -922.337.203.685.477,5808

4

8

Fecha/hora

smalldatetime

datetime

Del 1 de enero de 1900 al 6 de junio de 2079

Del 1 de enero de 1753 al 31 de diciembre de 9999

4

8

Caracteres

Page 93: 80575032 Libro de SQL y Tl SQL Excelente

Page 93 of 280

char(n)

varchar(n)

nchar(n)

nvarchar(n)

text

character

character varying, char varying

national character, national char

nchar varying, national char varying, national character varying

255 caracteres o menos

255 caracteres o menos

255 caracteres o menos

255 caracteres o menos

231 -1 (2.147.483.647) bytes o menos

n

longitud de entrada real

n * @@ncharsize

@@ncharsize * número de caracteres

0 o múltiplo de 2K

Binarios

binary(n)

varbinary(n)

image

255 bytes o menos

255 bytes o menos

231 -1 (2.147.483.647) bytes o menos

n

longitud de entrada real

0 o múltiplo de 2K

Bit

bit 0 o 1 1 (un byte contiene hasta 8 columnas bit )

A continuación, se describe cada tipo de datos.

Tipos numéricos exactos: enteros

SQL Server proporciona tres tipos de datos, tinyint , smallint e int para almacenar enteros (números enteros). Estos tipos son numéricos exactos, ya que mantienen su precisión durante las operaciones aritméticas.

Elija el tipo de entero en base al tamaño previsto de los números que van a almacenarse. El tamaño de almacenamiento interno varía en función del tipo de datos.

Tabla 6-2: Tipos de datos enteros

Tipo de datos

Almacena Bytes de almacenamiento

tinyint Números enteros entre 0 y 255, ambos incluidos. (No se admiten números negativos.)

1

smallint Números enteros entre 215 -1 y -215 (32.767 y -32.768), ambos incluidos.

2

int Números enteros entre 231 - 1 y -231 (2.147.483.647 y -2.147.483.648), ambos incluidos.

4

Tipos numéricos exactos: números decimales

SQL Server proporciona dos tipos de datos numéricos exactos adicionales: numeric y decimal , para números que incluyen comas decimales. Los datos almacenados en las columnas numeric y decimal se comprimen para ahorrar espacio en disco, y conservan su precisión hasta el dígito de menor significación después de realizar operaciones aritméticas. Los tipos numeric y decimal son idénticos en todos los aspectos, excepto uno: sólo los tipos numeric con una escala de 0 pueden utilizarse para la columna IDENTITY.

Los tipos numéricos exactos aceptan dos parámetros opcionales: p recision y scale , incluidos entre paréntesis y separados por una coma:

datatype [( precision [, scale ])]

SQL Server define cada combinación de precisión y escala como un tipo de datos distinto. Por ejemplo, numeric (10,0) y numeric (5,0) son dos tipos de datos diferentes. La precisión y la escala determinan el margen de valores que puede almacenarse en una columna decimal o numeric :

Page 94: 80575032 Libro de SQL y Tl SQL Excelente

Page 94 of 280

La precisión especifica el número máximo de dígitos decimales que pueden almacenarse en la columna e incluye todos los dígitos a la derecha o a la izquierda de la coma decimal. Es posible especificar una precisión de 1 a 38 dígitos, o utilizar la precisión predeterminada de 18 dígitos.

La escala especifica el número máximo de dígitos que pueden almacenarse a la derecha de la coma decimal. Observe que la escala debe ser menor o igual que la precisión. Es posible especificar una escala de 0 a 38 dígitos, o utilizar la escala predeterminada de 0 dígitos.

Los tipos numéricos exactos con una escala de 0 se muestran sin coma decimal. Si se introduce un valor que supera la precisión o la escala para la columna, SQL Server señala la entrada como un error.

El tamaño de almacenamiento para una columna numeric o decimal depende de su precisión. El requisito mínimo de almacenamiento es de 2 bytes para una columna de 1 o 2 dígitos. El tamaño de almacenamiento aumenta 1 byte por cada 2 dígitos adicionales de precisión, hasta un máximo de 17 bytes.

Tipos de datos numéricos aproximados

SQL Server proporciona tres tipos numéricos aproximados: float , double precision y real , para datos numéricos que pueden tolerar el redondeo durante operaciones aritméticas. Utilice los tipos de datos numéricos aproximados para datos que cubran un amplio margen de valores. Estos admiten todas las funciones agregadas y todas las operaciones aritméticas, excepto módulo (%).

Los tipos de datos real y double precision se crean en base a tipos suministrados por el sistema operativo. El tipo float acepta una precisión opcional entre paréntesis. Las columnas float con una precisión de 1-15 se almacenan como real ; las que tienen una precisión superior se almacenan como double precision . La precisión de margen y almacenamiento para los tres tipos depende de la máquina.

En la tabla siguiente se muestra el margen, la precisión de visualización y el tamaño de almacenamiento para cada tipo numérico aproximado. Observe que isql sólo muestra seis números significativos después de la coma decimal y que redondea el resto:

Tabla 6-3: Tipos de datos numéricos aproximados

Tipo de datos Bytes de almacenamiento

float [( default precision )] 4 para d efault precision < 16, 8 para d efault precision >= 16

double precision 8

real 4

Tipos de datos de caracteres

Utilice los tipos de datos de caracteres para almacenar cadenas compuestas de letras, números y símbolos incluidos entre comillas simples o dobles . La palabra clave like puede utilizarse para buscar determinados caracteres en estas cadenas y las funciones de cadena incorporadas a fin de manipular su contenido. Las cadenas compuestas de números pueden convertirse a tipos de datos numéricos exactos y aproximados con la función convert , y utilizarse posteriormente en operaciones aritméticas.

El tipo de datos char ( n ) almacena cadenas de longitud fija y el tipo de datos varchar ( n ) almacena cadenas de longitud variable, en juegos de caracteres de un solo byte, como English. Sus parejas de caracteres nacionales, nchar ( n ) y nvarchar ( n ) , almacenan cadenas de longitud fija y variable en juegos de caracteres multibyte, como Japanese . Es posible especificar el número máximo de caracteres con n , o utilizar la longitud de columna predeterminada de un carácter. Para cadenas más largas que bytes, utilice el tipo de datos text .

Tabla 6-4: Tipos de datos de caracteres

Tipo de datos

Almacena Bytes de almacenamiento

char(n) Datos de longitud fija, como números de seguridad social o códigos postales

n

varchar(n) Datos, como nombres, cuya longitud puede variar considerablemente

Número real de caracteres introducidos

nchar(n) Datos de longitud fija en juegos de caracteres multibyte n * @@ncharsize

Page 95: 80575032 Libro de SQL y Tl SQL Excelente

Page 95 of 280

nvarchar(n) Datos de longitud variable en juegos de caracteres multibyte Número real de caracteres * @@ncharsize

text Hasta 2.147.483.647 bytes de caracteres imprimibles en listas enlazadas de páginas de datos

0 sin inicializar; un múltiplo de 2K después de la inicialización

SQL Server trunca las entradas según la longitud de columna especificada sin indicar ningún mensaje de advertencia o error, a menos que se defina string_rtruncation on . Consulte el comando set en el Manual de Referencia de SQL Server para obtener más información. La cadena vacía , "" or '' , se almacena como un espacio único en lugar de como NULL. De este modo, "abc" + "" + "def" es equivalente a "abc def", no a "abcdef".

El comportamiento de las columnas de longitud fija y variable es algo distinto:

Los datos de las columnas de longitud fija se rellenan con espacios en blanco hasta la longitud de columna. Para el tipo de datos char , el tamaño de almacenamiento es n bytes; para el tipo de datos nchar , es n veces la longitud de caracteres nacionales promedio ( @@ncharsize ). Al crear una columna char o nchar que permite valores nulos, SQL Server la convierte automáticamente en una columna varchar o nvarchar y utiliza las reglas de almacenamiento para dichos tipos de datos. (No ocurre así para las variables y parámetros char y nchar .)

Los datos de las columnas de longitud variable se despojan de los espacios en blanco posteriores; el tamaño de almacenamiento es la longitud real de los datos. Para columnas varchar , es el número de caracteres; para columnas nvarchar , es el número de caracteres por la longitud de caracteres promedio. Los datos de caracteres de longitud variable necesitan menos espacio que los de longitud fija, pero el acceso a ellos es algo más lento.

El tipo de datos text almacena hasta 2.147.483.647 bytes de caracteres imprimibles en listas enlazadas de páginas de datos independientes. Para ahorrar espacio de almacenamiento, defina las columnas text como NULL. Al inicializar una columna text con un comando insert o update no nulo, SQL Server asigna un puntero de texto y una página completa de datos de 2K para contener el valor. Cada página almacena un máximo de 1.800 bytes de datos. Para añadir datos sin guardar grandes bloques de texto en el diario de transacciones, utilice writetext . Consulte el Manual de Referencia de SQL Server para obtener información detallada.

Tipos de datos binarios

Los tipos de datos binarios almacenan datos binarios en bruto, como imágenes, en una notación semejante a la hexadecimal. Los datos binarios comienzan con los caracteres "0x" e incluyen cualquier combinación de dígitos, así como las letras A-F mayúsculas y minúsculas.

Note: SQL Server manipula los tipos binarios según el tipo específico de plataforma. Para datos hexadecimales reales, utilice las funciones hextoint y inttohex . Consulte el Capítulo 10, "Uso de funciones incorporadas en consultas".

Utilice los tipos de datos binary(n) y varbinary(n) para almacenar datos de hasta 255 bytes de longitud. Cada byte de almacenamiento contiene 2 dígitos binarios. Especifique la longitud de columna con n , o utilice la longitud predeterminada de un byte. Si introduce un valor superior a n , SQL Server trunca la entrada en la longitud especificada sin emitir ningún mensaje de advertencia o de error.

Utilice el tipo binario de longitud fija binary(n) , para datos donde se espera que todas las entradas tengan una longitud similar. Debido a que las entradas de las columnas binary se rellenan con ceros en toda la longitud de la columna, es posible que necesiten más espacio de almacenamiento que las de las columnas varbinary , pero el acceso a éstas últimas será algo más rápido.

Utilice el tipo binario de longitud variable varbinary(n) , para datos cuya longitud se espera que varíe en gran medida. El tamaño de almacenamiento es el tamaño real de los valores de datos introducidos, y no la longitud de columna. Los ceros posteriores se truncan.

Al crear una columna binary que admite valores nulos, SQL Server la convierte automáticamente en una columna varbinary y utiliza las reglas de almacenamiento para dicho tipo de datos.

Es posible buscar cadenas de caracteres binarios con la palabra clave like y realizar operaciones con ellas mediante las funciones de cadena incorporadas. Debido a que el formato exacto donde se introduce un valor determinado depende del hardware que esté utilizándose , los cálculos en los que se utilizan datos binarios pueden producir resultados distintos en plataformas diferentes.

Utilice el tipo de datos image para almacenar bloques mayores de datos binarios en páginas de datos externas. Una columna image puede almacenar hasta 2.147.483.647 bytes de datos en listas enlazadas de páginas de datos, aparte de otros datos para la tabla. Al inicializar una columna i mage con un comando insert o update no nulo, SQL Server asigna un puntero de texto y una página completa de datos de 2K para contener el valor. Cada página almacena un máximo de 1.800 bytes.

Page 96: 80575032 Libro de SQL y Tl SQL Excelente

Page 96 of 280

Para ahorrar espacio de almacenamiento, defina las columnas image como NULL. Para añadir datos image sin guardar grandes bloques de texto en el diario de transacciones, utilice writetext . Consulte el Manual de Referencia de SQL Server para obtener información detallada.

En la tabla siguiente se resumen los requisitos de almacenamiento para tipos de datos binarios:

Tabla 6-5: Tipos de datos binarios

Tipo de datos Bytes de almacenamiento

binary(n) n

varbinary(n) Longitud real de entrada

image 0 sin inicializar; un múltiplo de 2K después de la inicialización

Tipos de datos monetarios

Los tipos de datos monetarios money y smallmoney , almacenan datos monetarios. Estos tipos de datos pueden utilizarse para dólares U.S. y para otras monedas decimales, aunque SQL Server no proporciona medios para convertir una moneda a otra. Pueden utilizarse todas las operaciones aritméticas, excepto módulo, y todas las funciones agregadas, con datos money y smallmoney .

La precisión de money y de smallmoney es de hasta 1/10000 de una unidad monetaria, pero los valores se redondean hasta dos posiciones decimales por razones de visualización. El formato de impresión predeterminado coloca un punto detrás de cada tres dígitos.

En la siguiente tabla se resumen los requisitos de margen y almacenamiento para los tipos de datos monetarios:

Tabla 6-6: Tipos de datos monetarios

Tipo de datos Margen Bytes de almacenamiento

money Valores monetarios entre +922.337.203.685.477,5807 y -922.337.203.685.477,5808

8

smallmoney Valores monetarios entre +214.748,3647 y -214.748,3648 4

Tipos de datos de fecha y hora

Utilice los tipos de datos datetime y smalldatetime para almacenar información de fecha y hora desde el 1 de enero de 1753 hasta el 31 de diciembre de 9999. Las fechas que no están comprendidas en este margen deben introducirse, almacenarse y manipularse como valores char o varchar .

Las columnas datetime contienen fechas comprendidas entre el 1 de enero de 1753 y el 31 de diciembre de 9999. Los valores datetime tienen una precisión de hasta 1/300 de segundo en plataformas que admiten este nivel de granularidad. El tamaño de almacenamiento es de 8 bytes: 4 bytes para el número de días desde la fecha base del 1 de enero de 1900, y 4 bytes para la hora del día.

Las columnas smalldatetime contienen fechas comprendidas entre el 1 de enero de 1900 y el 6 de junio de 2079, y su precisión de hasta un minuto. Su tamaño de almacenamiento es de 4 bytes: 2 bytes para el número de días después del 1 de enero de 1900, y 2 bytes para el número de minutos desde medianoche.

La información de fecha y hora debe incluirse entre comillas simples o dobles. Puede introducirse en mayúsculas o en minúsculas, y puede contener espacios entre las partes de los datos. SQL Server reconoce una amplia variedad de formatos de entrada de datos, que se describen en el Capítulo 8. Los valores como cero o 00/00/00, que no se reconocen como fechas, se rechazan.

El formato de visualización predeterminado para las fechas es "Apr 15 1987 10:23PM". Es posible utilizar la función convert para unificar más estilos de visualización de fechas. También es posible realizar algunos cálculos aritméticos con valores datetime mediante las funciones de fecha incorporadas.

En la tabla siguiente se resumen los requisitos de margen y de almacenamiento para los tipos de datos de fecha:

Tabla 6-7: Tipos de datos de fecha

Page 97: 80575032 Libro de SQL y Tl SQL Excelente

Page 97 of 280

Tipo de datos Margen Bytes de almacenamiento

datetime Del 1 de enero de 1753 al 31 de diciembre de 9999 8

smalldatetime Del 1 de enero de 1900 al 6 de junio de 2079 4

Tipo de datos bit

Utilice columnas bit para tipos de datos verdadero/falso o sí/no. Las columnas bit contienen los valores 0 o 1. Se admiten los valores enteros distintos de 0 o 1, pero siempre se interpretan como 1. El tamaño de almacenamiento es de 1 byte. Los tipos de datos bit múltiples de una tabla se agrupan en bytes. Por ejemplo, 7 columnas bit caben en 1 byte; 9 columnas bit necesitan 2 bytes.

Las columnas de tipo de datos bit no pueden ser NULL y no pueden tener índices. La columna status de la tabla del sistema syscolumns indica la posición de desplazamiento exclusiva para las columnas bit.

Tipo de datos timestamp

SQL Server también suministra el tipo de datos definido por el usuario timestamp . Las columnas timestamp son necesarias en tablas a examinarse en aplicaciones Open Client(TM) DB-Library(TM).

Cada vez que se inserta o actualiza una fila con una columna timestamp , la columna timestamp se actualiza automáticamente. Una tabla sólo puede tener una columna del tipo de datos timestamp . Una columna llamada timestamp tendrá automáticamente el tipo de datos del sistema timestamp . Su definición es varbinary (8) NULL.

Debido a que timestamp es un tipo de datos definido por el usuario, no puede utilizarse para definir otros tipos de datos definidos por el usuario. Es preciso introducirlo como "timestamp", con todas las letras en minúsculas.

Tipo de datos sysname

sysname es un tipo de datos definido por el usuario incluido en la cinta de instalación de SQL Server y se utiliza en las tablas del sistema. Su definición es:

varchar(30) "not null"

No es posible utilizar el tipo de datos sysname para crear una columna. Sin embargo, se puede crear un tipo de datos definido por el usuario con un tipo base de sysname y, luego, se puede emplear el tipo de datos definido por el usuario para crear columnas. Para obtener más información acerca de los tipos de datos definidos por el usuario, consulte "Creación de tipos de datos definidos por el usuario".

Conversión de tipos de datos

SQL Server maneja automáticamente muchas conversiones de un tipo de datos a otro. Estas conversiones se denominan implícitas. Es posible solicitar explícitamente otras conversiones con las funciones convert , inttohex y hextoint . Sin embargo, no es posible realizar otras conversiones, ni explícita ni automáticamente, debido a incompatibilidades entre los tipos de datos.

Por ejemplo, SQL Server convierte automáticamente expresiones char en datetime por razones de comparación, si pueden interpretarse como valores datetime , pero es necesario utilizar la función convert para convertir char en int . De forma similar, si desea que SQL Server trate los datos enteros como datos de caracteres, hay que usar convert para poder emplear la palabra clave like con ellos.

La sintaxis de la función convert es:

convert ( datatype , expression , [ style ])

Por ejemplo:

select title, total_sales

from titles

where convert (char(20), total_sales) like "2%"

Page 98: 80575032 Libro de SQL y Tl SQL Excelente

Page 98 of 280

El parámetro style opcional se utiliza para convertir valores datetime en tipos de datos char o varchar , a fin de obtener una amplia variedad de formatos de visualización de fecha.

Consulte el Capítulo 10 para obtener información detallada sobre las funciones convert , inttohex y hextoint .

Aritmética de modo mixto y jerarquía de tipos de datos

Al realizar operaciones aritméticas con valores de distintos tipos de datos, SQL Server debe determinar el tipo de datos y, en algunos casos, la longitud y precisión del resultado.

Cada tipo de datos del sistema tiene una jerarquía de tipos de datos , que se almacena en la tabla del sistema systypes . Los tipos de datos definidos por el usuario heredan la jerarquía del tipo del sistema en el que están basados.

La siguiente consulta establece una jerarquía de los tipos de datos de una base de datos. Además de la información que se muestra a continuación, los resultados de la consulta incluirán información sobre cualquier tipo de datos definido por el usuario de la base de datos:

select name,hierarchy

from systypes

order by hierarchy

name hierarchy

------------------------------ -------

floatn 1

float 2

datetimn 3

datetime 4

real 5

numericn 6

numeric 7

decimaln 8

decimal 9

moneyn 10

money 11

smallmoney 12

smalldatetime 13

intn 14

int 15

smallint 16

tinyint 17

bit 18

varchar 19

sysname 19

nvarchar 19

char 20

nchar 20

varbinary 21

timestamp 21

binary 22

text 23

image 24

(28 rows affected)

La jerarquía de tipos de datos determina el resultado de los cálculos en que se utilizan distintos tipos de datos. Al valor resultante se le asigna el tipo de datos más cercano al principio de la lista.

En el ejemplo siguiente, qty de la tabla sales se multiplica por royalty de la tabla roysched . qty es del tipo de datos smallint , cuya jerarquía es 16; royalty es del tipo de datos int , cuya jerarquía es 15. De este modo, el tipo de datos del resultado es int .

smallint(qty) * int(royalty) = int

Uso de tipos de datos money

Si está combinando money junto con literales o variables, y necesita obtener resultados del tipo money , emplee literales o variables money :

select moneycol * $2.5 from mytable

Page 99: 80575032 Libro de SQL y Tl SQL Excelente

Page 99 of 280

Si está combinando m oney con tipos de datos float o numeric de valores de columna, utilice la función convert :

select convert (money, moneycol * percentcol)

from debts, interest

Determinación de la precisión y la escala

Para los tipos numeric y decimal , cada combinación de precisión y escala es un tipo de datos de SQL Server distinto. Si realiza operaciones aritméticas con dos valores numeric o decimal , n1 con la precisión p1 y la escala s1, y n2 con la precisión p2 y la escala s2, SQL Server determina la precisión y escala de los resultados como se indica a continuación:

Tabla 6-8: Precisión y escala después de realizar operaciones aritmética

Operación Precisión Escala

n1 + n2 máx(s1, s2) + máx(p1 -s1, p2 - s2) + 1 máx(s1, s2)

n1 - n2 máx(s1, s2) + máx(p1 -s1, p2 - s2) + 1 máx(s1, s2)

n1 * n2 s1 + s2 + (p1 - s1) + (p2 - s2) + 1 s1 + s2

n1 / n2 máx(s1 + p2 + 1, 6) + p1 - s1 + p2 máx(s1 + p2 -s2 + 1, 6)

Creación de tipos de datos definidos por el usuario

Si se mejora Transact-SQL al nivel de SQL se puede poner nombre y diseñar tipos de datos propios para complementar los tipos de datos del sistema. Un tipo de datos definido por el usuario se define en función de los tipos de datos del sistema. Es posible asignar un nombre a una definición de tipo de datos de uso frecuente. Esto facilita la adaptación personalizada de tipos de datos a las columnas.

Note: Para utilizar un tipo de datos definido por el usuario en más de una base de datos, créelo en la base de datos m odel . De este modo todas las bases de datos creadas reconocerán la definición del tipo de datos definido por el usuario.

Al definir un tipo de datos, puede utilizarse como el tipo de datos para cualquier columna de la base de datos. Por ejemplo, tid se emplea como el tipo de datos para columnas de varias tablas de pubs2 : titles . title_id , titleauthor.title_id , sales . title_id y roysched.title_id.

La ventaja de los tipos de datos definidos por el usuario reside en que es posible vincularles reglas y valores predeterminados para utilizarlos en varias tablas. Para obtener más información sobre este tema, consulte el Capítulo 12.

El procedimiento del sistema sp_addtype se utiliza para crear tipos de datos de usuario. Toma como parámetros el nombre del tipo de datos de usuario que está creándose, el tipo de datos suministrado por SQL Server a partir del que está creándose, y una especificación NULL, NOT NULL o IDENTITY opcional.

Se puede crear un tipo de datos definido por el usuario utilizando cualquier tipo de datos del sistema menos t imestamp . Los tipos de datos definidos por el usuario tienen la misma jerarquía de tipos de datos que los tipos de datos del sistema en que están basados. Pero, a diferencia de los tipos de datos suministrados por SQL Server, los nombres de los tipos de datos definidos por el usuario distinguen entre mayúsculas y minúsculas.

Sintaxis de sp_addtype :

sp_addtype datatypename ,

phystype [(length) | (precision [, scale])]

[, "identity" | nulltype ]

tid se ha definido de la siguiente forma:

sp_addtype tid, "char(6)", "not null"

Es preciso incluir un parámetro entre comillas simples o dobles, si contiene un espacio en blanco o algún signo de puntuación, o si es una palabra clave distinta de null (por ejemplo, identity o sp_helpgroup ). En este ejemplo, es necesario incluir char(6 ) entre comillas debido al paréntesis, así como NOT NULL, debido al espacio en blanco. No es preciso incluir tid entre comillas.

Especificación de la longitud, precisión y escala

Page 100: 80575032 Libro de SQL y Tl SQL Excelente

Page 100 of 280

Al crear un tipo de datos definido por el usuario basado en determinados tipos de datos de SQL Server, es necesario especificar parámetros adicionales:

Para los tipos de datos char , nchar , varchar , nvarchar , binary y varbinary , puede suministrarse un valor de longitud entre paréntesis. Si no se suministra, SQL Server utiliza la longitud predeterminada de un carácter.

Para el tipo de datos float , puede suministrarse un valor de precisión entre paréntesis. Si no se suministra, SQL Server utiliza la precisión predeterminada para la plataforma.

Para los tipos de datos numeric y decimal , pueden suministrarse valores de precisión y de escala entre paréntesis, separados por una coma. Si no se suministran, SQL Server utiliza la precisión y escala predeterminadas de 18 y 0.

No es posible cambiar la especificación de longitud, precisión o escala al incluir el tipo definido por el usuario en una instrucción create table .

Especificación del tipo nulo

El tipo nulo determina cómo el tipo de datos definido por el usuario trata los valores nulos. Es posible crear un tipo de datos definido por el usuario con un tipo nulo "null", "NULL", "nonull", "NONULL", " not null " o " NOT NULL". Por definición, los tipos bit e IDENTITY no admiten valores nulos.

Si se excluye el tipo nulo, SQL Server emplea el modo nulo definido por la base de datos (de forma predeterminada, NOT NULL). Por razones de compatibilidad con las normas SQL, utilice el procedimiento del sistema sp_dboption para definir la opción allow nulls by default como true .

Es posible escribir sobre el tipo nulo al incluir el tipo de datos definido por el usuario en una instrucción create table .

Asociación de reglas y valores predeterminados con tipos de datos definidos por el usuario

Una vez creado un tipo de datos definido por el usuario, es posible utilizar los procedimientos del sistema sp_bindrule y sp_bindefault para asociar reglas y valores predeterminados con el tipo de datos. Con el procedimiento del sistema sp_help , se puede imprimir un informe que enumere las reglas, valores predeterminados e información adicional asociados con el tipo de datos.

Las reglas y los valores predeterminados se describen en el Capítulo 12. Para obtener información completa sobre los procedimientos del sistema, consulte el Manual de Referencia de SQL Server .

Omisión de un tipo de datos definido por el usuario

Para omitir un tipo de datos definido por el usuario, ejecute sp_droptype :

sp_droptype typename

Note: No es posible omitir un tipo de datos que esté en uso en alguna tabla.

Obtención de información sobre tipos de datos

Utilice el procedimiento del sistema sp_help para mostrar información sobre las propiedades de un tipo de datos del sistema o de uno definido por el usuario. El informe indica el tipo base a partir del que se ha creado el tipo de datos, si admite o no valores nulos, los nombres o cualquier regla o valor predeterminado vinculados al tipo de datos, y si dispone de la propiedad IDENTITY.

En los ejemplos siguientes, se muestra información sobre el tipo de datos del sistema money y el tipo de datos definido por el usuario tid :

sp_help money

Type_name Storage_type Length Prec Scale

---------- ------------ ------ ----- -----

money money 8 NULL NULL

Nulls Default_name Rule_name Identity

----- ------------ --------- --------

1 NULL NULL 0

(return status = 0)

sp_help tid

Page 101: 80575032 Libro de SQL y Tl SQL Excelente

Page 101 of 280

Type_name Storage_type Length Prec Scale

---------- ------------ ------ ----- -----

tid varchar 6 NULL NULL

Nulls Default_name Rule_name Identity

----- ------------ --------- --------

0 NULL NULL 0

(return status = 0)

Chapter 7

Creación de bases de datos y tablas

En este capítulo se describe el modo de configurar bases de datos y tablas, un proceso llamado definición de datos . En él se trata lo siguiente:

Introducción general a bases de datos y sus tablas

Uso y creación de bases de datos

Creación de tablas y definición de sus columnas

Creación de tipos de datos definidos por el usuario

Cambio de tablas existentes

Obtención de información sobre bases de datos y tablas

Si no planea crear sus propias bases de datos y tablas, lea los conceptos básicos de bases de datos y tablas (descritos en la siguiente sección) y la explicación del comando use (descrito en una sección posterior). Después puede omitir el resto de este capítulo.

Definición de base de datos y de tabla

Uso y creación de bases de datos

Omisión de bases de datos

Alteración de los tamaños de bases de datos

Creación de tablas

Definición de restricciones de integridad para tablas

Diseño y creación de tablas

Creación de tablas nuevas a partir de resultados de consultas: select into

Omisión de tablas

Alteración de tablas existentes

Asignación de permisos a los usuarios

Obtención de información sobre bases de datos y tablas

Definición de base de datos y de tabla

Una base de datos almacena información (datos) en un conjunto de objetos de base de datos, tales como tablas, relacionados entre sí. Una tabla es un conjunto de filas que tienen columnas asociadas con elementos de datos individuales. La organización de los datos se define cuando se crean las bases de datos y las tablas. Este proceso se llama definición de datos.

Los objetos de base de datos de SQL Server incluyen:

Tablas

Reglas

Valores predeterminados

Procedimientos almacenados

Disparadores

Vistas

Restricciones de integridad de referencia

Restricciones de integridad de verificación

Este capítulo sólo cubre la creación, modificación y eliminación de bases de datos y tablas, incluyendo las restricciones de integridad.

Page 102: 80575032 Libro de SQL y Tl SQL Excelente

Page 102 of 280

Las reglas y valores predeterminados se explican en el Capítulo 12, las vistas en el Capítulo 9, los procedimientos en el Capítulo 14 y los disparadores en el Capítulo 15.

Las columnas y tipos de datos definen el tipo de datos incluidos en las tablas, mientras que los índices describen el modo en que dichos datos se organizan en las tablas. SQL Server no los considera objetos de la base de datos y no aparecen enumerados en sysobjects . Las columnas y tipos de datos se explican en este capítulo; los índices se describen en el Capítulo 11.

Imposición de la integridad de datos en bases de datos

La integridad de datos refiere a la validez e integridad de los datos dentro de una base de datos. Para imponer la integridad de datos, es posible restringir los valores de los datos que los usuarios pueden insertar, eliminar o actualizar en la base de datos. Por ejemplo, la integridad de los datos de la base de datos pubs2 requiere que un título de libro de la tabla titles tenga un editor en la tabla publishers . No se debe insertar libros en titles que no tengan un editor válido, ya que esto viola la integridad de los datos de pubs2 .

Transact-SQL proporciona varios mecanismos para imponer la integridad en una base de datos, como reglas, valores predeterminados, índices y disparadores, que permiten mantener los siguientes tipos de integridad de datos:

Requisito: esta integridad requiere que una columna de tabla contenga un valor válido en cada fila; no permite valores nulos. La instrucción create table permite restringir los valores nulos de una columna.

Verificación o validez: esta integridad limita o restringe los valores de datos insertados en una columna de tabla. Para imponer esta integridad de datos, pueden utilizarse disparadores o reglas.

Exclusividad : esta integridad establece que no debe haber dos filas de tabla con los mismos valores no nulos para una o más columnas de tablas. Para imponer esta integridad, pueden utilizarse índices.

De referencia: esta integridad establece que los datos insertados en una columna de tabla ya tengan datos coincidentes en otra columna de tabla, o en otra columna de la misma tabla. Para imponer esta integridad, pueden utilizarse disparadores.

La consistencia de los valores de datos de la base de datos es otra integridad de datos, que se describe en el Capítulo 17.

Como alternativa al uso de reglas, valores predeterminados, índices y disparadores, Transact-SQL proporciona una serie de restricciones de integridad que forman parte de la instrucción create table para imponer la integridad de datos según las normas SQL. Estas restricciones de integridad se describen más adelante en este capítulo.

Permisos dentro de bases de datos

La posibilidad de crear y omitir bases de datos y objetos de base de datos depende de los permisos o privilegios que el usuario tenga asignados. Normalmente, el administrador del sistema o propietario de la base de datos define los permisos del usuario, según el tipo de trabajo que realice y las funciones que necesite. Estos permisos pueden ser distintos para cada usuario de una instalación o base de datos dadas.

Para determinar los permisos que posee, ejecute:

sp_helprotect user_name

donde user_name es su nombre de login de SQL Server.

Para experimentar con objetos de base de datos de la forma más conveniente posible, la base de datos pubs2 tiene un usuario " invitado " en su tabla del sistema sysusers . El guión que crea pubs2 concede una gran variedad de permisos al " invitado " .

El mecanismo " invitado " significa que cualquiera que tenga un login en SQL Server, es decir, que aparezca en master.. syslogins , tendrá acceso a pubs2 y permiso para crear y omitir objetos como tablas, índices, valores predeterminados, reglas, procedimientos, etc.. El nombre de usuario " invitado " también permite utilizar algunos procedimientos almacenados, crear tipos de datos definidos por el usuario, consultar la base de datos y modificar sus datos.

Para utilizar la base de datos pubs2 , emita el comando use . SQL Server verifica si su nombre de usuario aparece en pubs2.. sysusers . Si no aparece, será admitido como invitado sin más trámite. Si su nombre aparece en pubs2.. sysusers , será admitido, pero sus permisos pueden ser diferentes de los de " invitado " . Todos los ejemplos de este capítulo suponen que usted es un " invitado " .

Uso y creación de bases de datos

Page 103: 80575032 Libro de SQL y Tl SQL Excelente

Page 103 of 280

Una base de datos es un conjunto de tablas relacionadas y otros objetos de base de datos (vistas, índices, etc.).

La primera vez que se instala, SQL Server contiene estas bases de datos del sistema :

La base de datos master controla las bases de datos del usuario y el funcionamiento de SQL Server como un todo.

La base de datos sybsystemprocs contiene los procedimientos almacenados del sistema.

La base de datos temporal, tempdb , almacena los objetos temporales, incluidas las tablas temporales creadas con el prefijo de nombre " tempdb ..".

La base de datos model es utilizada por SQL Server como plantilla para la creación de nuevas bases de datos de usuario.

Además, los administradores del sistema pueden instalar la base de datos de muestra, pubs2 , y la base de datos de sintaxis, sybsyntax , mediante isql y los guiones SQL incluidos en el directorio scripts . La base de datos pubs2 sirve como base para la mayoría de los ejemplos de la documentación de SQL Server. La base de datos sybsyntax almacena toda la información de sintaxis de los comandos y procedimientos a los que se tiene acceso mediante sp_syntax .

Las bases de datos pubs2 y sybsyntax son bases de datos del usuario. Todos sus datos - el motivo para usar un sistema de administración de bases de datos - se almacenan en bases de datos del usuario. SQL Server administra cada base de datos mediante las tablas del sistema. Las tablas del diccionario de datos de la base de datos master y de otras bases de datos se consideran tablas del sistema.

Selección de una base de datos: use

La mayor parte del tiempo, usted utilizará una base de datos que ya existe. La sintaxis del comando que permite el acceso a una base de datos existente es:

use database_name

Por ejemplo, para tener acceso a la base de datos llamada pubs2 , escriba:

use pubs2

El usuario puede tener acceso a la base de datos pubs2 mediante dicho comando sólo si es un usuario conocido en pubs2 . De lo contrario, SQL Server muestra un mensaje de error. El propietario de la base de datos decide quién tiene acceso a dicha base de datos ejecutando el procedimiento del sistema sp_adduser.

La mayoría de los usuarios podrán ver las tablas del sistema de la base de datos master como invitados, según se explicó anteriormente. Los usuarios que no son reconocidos por nombre en la base de datos master pueden tener acceso a la misma como usuarios " invitados " . El usuario " invitado " se añade a la base de datos master en el guión que crea esta base de datos cuando se instala.

Un propietario de base de datos, "dbo", puede añadir un usuario "invitado" a cualquier base de datos de usuario con el procedimiento del sistema sp_adduser . Los administradores del sistema se convierten automáticamente en los propietarios de las base de datos que usan. Para obtener más información, consulte la Guía de Administración del Sistema o el Manual del Referencia de SQL Server .

Es probable que se conecte automáticamente a la base de datos master cuando haga el login a SQL Server, de manera que deberá ejecutar el comando use para tener acceso a otra base de datos. Tanto usted como el administrador del sistema pueden cambiar la base de datos a la que se conectan inicialmente mediante el procedimiento del sistema sp_modifylogin . Sólo el administrador del sistema puede cambiar la base de datos predeterminada para otro usuario.

Creación de una base de datos del usuario: create database

Si el administrador del sistema le concede el permiso para utilizar el comando create database , usted puede crear una base de datos nueva. Cuando cree una base de datos, deberá estar usando la base de datos master . En muchas empresas, el administrador del sistema crea todas las bases de datos. El autor de la base de datos es su propietario. Si otro usuario crea la base de datos, puede transferirle los derechos de propiedad mediante el procedimiento del sistema sp_changedbowner .

El propietario de la base de datos es responsable de proporcionar acceso a la base de datos a los usuarios, y de conceder y revocar otros permisos para usuarios. En algunas organizaciones, el propietario de la base de datos también es responsable de mantener copias de seguridad periódicas de la base de datos y de volver a cargarla en caso de un fallo del sistema. El

Page 104: 80575032 Libro de SQL y Tl SQL Excelente

Page 104 of 280

propietario de la base de datos siempre puede hacerse pasar por cualquier otro usuario de la base de datos, consiguiendo temporalmente los permisos de tales usuarios, mediante el comando setuser .

Dado que cada base de datos tiene asignada una cantidad importante de espacio, aunque contenga sólo pequeñas cantidades de datos, es posible que no se le otorgue el permiso para utilizar el comando create database . Si éste es el caso, ignore esta sección y pase a la explicación "Creación de tablas".

Este es el formato más sencillo del comando create database :

create database database_name

Para crear la base de datos newpubs , cerciórese de estar usando la base de datos master en lugar de pubs2 y luego escriba este comando:

create database newpubs

El nombre de la base de datos debe ser único en SQL Server y ajustarse a las reglas para identificadores proporcionadas en el Capítulo 1. SQL Server puede administrar hasta 32.767 bases de datos. Sólo se puede crear una base de datos por vez. El número máximo de segmentos para cualquier base de datos es 32.

SQL Server crea la base de datos nueva como una copia de la base de datos model , que contiene las tablas del sistema pertenecientes a todas las bases de datos de usuario.

La creación de una base de datos nueva se registra en las tablas sysdatabases y sysusages de la base de datos master .

Esta es la sintaxis completa del comando create database :

create database database_name

[on {default | database_device } [= size ]

[, database_device [= size ]]...]

[log on database_device [= size ]

[, database_device [= size ]]...]

[with override]

[for load]

En este capítulo se describen todas las opciones de create database , excepto with override . Para obtener más información sobre dicha opción, consulte la Guía de Administración del Sistema .

Note: En los ejemplos anteriores y en los de la siguiente sección, no se muestra la cláusula log on por razones de simplicidad. Sin embargo, cuando cree bases de datos de producción, siempre debe hacerlo con la cláusula log on . Consulte la siguiente sección.

La cláusula on

La cláusula opcional on permite especificar la posición donde debe almacenarse la base de datos y la cantidad de espacio en megabytes que se le debe asignar. Si utiliza la palabra clave default , la base de datos se asignará a un dispositivo de bases de datos del banco de dispositivos de bases de datos indicado en la tabla sysdevices de la base de datos master . Emplee el procedimiento del sistema sp_helpdevice para ver los dispositivos de la lista predeterminada.

Note: Un administrador del sistema puede tener ciertas asignaciones de almacenamiento basadas en estadísticas de rendimiento y otras consideraciones. Antes de crear bases de datos, consulte con un administrador del sistema.

Para especificar un tamaño de 5 MB para una base de datos que va a almacenarse en esta posición predeterminada, utilice on default = size de la siguiente manera:

create database newpubs

on default = 5

Si quiere especificar una posición diferente para la base de datos, proporcione el nombre lógico del dispositivo de base de datos donde desea almacenarla. Una base de datos puede almacenarse en varios dispositivos de base de datos, con diferentes cantidades de espacio en cada uno.

Esta instrucción crea la base de datos newpubs y le asigna 3 MB en pubsdata y 2 MB en newdata :

Page 105: 80575032 Libro de SQL y Tl SQL Excelente

Page 105 of 280

create database newpubs

on pubsdata = 3, newdata = 2

Si omite la cláusula on y el tamaño, la base de datos se crea con 2 MB de espacio del banco de dispositivos de base de datos predeterminados indicados en sysdevices .

El tamaño de una asignación de base de datos puede estar comprendido entre 2 MB y 223 MB.

La cláusula log on

A menos que esté creando bases de datos pequeñas y no esenciales, siempre deberá utilizar la extensión log on database_device de create database . Esta extensión sitúa los diarios de transacciones en un dispositivo de bases de datos independiente. Hay varias razones para situar los diarios en otro dispositivo:

Permite utilizar el comando dump transaction en lugar de dump database , ahorrando así tiempo y cintas.

Permite establecer un tamaño fijo para el diario, dejando así espacio libre para otras actividades de la base de datos.

Hay otras razones para situar el diario en un dispositivo físico distinto del de las tablas de datos:

Aumento de rendimiento.

Garantía de una capacidad de recuperación total en caso de fallos del disco duro.

El siguiente comando coloca el diario de newpubs en el dispositivo lógico "pubslog" , con un tamaño de 1 megabyte:

create database newpubs

on pubsdata = 3, newdata = 2

log on pubslog = 1

Note: Cuando utilice la extensión log on , colocará el diario de transacciones de la base de datos en un segmento llamado "logsegment". Si alguna vez necesita añadir más espacio para el diario, deberá usar alter database y, en algunos casos, el procedimiento del sistema sp_extendsegment . Consulte el Manual de Referencia de SQL Server o la Guía de Administración de Sistema SQL Server para obtener información adicional.

El tamaño del dispositivo requerido para el diario de transacciones varía según la cantidad de actividad de actualización y la frecuencia de los volcados del diario de transacciones. Como regla práctica, asigne entre un 10 y 25 por ciento del espacio asignado a la base de datos en sí al diario.

La opción for load

La cláusula opcional for load ejecuta una versión racionalizada de create database que sólo puede utilizarse para cargar un volcado de base de datos. Use esta opción para efectuar la recuperación tras un fallo de medios, o para el traslado de una base de datos de una máquina a otra. Consulte la Guía de Administración del Sistema para obtener información detallada.

Omisión de bases de datos

La supresión de una base de datos se lleva a cabo con el comando drop database . drop database elimina la base de datos y su contenido de SQL Server, libera el espacio de almacenamiento que se le había asignado, y elimina las referencias a la misma por parte de la base de datos master .

Esta es la sintaxis del comando:

drop database database_name [, database_name ]...

No es posible omitir una base de datos en uso, es decir, que está abierta para su lectura o escritura por parte de cualquier usuario.

Como se indica, se puede omitir más de una base de datos en un solo comando. Por ejemplo:

drop database newpubs, newdb

Una base de datos dañada no puede suprimirse con drop database . Utilice el comando dbcc dbrepair .

Page 106: 80575032 Libro de SQL y Tl SQL Excelente

Page 106 of 280

Alteración de los tamaños de bases de datos

Si una base de datos ha utilizado todo el espacio de almacenamiento asignado, no es posible añadirle datos nuevos ni actualizaciones. Lógicamente, los datos existentes siempre se conservan. Si el espacio asignado a una base de datos es demasiado reducido, el propietario de la base de datos puede aumentarlo con el comando alter database . El permiso alter database corresponde predeterminadamente al propietario de la base de datos y no puede transferirse. Para usar el comando alter database , hay que estar utilizando la base de datos master .

El incremento predeterminado es de 2 MB y proviene del banco predeterminado de espacio. Esta instrucción añade 2 MB a newpubs en el dispositivo de bases de datos predeterminado:

alter database newpubs

La sintaxis completa de alter database permite ampliar una base de datos en un número especificado de megabytes (un mínimo de 1 MB) e indicar dónde debe añadirse el espacio de almacenamiento:

alter database database_name

[on {default | database_device } [= size ]

[, database_device [= size ]]...]

[log on { default | database_device } [ = size ]

[ , database_device [= size ]]...]

[with override]

[for load]

La cláusula on del comando alter database es como la cláusula on del comando create database . La cláusula for load es como la cláusula for load del comando create database y sólo puede utilizarse en una base de datos creada con for load .

Para aumentar el espacio asignado a newpubs en 2 MB en el dispositivo de bases de datos pubsdata , y en 3 MB en el dispositivo de bases de datos newdata , escriba:

alter database newpubs

on pubsdata = 2, newdata = 3

Cuando se usa alter database para asignar más espacio en un dispositivo ya en uso por la base de datos, todos los segmentos existentes del dispositivo utilizan el fragmento de espacio añadido. Todos los objetos ya correlacionados con los segmentos existentes pueden ampliarse en el espacio añadido. El número máximo de segmentos para cualquier base de datos es 32.

Cuando se usa alter database para asignar espacio en un dispositivo que todavía no está en uso por una base de datos, los segmentos system y default se correlacionan con el dispositivo nuevo. Si quiere cambiar esta correlación de segmentos, debe utilizar sp_dropsegment para omitir los segmentos no deseados del dispositivo.

Note: El uso de sp_extendsegment , logsegment o device_name cancela automáticamente la correlación de los segmentos system y default .

Para obtener información sobre with override , consulte la Guía de Administración del Sistema.

Creación de tablas

Cuando se crea una tabla, se asignan nombres a sus columnas y un tipo de datos a cada columna. También puede especificarse si una columna concreta puede contener valores nulos, o indicarse cualquier restricción de integridad para las columnas de la tabla.

Puede haber 2.000 millones de tablas por base de datos.

Ejemplo de creación de una tabla

Cerciórese de utilizar la base de datos newpubs creada en la sección anterior para intentar estos ejemplos. De lo contrario, todos estos cambios afectarán a otra base de datos, como pubs2 .

Para crear una tabla, use el comando create table , cuyo formato más sencillo es el siguiente:

create table table_name

( column_name datatype )

Page 107: 80575032 Libro de SQL y Tl SQL Excelente

Page 107 of 280

Por ejemplo, para crear una tabla llamada names con una columna some_name y una longitud fija de 11 bytes, introduzca:

create table names

(some_name char(11))

Puede definir hasta 250 columnas. Si ha definido quoted_identifier como on , el nombre de la tabla y los nombres de las columnas pueden ser identificadores delimitados. En caso contrario, deben ajustarse a las reglas para identificadores del Capítulo 1, "Introducción". Los nombres de columna deben ser únicos dentro de una tabla determinada, pero es posible utilizar el mismo nombre de columna en diferentes tablas de la misma base de datos.

Debe haber un tipo de datos para cada columna. La palabra "char" después del nombre de columna del ejemplo anterior hace referencia al tipo de datos de la columna, es decir, el tipo de valor que contendrá la columna. Los tipos de datos se explican en el Capítulo 6, "Uso y creación de tipos de datos".

El número entre paréntesis después del tipo de datos proporciona el número máximo de bytes que puede almacenarse en la columna. Se proporciona una longitud máxima para algunos tipos de datos. Otros tienen una longitud definida por el sistema.

Cerciórese de incluir la lista de nombres de columnas entre paréntesis y de colocar comas después de cada definición de columna.

Selección de nombres de tablas

El comando create table crea la tabla nueva en la base de datos abierta. Los nombres de tablas deben ser únicos para cada usuario.

Se pueden crear tablas temporales precediendo el nombre de la tabla en una instrucción create table con un símbolo de número (#) o especificando el prefijo de nombre " tempdb ..".

Las tablas temporales creadas con el símbolo de libra sólo pueden accederse durante la sesión actual de SQL Server y se eliminan al final de la sesión. Los 13 primeros bytes del nombre de la tabla, incluido el símbolo de número (#), deben ser únicos. SQL Server asigna un sufijo numérico de 17 bytes a los nombres de dichas tablas.

Las tablas temporales creadas con el prefijo " tempdb .." se almacenan en tempdb y pueden compartirse entre sesiones de SQL Server. SQL Server no cambia los nombres de las tablas temporales creadas de este modo. La tabla existe hasta que se reinicia SQL Server o hasta que la omite su propietario mediante drop table . Las tablas temporales no son recuperables.

create table #authors

(au_id char(11))

crea una tabla temporal no compartible.

create table tempdb..authors

(au_id char(11))

crea una tabla temporal que puede compartirse entre sesiones de SQL Server.

Usted puede utilizar cualquier tabla u otros objetos que haya creado sin calificar sus nombres. También puede usar los objetos creados por el propietario de la base de datos sin calificar sus nombres, siempre que tenga los permisos adecuados. Estas reglas se aplican a todos los usuarios, incluidos el administrador del sistema y el propietario de la base de datos.

Si bien los nombres de tablas deben ser únicos para cada usuario, diferentes usuarios pueden crear tablas con el mismo nombre. Por ejemplo, un usuario llamado "jonah" y otro llamado "sally" pueden crear tablas llamadas info . Los usuarios que tengan permiso en ambas tablas tendrán que calificarlas como jonah . info y sally.info. Sally tendrá que calificar todas las referencias a la tabla info de Jonah, aunque puede referirse a la suya simplemente como info .

Sintaxis de create table

Esta es la sintaxis del comando create table :

create table [ database .[ owner ].] table_name ( column_name datatype

[default { constant_expression | user | null}]

{[{identity | null | not null}]

Page 108: 80575032 Libro de SQL y Tl SQL Excelente

Page 108 of 280

| [[constraint constraint_name ]

{{unique | primary key}

[clustered | nonclustered]

[with {fillfactor | max_rows_per_page} = x]

[on segment_name ]

| references [[ database .] owner .] ref_table

[( ref_column )]

| check ( search_condition )}]}...

| [constraint constraint_name ]

{{unique | primary key}

[clustered | nonclustered]

( column_name [{, column_name }...])

[with {fillfactor | max_rows_per_page} = x]

[on segment_name ]

| foreign key ( column_name [{, column_name }...])

references [[ database .] owner .] ref_table

[( ref_column [{, ref_column }...])]

| check ( search_condition )}

[{, { next_column | next_constraint }}...])

+

[with max_rows_per_page = x][on segment_name ]

La instrucción create table define cada columna de la tabla. create table proporciona el nombre y el tipo de datos de la columna, especifica el modo en que cada columna manipula los valores nulos, e indica qué columna, si hubiera alguna, tiene la propiedad IDENTITY. create table también puede definir restricciones de integridad a nivel de columna y a nivel de tabla. Cada definición de tabla puede tener múltiples restricciones por columna y por tabla.

Por ejemplo, la instrucción create table para la tabla titles de la base de datos pubs2 es:

create table titles

(title_id tid,

title varchar(80) not null,

type char(12),

pub_id char(4) null,

price money null,

advance money null,

royalty int null,

total_sales int null,

notes varchar(200) null,

pubdate datetime

contract bit not null)

En las secciones siguientes se describen varios componentes distintos de definición de tabla: tipos de datos suministrados por el sistema, tipos de datos definidos por el usuario, tipos nulos y columnas IDENTITY. La definición de restricciones de integridad para una tabla se describe después de estas secciones.

Note: La extensión on segment_name de create table permite colocar la tabla en un segmento, un nombre que apunte a un dispositivo de bases de datos específico, o un conjunto de dispositivos de bases de datos. Antes de crear una tabla en un segmento, solicite una lista de los segmentos que pueden utilizarse al administrador del sistema o propietario de la base de datos. Algunos segmentos pueden estar asignados a tablas o índices específicos por razones de rendimiento, o por otras consideraciones.

Uso de valores nulos

Para cada columna, puede especificar si se admiten o no valores nulos. Un valor nulo no es lo mismo que "cero" o "espacio en blanco". NULL (nulo) significa que no se ha realizado ninguna entrada y generalmente implica "valor desconocido" o "valor inaplicable". Esto indica que el usuario no ha realizado ninguna entrada, cualquiera que sea la razón. Por ejemplo, una entrada nula en la columna price de la tabla titles no quiere decir que el libro sea gratuito, sino que el precio se desconoce, o que todavía no se ha fijado.

Si el usuario no realiza ninguna entrada en una columna definida con la palabra clave null , SQL Server proporcionará el valor NULL. Una columna definida con la palabra clave null también aceptará una entrada explícita de NULL por parte del usuario, cualquiera sea su tipo de datos. Sin embargo, hay que tener cuidado al introducir valores nulos en columnas de caracteres. Si incluye la palabra "null" entre comillas dobles o simples, SQL Server interpreta la entrada como una cadena de caracteres y no como el valor NULL.

Page 109: 80575032 Libro de SQL y Tl SQL Excelente

Page 109 of 280

Si omite null o not null en la instrucción create table , SQL Server utiliza el modo nulo definido para la base de datos (de forma predeterminada, NOT NULL). Para compatibilidad con las normas SQL, utilice el procedimiento del sistema sp_dboption para definir la opción allow nulls by default como true (verdadera).

Para una columna definida como NOT NULL, SQL Server insistirá en que se realice una entrada. Si no existe ninguna entrada para una columna NOT NULL, aparecerá un mensaje de error.

Los valores predeterminados, es decir, los valores suministrados de forma automática cuando no se realiza ninguna entrada, pueden usarse con columnas NULL y NOT NULL. Un valor predeterminado se considera una entrada. Sin embargo, no es posible designar un valor predeterminado NULL para una columna NOT NULL. Los valores nulos pueden especificarse como valores predeterminados mediante la restricción default de la instrucción create table , o mediante la instrucción create default . La restricción default se describe más adelante en este capítulo; create default se describe en el Capítulo 12.

Definir las columnas como NULL proporciona un marcador de lugar para los datos que todavía se desconocen. Por ejemplo, en la tabla titles , las columnas price , advance , royalty y total_sales están definidas para permitir valores NULL.

Sin embargo, title_id y title no están definidas para permitir valores NULL, ya que la falta de una entrada en estas columnas no tendría sentido y resultaría confuso. Un precio sin título no tendría sentido, mientras que un título sin precio simplemente significaría que el precio todavía estaba sin decidir o no estaba disponible.

En la instrucción create table , use las palabras clave not null cuando la información de la columna sea fundamental para el significado de las demás columnas.

Uso de columnas IDENTITY

Cada tabla puede incluir una sola columna IDENTITY. Las columnas IDENTITY almacenan números secuenciales (como los números de factura, de empleado o de registro) generados de forma automática por SQL Server. El valor de la columna IDENTITY identifica de forma única cada fila de una tabla.

La columna IDENTITY se define especificando la palabra clave identity, en lugar de null o not null, en la instrucción create table (por definición, las columnas IDENTITY no permiten valores nulos). Las columnas IDENTITY deben tener un tipo de datos numeric y una escala de 0.

La precisión determina el valor máximo que puede insertarse en la columna. El valor máximo posible de columna es 10 precision - 1. A continuación se muestra un ejemplo de una tabla cuya columna IDENTITY permite un valor máximo de 10 5 - 1, o 9,999:

create table sales_daily

(row_id numeric(5,0) identity,

stor_id char(4) not null)

Con la opción de base de datos auto identity y el parámetro de configuración size of auto identity se pueden crear columnas IDENTITY automáticas. Para incluir columnas IDENTITY como índices no únicos, use la opción de base de datos identity in nonunique index .

Creación de columnas IDENTITY con tipos de datos definidos por el usuario

También pueden utilizarse tipos de datos definidos por el usuario para crear columnas IDENTITY. El tipo de datos definido por el usuario debe tener un tipo numeric subyacente y una escala de 0.

Si el tipo de datos definido por el usuario fue creado con la propiedad IDENTITY, no es necesario repetir la palabra clave identity al crear la columna. A continuación se muestra un ejemplo de un tipo de datos definido por el usuario con la propiedad IDENTITY:

sp_addtype ident, "numeric(5)", "identity"

Esta es una columna IDENTITY basada en ese tipo:

create table sales_monthly

(row_id ident, stor_id char(4) not null)

Si el tipo definido por el usuario fue creado como not null , deberá especificar la palabra clave identity en la instrucción create table . No es posible crear una columna IDENTITY a partir de un tipo de datos definido por el usuario que permite valores nulos.

Page 110: 80575032 Libro de SQL y Tl SQL Excelente

Page 110 of 280

Referencia a columnas IDENTITY con syb_identity

Una vez definida la columna IDENTITY, no es necesario recordar el nombre de columna real. Se puede utilizar la palabra clave syb_identity, calificada por el nombre de la tabla donde sea necesario, en operaciones de selección, actualización y eliminación realizadas en la tabla. Por ejemplo, para seleccionar la fila donde row_id es igual a 30, utilice esta consulta:

select * from sales_daily

where syb_identity = 30

Generación de valores de columna

La primera vez que inserta una fila en una tabla, SQL Server asigna el valor 1 a la columna IDENTITY. Cada nueva fila obtiene un valor de columna mayor en uno que el anterior. Las reversiones de transacciones, eliminación de filas, parámetro de configuración identity grab size e inserción manual de datos en la columna IDENTITY pueden provocar la aparición de espacios en blanco en los valores de columna.

Los fallos del servidor también pueden crear espacios en blanco en los valores de columnas IDENTITY. El tamaño de estos espacios en blanco, como un porcentaje del tamaño máximo de la tabla, depende del valor del parámetro de configuración identity burning set factor . Este parámetro se define durante la instalación y el administrador del sistema puede volver a definirlo.

Uso de tablas temporales

Si utiliza el símbolo de número (#) o " tempdb .." antes del nombre de la tabla en el comando create table , la tabla nueva es temporal.

Hay dos tipos de tablas temporales:

Tablas que pueden compartirse entre sesiones de SQL Server.Estas tablas temporales compartibles se crean especificando tempdb como parte del nombre de la tabla en la instrucción create table . Por ejemplo:

create table tempdb..my_temptbl

SQL Server no cambia los nombres de las tablas temporales creadas de este modo. La tabla existe hasta que se reinicia SQL Server o hasta que su propietario la omita con drop table .

Tablas a las que sólo puede accederse durante la sesión actual de SQL Server. Las tablas temporales no compartibles deben comenzar con un símbolo de número (#). Para crear una tabla temporal no compartible, especifique sólo el nombre de la tabla en la instrucción create table . Por ejemplo:

create table #my_temptbl

SQL Server garantiza que el nombre de la tabla temporal sea único en la sesión actual. El programa trunca los nombres de tabla temporal largos a 13 caracteres (incluido el símbolo de número) y rellena los nombres cortos a 13 caracteres mediante caracteres de subrayado (_). Luego SQL Server añade un sufijo numérico de 17 dígitos único para una sesión de SQL Server. La tabla existe hasta que la sesión actual termina o hasta que su propietario la omite con drop table .

Si no indica el símbolo de número o " tempdb .." antes del nombre de la tabla y no utiliza tempdb , la tabla se crea como una tabla permanente. Una tabla permanente se conserva en la base de datos hasta que su propietario la omite de forma explícita.

A continuación se muestra una instrucción que crea una tabla temporal no compartible:

create table #myjobs

(task char(30),

start datetime,

stop datetime,

notes varchar(200))

Esta tabla se puede utilizar para mantener una lista de las tareas diarias junto con un registro del inicio y término de las mismas, y cualquier otra observación. La tabla y sus datos desaparecerán al final de la sesión de trabajo actual.

Page 111: 80575032 Libro de SQL y Tl SQL Excelente

Page 111 of 280

Las tablas temporales no son recuperables.

Es posible asociar reglas, valores predeterminados e índices a las tablas temporales, pero no crear vistas en tablas temporales ni asociar disparadores con ellas. Al crearse una tabla temporal, se puede utilizar un tipo de datos definido por el usuario, sólo si dicho tipo se encuentra en tempdb .. systypes .

Existen dos formas de añadir un tipo de datos definido por el usuario, o cualquier otro objeto, a tempdb . Para añadir un objeto sólo para la sesión actual, ejecute sp_addtype mientras utiliza tempdb . Para añadir un tipo de datos definido por el usuario permanentemente, ejecute sp_addtype en model y después reinicie SQL Server para que model se copie en tempdb .

Creación de tablas en bases de datos diferentes

Como muestra la sintaxis de create table , se puede crear una tabla en una base de datos distinta de la actual calificando el nombre de la tabla con el nombre de la otra base de datos. Sin embargo, es necesario ser un usuario autorizado de la base de datos donde va a crearse la tabla y tener el permiso create table sobre ella.

Si se usa pubs2 y hay otra base de datos llamada newpubs , se puede crear una tabla llamada newtab en newpubs así:

create table newpubs..newtab (col1 int)

Para que create table se ejecute de forma correcta, la etiqueta de sesión curread debe dominar el obstáculo de la base de datos donde se va a crear la tabla.

No es posible crear otros objetos de base de datos (vistas, reglas, valores predeterminados, procedimientos almacenados o disparadores) en una base de datos distinta de la actual.

Definición de restricciones de integridad para tablas

Transact-SQL proporciona dos métodos para mantener la integridad de los datos de una base de datos:

Definición de reglas, valores predeterminados, índices y disparadores

Definición de restricciones de integridad de create table

La selección de un método en lugar de otro depende de los requisitos del usuario. Las restricciones de integridad ofrecen la ventaja de definir los controles de integridad en un paso durante el proceso de creación de la tabla (según definen las normas SQL) y de simplificar el proceso para crear dichos controles. Sin embargo, las restricciones de integridad están más limitadas en alcance y son menos extensas que los valores predeterminados, reglas, índices y disparadores.

Por ejemplo, los disparadores proporcionan una manipulación más compleja de la integridad de referencia que los declarados en create table . Asimismo, las restricciones de referencia definidas por create table son específicas de dicha tabla. A diferencia de las reglas o valores predeterminados, las restricciones no pueden vincularse a otras tablas y sólo pueden omitirse o cambiarse mediante alter table . Las restricciones no pueden contener subconsultas ni funciones agregadas, ni siquiera en la misma tabla.

Los dos métodos no son excluyentes entre sí. Es posible utilizar restricciones de referencia junto con valores predeterminados, reglas, índices y disparadores. Esto proporciona la flexibilidad de elegir el método que mejor se ajuste a cada aplicación de usuario. En esta sección se describen las restricciones de integridad de create table . Los valores predeterminados, reglas, índices y disparadores se explican en capítulos posteriores.

Pueden crearse los siguientes tipos de restricciones:

Las restricciones unique y primary key exigen que no haya dos filas en una tabla con los mismos valores en las columnas especificadas. Además, la restricción primary key requiere que no haya valores nulos en ninguna fila de la columna.

La integridad de referencia ( references ) exige que los datos insertados en columnas específicas ya tengan datos coincidentes en la tabla y columnas especificadas.

Las restricciones check limitan los valores de datos insertados en las columnas.

También se puede imponer la integridad de datos restringiendo el uso de valores nulos en una columna (las palabras clave null o not null ) y proporcionando valores predeterminados para columnas (la cláusula default ). Consulte la sección ''Uso de valores nulos'', para obtener más información sobre las palabras clave null y not null .

Page 112: 80575032 Libro de SQL y Tl SQL Excelente

Page 112 of 280

Se pueden crear mensajes de error vinculados a restricciones. Genere mensajes con sp_addmessage y vincúlelos a las restricciones con sp_bindmsg. Para obtener más información, consulte sp_addmessage y sp_bindmsg en el Manual de Referencia de SQL Server .

Para obtener más información sobre restricciones definidas para una tabla, utilice el procedimiento del sistema sp_helpconstraint , que se describe al final de este capítulo.

Especificación de restricciones a nivel de tabla o de columna

Es posible declarar restricciones de integridad a nivel de tabla o de columna. La diferencia es sintáctica. Las restricciones a nivel de columna se incluyen después del nombre de columna y del tipo de datos, antes de la coma de delimitación. Las restricciones a nivel de tabla se introducen como cláusulas delimitadas por comas distintas. SQL Server trata las restricciones a nivel de tabla y de columna del mismo modo; ningún método es más eficaz que el otro.

Sin embargo, las restricciones que operen en más de una columna deben declararse como restricciones a nivel de tabla. Por ejemplo, la siguiente instrucción create table tiene una restricción check que opera en dos columnas , pub_id y pub_name :

create table my_publishers

(pub_id char(4),

pub_name varchar(40),

constraint my_chk_constraint

check(pub_id in ("1389", "0736", "0877")

or pub_name not like "Bad News Books"))

Es posible, pero no es necesario, declarar las restricciones que operan sólo en una columna como restricciones a nivel de columna. Por ejemplo, si la restricción check anterior sólo utiliza una columna ( pub_id) , se puede poner la restricción en esa columna:

create table my_publishers

(pub_id char(4) constraint my_chk_constraint

check(pub_id in ("1389", "0736", "0877")),

pub_name varchar(40))

En ambos casos, la palabra clave constraint y el nombre de restricción que la acompaña son opcionales. La restricción check se describe en una sección posterior.

Especificación de valores de columna predeterminados

Antes de definir ninguna restricción de integridad a nivel de columna, se puede especificar un valor predeterminado de columna con la cláusula default . Esta cláusula asigna un valor predeterminado a una columna en un paso, como parte de la instrucción create table . Cuando un usuario no introduce ningún valor de columna, SQL Server inserta el valor predeterminado automáticamente.

Con la cláusula default se pueden utilizar los siguientes valores:

constant_expression : especifica una expresión constante para usarse como valor predeterminado de la columna. No se puede incluir el nombre de ninguna columna ni otro objeto de base de datos, pero sí funciones incorporadas que no hagan referencia a objetos de base de datos. Este valor predeterminado debe ser compatible con el tipo de datos de la columna.

user : indica que SQL Server debe insertar el nombre del usuario como valor predeterminado. Para utilizar este valor predeterminado, el tipo de datos de la columna debe ser char(30) o varchar(30) .

null : indica que SQL Server debe insertar el valor nulo como valor predeterminado. No se puede definir este valor predeterminado en columnas que no permitan valores nulos (utilizando la palabra clave not null ).

Por ejemplo, esta instrucción create table define dos valores predeterminados de columna:

create table my_titles

(title_id char(6),

title varchar(80),

price money default null,

total_sales int default 0)

Sólo puede incluirse una cláusula default por columna de tabla.

Page 113: 80575032 Libro de SQL y Tl SQL Excelente

Page 113 of 280

El uso de la cláusula default para asignar valores predeterminados es más sencillo que el método de dos pasos de Transact-SQL. En Transact-SQL, es posible utilizar create default para declarar el valor predeterminado y luego vincularlo a la columna con sp_bindefault .

Especificación de restricciones unique y primary key

Para garantizar que no haya dos filas de una tabla con los mismos valores en las columnas especificadas, se pueden declarar restricciones unique o primary key . Ambas restricciones crean índices únicos que imponen esta integridad de datos. Sin embargo, las restricciones primary key son más restrictivas que las unique . Las columnas con restricciones primary key no pueden contener valores nulos. La restricción primary key de una tabla suele usarse en conjunción con las restricciones de integridad de referencia definidas en otras tablas.

La definición de restricciones unique de las normas SQL especifica que la definición de columna no debe admitir valores nulos. De forma predeterminada, SQL Server define la columna para no permitir valores nulos (si no se modificó con sp_dboption ) si el usuario omite las palabras clave null o not null en la definición de columna. En Transact-SQL, es posible definir la columna para que admita valores nulos con la restricción unique , ya que el índice único usado para imponer la restricción permite insertar valores nulos.

Note: No confunda las restricciones de integridad unique y primary key con la información definida por los procedimientos del sistema sp_primarykey , sp_foreignkey y sp_commonkey . Las restricciones unique y primary key crean índices para definir los atributos únicos o de clave primaria de las columnas de tablas. sp_primarykey , sp_foreignkey y sp_commonkey definen la relación lógica de claves (en la tabla syskeys ) para las columnas de tabla, que se impone mediante la creación de índices y disparadores.

De forma predeterminada, las restricciones unique crean índices únicos no agrupados y las restricciones primary key crean índices únicos agrupados. Los índices agrupados o no agrupados pueden declararse con cualquiera de los dos tipos de restricción.

Por ejemplo, esta instrucción create table utiliza una restricción unique a nivel de tabla para garantizar que no haya dos filas con los mismos valores en las columnas stor_id y ord_num :

create table my_sales

(stor_id char(4),

ord_num varchar(20),

date datetime,

unique clustered (stor_id, ord_num))

Sólo puede existir un índice agrupado en una tabla, de modo que sólo puede especificarse una restricción unique clustered o primary key clustered .

Las restricciones unique y primary key pueden emplearse para crear índices únicos (incluidas las opciones with fillfactor , with max_rows_per_page y on segment_name ) al reforzar la integridad de datos. Sin embargo, los índices proporcionan funciones adicionales. Para obtener más información sobre los índices y sus opciones, incluidas las diferencias entre los índices agrupados y no agrupados, consulte el Capítulo 11, "Creación de índices en tablas".

Especificación de restricciones de integridad de referencia

Se pueden declarar restricciones de integridad de referencia para que los datos insertados en una tabla "de referencia" que defina la restricción tengan valores coincidentes en una tabla "referenciada". Una restricción de integridad de referencia se satisface con cualquiera de las siguientes condiciones:

Si una columna de la tabla de referencia incluida con la restricción contiene un valor nulo

Si las columnas de la tabla de referencia incluidas con la restricción coinciden con las columnas correspondientes de la tabla referenciada

Por ejemplo, esta instrucción create table emplea dos restricciones de integridad de referencia:

create table my_salesdetail

(stor_id char(4),

ord_num varchar(20),

title_id char(6)

references my_titles(title_id),

qty smallint,

constraint salesdet_constr

Page 114: 80575032 Libro de SQL y Tl SQL Excelente

Page 114 of 280

foreign key (stor_id, ord_num)

references my_sales (stor_id, ord_num))

La primera restricción garantiza que cualquier fila insertada en my_salesdetail tenga un valor para title_id que coincida con un valor para la columna title_id de la tabla my_titles . my_salesdetail es la tabla de referencia y my_titles es la tabla referenciada. La segunda restricción (llamada salesdet_constr ) garantiza que los valores insertados para las columnas stor_id y ord_num de una fila coincidan con columnas con nombres similares en una fila de la tabla my_sales .

Una tabla puede incluir una restricción de integridad de referencia en sí misma. No es posible eliminar filas ni actualizar valores de columna de una tabla referenciada que tenga valores coincidentes en una tabla de referencia. Asimismo, sólo se puede omitir la tabla referenciada si se omite la tabla de referencia o se quita la restricción de integridad de referencia.

Las restricciones de integridad de referencia a nivel de tabla deben incluir la cláusula foreign key y una lista de uno o más nombres de columna. Los nombres de columna de la cláusula references son opcionales sólo si las columnas de la tabla referenciada se designan como clave primaria a través de una restricción primary key .

Cualquier columna referenciada que se especifique debe estar restringida por un índice único de dicha tabla. Dicho índice único puede crearse mediante la restricción unique o primary key , o la instrucción create index . Además, los tipos de datos de las columnas de la tabla de referencia deben coincidir exactamente con el tipo de datos de las columnas de la tabla referenciada. Por ejemplo:

create table test_type

(col1 char(4) not null

references publishers(pub_id),

col2 varchar(20) not null)

El tipo de datos de col1 de la tabla de referencia ( test_type ) coincide con el tipo de datos de pub_id de la tabla referenciada ( publishers ).

Es necesario tener el permiso references en la tabla referenciada para utilizar las restricciones de integridad de referencia. Para obtener más información sobre permisos, consulte la Guía del Usuario de las Características de Seguridad .

Las restricciones de integridad de referencia proporcionan un modo más sencillo de imponer la integridad de los datos cuando se comparan con la creación de disparadores. Sin embargo, los disparadores proporcionan funciones adicionales para imponer la integridad de referencia entre tablas. Para obtener más información sobre disparadores, consulte el Capítulo 15.

Especificación de restricciones check

Es posible declarar una restricción check para limitar los valores que los usuarios pueden insertar en una columna de una tabla. Una restricción check especifica una condición de búsqueda ( search_condition) que los valores deben cumplir antes de su inserción en la tabla. Una condición de búsqueda puede incluir:

Una lista de expresiones constantes introducidas por in

Un rango de expresiones constantes introducidas por between

Un conjunto de condiciones introducidas por like , que puede contener caracteres comodín

Una expresión puede incluir operaciones aritméticas y funciones Transact-SQL incorporadas. La condición de búsqueda no puede contener subconsultas, una especificación de función de conjunto ni una especificación de destino.

Por ejemplo, esta instrucción create table garantiza que sólo se introducirán determinados valores en la columna pub_id :

create table my_new_publishers

(pub_id char(4)

check (pub_id in ("1389", "0736", "0877",

"1622", "1756")

or pub_id like "99[0-9][0-9]"),

pub_name varchar(40),

city varchar(20),

state char(2))

Si la restricción de verificación es una restricción de verificación a nivel de columna, sólo puede hacer referencia a la columna en la que está definida y no puede hacer referencia a ninguna otra columna de la tabla. Las restricciones de verificación a nivel de tabla pueden hacer referencia a cualquier columna de la tabla. create table permite múltiples restricciones check en una definición de columna.

Page 115: 80575032 Libro de SQL y Tl SQL Excelente

Page 115 of 280

Diseño y creación de tablas

Esta sección proporciona un ejemplo de una instrucción create table que se puede utilizar para crear una tabla práctica propia. Si no dispone del permiso create table , consulte al administrador del sistema o propietario de la base de datos en la que se está trabajando.

La creación de una tabla implica normalmente la creación de índices, valores predeterminados y reglas que la acompañan. Con frecuencia también se incluyen tipos de datos, disparadores y vistas personalizados.

Lógicamente, se puede crear una tabla, introducir algunos datos y trabajar con ellos durante algún tiempo antes de crear índices, valores predeterminados, reglas, disparadores o vistas. Esto ofrece la oportunidad de ver el tipo de transacciones que son más comunes y el tipo de datos que se introducen con más frecuencia.

Por otro lado, generalmente es más eficaz diseñar una tabla y todos los componentes que la acompañan al mismo tiempo. A continuación se muestra un esquema de los pasos a seguir. Quizás le resulte más sencillo realizar un esquema sobre papel antes de crear la tabla y los objetos que la acompañan.

1. Decida qué columnas necesita en la tabla, así como el tipo de datos, longitud, precisión y escala de cada una. 2. Cree los nuevos tipos de datos definidos por el usuario antes de establecer la tabla en la que se van a utilizar. 3. Decida qué columna, si fuera necesario, debe ser la columna IDENTITY. 4. Decida qué columnas deben aceptar valores nulos y cuáles no. 5. Decida qué restricciones de integridad o valores predeterminados de columna, si los hubiera, es necesario añadir a las

columnas de la tabla. Esto también implica decidir cuándo deben utilizarse las restricciones y valores predeterminados de columna en lugar de los valores predeterminados, reglas, índices y disparadores para imponer la integridad de los datos.

6. Decida si necesita valores predeterminados y reglas y, en caso afirmativo, determine su ubicación y tipo. Tenga en cuenta la relación entre el estado NULL y NOT NULL de una columna, así como los valores predeterminados y las reglas.

7. Decida qué tipo de índices necesita y su ubicación. Los índices se explican en el Capítulo 11. 8. Cree la tabla y sus índices con los comandos create table y create index . 9. Cree los nuevos valores predeterminados y reglas necesarios con los comandos create default y create rule . Estos

comandos se explican en el Capítulo 12. 10. Vincule los valores predeterminados y reglas necesarios con los procedimientos del sistema sp_bindefault y

sp_bindrule . Si hubiera algún valor predeterminado o regla en un tipo de datos definido por el usuario utilizado en una instrucción create table , se activará de forma automática. Estos procedimientos del sistema se explican en el Capítulo 14.

11. Cree disparadores con el comando create trigger . Los disparadores se explican en el Capítulo 15. 12. Cree vistas con el comando create view . Las vistas se explican en el Capítulo 9.

Realización de un esquema de diseño

La tabla friends_etc se utiliza en capítulos subsiguientes para mostrar cómo crear índices, valores predeterminados, reglas, disparadores, etc.. Dicha tabla puede contener nombres, direcciones, números de teléfono e información personal sobre amigos, y no define ningún valor predeterminado de columna o restricción de integridad a fin de evitar entrar en conflicto con dichos objetos.

Si piensa seguir los ejemplos y crear todos los objetos de friends_etc , consulte al administrador del sistema o propietario de la base de datos. La persona responsable deberá cerciorarse de que, si otro usuario creó la tabla, sus índices, valores predeterminados, reglas y disparadores, la tabla haya sido omitida a fin de evitar cualquier conflicto al crear los objetos.

La siguiente tabla muestra la estructura propuesta de la tabla y los índices, valores predeterminados y reglas que acompañarán a cada columna.

Tabla 7-1: Muestra de un diseño de tabla

Columna Tipo de datos NULL? Indice Valor predeterminado Regla

pname nm NOT NULL nmind (compuesto)

sname nm NOT NULL nmind (compuesto)

address varchar(30) NULL

city varchar(30) NOT NULL citydflt

state char(2) NOT NULL statedflt

zip char(5) NULL zipind zipdflt ziprule

Page 116: 80575032 Libro de SQL y Tl SQL Excelente

Page 116 of 280

phone p# NULL phonerule

age tinyint NULL agerule

bday datetime NOT NULL bdflt

sex bit NOT NULL sexdflt

debt money NOT NULL sexdflt

notes varchar(255) NULL

Creación de tipos de datos definidos por el usuario

Las dos primeras columnas son para el nombre y apellido, y su tipo de datos está definido como nm . Antes de crear la tabla, es necesario generar el tipo de datos. Lo mismo ocurre con el tipo de datos p# de la columna phone .

El tipo de datos nm permite una entrada de caracteres de longitud variable con un máximo de 30 bytes. El tipo de datos p # permite un tipo de datos char con un tamaño de longitud fija de 10 bytes.

Introduzca las definiciones de tipo de datos de nm y p # de esta forma:

execute sp_addtype nm, "varchar(30)"

execute sp_addtype p#, "char(10)"

Selección de columnas que aceptan valores nulos

Salvo las columnas a las que se asignan tipos de datos definidos por el usuario, cada columna tiene una entrada explícita NULL o NOT NULL. Recuerde que no es necesario especificar NOT NULL en la definición de tabla, porque se trata del valor predeterminado. Este diseño de tabla especifica NOT NULL de forma explícita para facilitar la lectura.

El valor predeterminado NOT NULL quiere decir que se precisa una entrada, por ejemplo, para las dos columnas de nombre de esta tabla. Los demás datos no tienen sentido sin los nombres. Además, la columna sex debe ser NOT NULL porque no se puede utilizar NULL con columnas bit .

Si se designa una columna como NULL y se vincula con un valor predeterminado, cuando no se proporciona ningún otro valor en la entrada, se introduce el valor predeterminado, en lugar de NULL. Si se designa una columna NULL y se vincula con una regla que no especifica NULL, cuando no se introduce ningún valor para la columna, la definición de columna ignora la regla. Las columnas pueden tener valores predeterminados y reglas. La relación entre ambos se explica en un capítulo posterior.

Definición de una tabla

Ahora puede escribir la instrucción create table :

create table friends_etc

(pname nm not null,

sname no not null,

address varchar(30) null,

city varchar(30) not null,

state char(2) not null,

postalcode char(5) null,

phone p# null,

age tinyint null,

bday datetime not null,

sex bit not null,

debt money not null,

notes varchar(255) null

Ahora hay columnas definidas para nombre y apellido, dirección, ciudad, estado, código postal, número de teléfono, edad, fecha de nacimiento, sexo, información sobre deudas y notas. En otros capítulos se describe el modo de crear reglas, valores predeterminados, índices, disparadores y vistas usados con la tabla.

Creación de tablas nuevas a partir de resultados de consultas: select into

La cláusula select into se puede utilizar para hacer una selección dentro de una tabla permanente, sólo si la opción de base de datos select into/bulkcopy está definida como on . El administrador del sistema puede activar esta opción con el

Page 117: 80575032 Libro de SQL y Tl SQL Excelente

Page 117 of 280

procedimiento del sistema sp_dboption . Para comprobar si esta opción está activada, ejecute el procedimiento del sistema sp_helpdb .

A continuación se muestra el comando y sus resultados si la opción está activada:

sp_helpdb pubs2

name db_size owner dbid created status

--------- ------- ------ ----- ----------- ------------

pubs 2 MB sa 5 Jun 3 1988 select into

/bulkcopy

(1 row affected)

device size usage

----------------- --------- --------------

master 2 MB data and log

(1 row affected)

Si la opción está desactivada, el informe generado por sp_helpdb así lo indica. Sólo el administrador del sistema o el propietario de la base de datos pueden definir las opciones de base de datos.

Si la opción de base de datos select into/bulkcopy está activada, puede utilizar la cláusula select into para crear una tabla nueva permanente sin emplear una instrucción create table . Es posible usar select into en una tabla temporal, incluso si la opción no está activada.

Note: Dado que select into es una operación no registrada, use dump database para realizar una copia de seguridad de la base de datos después de un select into . No utilice dump transaction , puesto que un volcado del diario después de una operación no registrada no es utilizable con load transaction .

A diferencia de una vista que muestra parte de una tabla, una tabla creada con select into es una entidad diferente e independiente. Consulte el Capítulo 9 para obtener información detallada sobre las vistas.

La tabla nueva se basa en las columnas especificadas en la lista de selección, las tablas indicadas en la cláusula from y las filas elegidas en la cláusula where . El nombre de la tabla nueva debe ser único en la base de datos y cumplir con las reglas para identificadores.

Una instrucción select con una cláusula into permite definir una tabla y poner datos en ella, basándose en definiciones y datos existentes, sin realizar el proceso de definición de datos habitual.

El siguiente ejemplo muestra una instrucción select into y sus resultados. Se crea una tabla llamada newtable a partir de dos de las cuatro columnas de la tabla publishers . Dado que esta instrucción concreta no incluye ninguna cláusula where , los datos de todas las filas (pero sólo dos de las columnas) se copian en newtable .

select pub_id, pub_name

into newtable

from publishers

(3 rows affected)

El mensaje de SQL Server "3 rows affected" se refiere a las tres filas insertadas en newtable . Este es el aspecto de newtable :

select *

from newtable

pub_id pub_name

------ ------------------------------------

0736 New Age Books

0877 Binnet & Hardley

1389 Algodata Infosystems

(3 rows affected)

La tabla nueva contiene los resultados de la instrucción select y pasa a formar parte de la base de datos, al igual que su tabla madre. La cláusula into resulta útil para crear tablas de prueba, tablas nuevas como copias de tablas existentes, y para generar varias tablas pequeñas a partir de una grande. También se puede utilizar select into para crear una tabla base sin datos mediante la colocación de una condición falsa en la cláusula where . Por ejemplo:

Page 118: 80575032 Libro de SQL y Tl SQL Excelente

Page 118 of 280

select *

into newtable2

from publishers

where 1=2

(0 rows affected)

select *

from newtable2

pub_id pub_name city state

---------------------- -----------

(0 rows affected)

No se inserta ninguna fila en la tabla nueva, porque 1 nunca es igual a 2.

También puede utilizar select into con funciones agregadas para crear tablas con datos de totalización:

select type, "Total_amount" = sum(advance)

into #whatspent

from titles

group by type

(6 rows affected)

select * from #whatspent

type Total_amount

------------ ------------------------

UNDECIDED NULL

business 25,125.00

mod_cook 15,000.00

popular_comp 15,000.00

psychology 21,275.00

trad_cook 19,000.00

(6 rows affected)

Siempre debe proporcionarse un nombre de columna para cualquier columna de la tabla de resultados de select into que resulte de una función agregada o de cualquier otra expresión, como la realización de operaciones aritméticas ( amount*2 ), la concatenación ( lname + fname ) o el uso de funciones incorporadas de SQL Server ( lower(lname) ). A continuación se muestra un ejemplo del uso de la concatenación:

select au_id,

"Full_Name" = au_fname + ' ' + au_lname

into #g_authortemp

from authors

where au_lname like "G%"

(3 rows affected)

select * from #g_authortemp

au_id Full_Name

----------- -------------------------

213-46-8915 Marjorie Green

472-27-2349 Burt Gringlesby

527-72-3246 Morningstar Greene

(3 rows affected)

Selección de una columna IDENTITY

Para seleccionar una columna IDENTITY en una tabla nueva, hay que incluir el nombre de la columna (o la palabra clave syb_identity ) en la lista de columnas de la instrucción de selección. La columna nueva hereda la propiedad IDENTITY, a menos que se cumpla alguna de las siguientes condiciones:

La columna IDENTITY está seleccionada más de una vez.

La columna IDENTITY está seleccionada como parte de una expresión.

La instrucción select contiene una cláusula group by , función agregada, operador union o combinación.

Adición de una nueva columna IDENTITY con select into

Para definir una nueva columna IDENTITY en una instrucción select into , hay que añadir la definición de columna antes de la cláusula into . Observe que la definición incluye la precisión de la columna, pero no su escala:

Page 119: 80575032 Libro de SQL y Tl SQL Excelente

Page 119 of 280

select column_list

identity_column_name = identity( precision )

into table_name

from table_name

No es posible utilizar select into para crear una tabla nueva con múltiples columnas IDENTITY. Si la instrucción select incluye una columna IDENTITY existente y una especificación IDENTITY nueva, la instrucción no se ejecuta correctamente.

Para obtener más información sobre columnas IDENTITY, consulte select y la sección sobre columnas IDENTITY en el Manual de Referencia de SQL Server .

Omisión de tablas

El comando para quitar una tabla de una base de datos es drop table . Su sintaxis es:

drop table [[ database .] owner .] table_name

[, [[ database .] owner .] table_name ]...

Cuando se ejecuta este comando, SQL Server quita las tablas especificadas de la base de datos, junto con su contenido y todos los índices y privilegios asociados a ellas. Las reglas o valores predeterminados vinculados a la tabla dejan de estar vinculados, pero no son afectados.

Es necesario ser el propietario de una tabla para poder omitirla. Sin embargo, nadie puede omitir una tabla mientras está en uso, es decir, mientras un usuario o un programa frontal la está leyendo o escribiendo. El comando drop table no puede utilizarse en ninguna de las tablas del sistema, en la base de datos master ni en una base de datos de usuario.

Como indica la sintaxis, el usuario puede omitir una tabla de otra base de datos siempre que sea propietario de la tabla.

Si elimina todas las filas de una tabla (con delete ) o utiliza el comando truncate table , la tabla continuará existiendo hasta que se omita (con drop ).

El permiso drop table y truncate table no puede transferirse a otros usuarios.

Alteración de tablas existentes

Si cambia de opinión sobre la estructura de una tabla después de haberla utilizado durante algún tiempo y decide que es necesario modificar la manera en que está definida, tiene estas alternativas:

Añadir columnas y restricciones, omitir restricciones o cambiar valores predeterminados de columna mediante el comando alter table .

Cambiar el nombre de una tabla, columna o cualquier otro objeto de base de datos con el procedimiento del sistema sp_rename .

Cambio de las estructuras de tabla: alter table

El comando alter table permite realizar los siguientes cambios en tablas existentes:

Añadir columnas (salvo columnas de tipo de datos bit )

Añadir restricciones

Omitir restricciones

Sustituir los valores predeterminados definidos para sus columnas

A continuación se muestra la sintaxis de alter table :

alter table [ database .[ owner ].] table_name

{add column_name datatype

[default { constant_expression | user | null}]

{[{identity | null}]

| [[constraint constraint_name ]

{{unique | primary key}

[clustered | nonclustered]

[with {fillfactor | max_rows_per_page} = x]

Page 120: 80575032 Libro de SQL y Tl SQL Excelente

Page 120 of 280

[on segment_name ]

| references [[ database .] owner .] ref_table

[( ref_column )]

| check ( search_condition )}]}...

{[, next_column ]}...

| add {[constraint constraint_name ]

{unique | primary key}

[clustered | nonclustered]

( column_name [{, column_name }...])

[with {fillfactor | max_rows_per_page} = x]

[on segment_name ]

| foreign key ( column_name [{, column_name }...])

references [[ database .] owner .] ref_table

[( ref_column [{, ref_column }...])]

| check ( search_condition )}

| drop constraint constraint_name

| replace column_name

default { constant_expression | user | null}}

El número de columnas de una tabla no puede ser superior a 250, tanto si se añaden con una instrucción alter table como si se definen con la instrucción create table original.

Una tabla sólo puede tener una columna IDENTITY con un tipo de datos numeric y una escala de cero. Cuando se añade una columna IDENTITY con la instrucción alter table, SQL Server asigna un valor secuencial único a cada fila existente.

Todas las demás columnas que se añadan deben permitir valores nulos. Esto se debe a que, cuando se añade la columna nueva a las filas existentes, debe tener algún valor. Hay que especificar null cuando se añade una columna diferente a la columna IDENTITY.

Note: Si los procedimientos almacenados que utilizan select * hacen referencia a una tabla alterada, el procedimiento, aunque se utilice la opción with recompile , no tomará ninguna columna nueva que pueda haberse añadido a la tabla. Es preciso omitir el procedimiento y volver a crearlo.

Por ejemplo, se puede añadir una columna a la tabla friends_etc de la siguiente manera:

alter table friends_etc

add country varchar(20) null

Luego se puede añadir una o más restricciones de integridad a la columna nueva (o a cualquier otra columna) de friends_etc :

alter table friends_etc

add constraint no_old_country

check (country not in ("GDR", "E. Germany",

"East Germany"))

Cuando no se necesita una restricción, puede omitirse:

alter table friends_etc

drop constraint no_old_country

Para omitir restricciones, especifique el nombre de restricción. Si desea determinar los nombres de las restricciones definidas para una tabla, utilice el procedimiento almacenado del sistema sp_helpconstraint , descrito en "Uso de sp_helpconstraint en tablas".

alter table también permite cambiar el valor predeterminado definido para una columna (o añadir un valor predeterminado de columna si no existe ninguno). Por ejemplo:

alter table friends_etc

replace country default "USA"

Para obtener más información sobre valores predeterminados de columna y restricciones de integridad, consulte la sección "Definición de restricciones de integridad para tablas".

Page 121: 80575032 Libro de SQL y Tl SQL Excelente

Page 121 of 280

Cambio de nombre de tablas y otros objetos

Para cambiar el nombre de las tablas y otros objetos de base de datos (vistas, índices, reglas, valores predeterminados, procedimientos y disparadores), utilice el procedimiento del sistema sp_rename . Para cambiar el nombre de un objeto, es necesario ser el propietario.

Para cambiar el nombre de la base de datos, utilice el procedimiento del sistema sp_renamedb . Consulte el Manual de Referencia de SQL Server para obtener información sobre sp_renamedb .

Esta es la sintaxis de sp_rename :

sp_rename objname , newname

Por ejemplo, para cambiar el nombre de friends_etc a infotable , escriba lo siguiente:

sp_rename friends_etc, infotable

También puede utilizarse sp_rename para cambiar el nombre de otros objetos: columnas, valores predeterminados, reglas, procedimientos, vistas, disparadores, restricciones de verificación, restricciones de integridad de referencia y tipos de datos del usuario. Si cambia el nombre de una columna, use esta sintaxis:

sp_rename "table.column", newcolumnname

Omita el prefijo del nombre de la tabla del nuevo nombre de columna, ya que, de lo contrario, no se aceptará el nombre nuevo. Para cambiar el nombre de un índice, use esta sintaxis:

sp_rename "table.index", newindexname

Una vez más, no incluya el nombre de tabla en el nombre nuevo.

A continuación se indica cómo cambiar el nombre del tipo de datos de usuario tid a t_id :

exec sp_rename tid, "t_id"

No se puede cambiar el nombre de los objetos del sistema ni de los tipos de datos del sistema. El objeto cuyo nombre se está cambiando debe estar en la base de datos actual. Sólo el propietarios de los objetos puede cambiar los nombres de los mismos. Sin embargo, el propietario de la base de datos puede cambiar el nombre de cualquier objeto de usuario.

El usuario sólo puede cambiar los nombres de los objetos que son de su propiedad. El propietario de la base de datos puede cambiar el nombre de cualquier objeto de usuario.

Efecto del cambio de nombre en objetos dependientes

Los procedimientos, disparadores y vistas que dependen de un objeto cuyo nombre se ha cambiado funcionan bien hasta que se vuelven a compilar. Sin embargo, la recompilación tiene lugar por diversas razones y sin notificación al usuario, por ejemplo, si se carga una base de datos, o si un usuario omite y vuelve a crear una tabla u omite un índice.

Cuando SQL Server vuelve a compilar el procedimiento, disparador o vista, éstos dejan de funcionar. El usuario debe cambiar su texto para reflejar el nombre de objeto nuevo. Además, el nombre de objeto antiguo aparecerá en los resultados de la consulta hasta que el procedimiento, disparador o vista se haya cambiado y vuelto a compilar. La forma más segura es cambiar las definiciones de cualquier objeto dependiente al ejecutar sp_rename . El procedimiento del sistema sp_depends proporciona una lista de objetos dependientes.

Asignación de permisos a los usuarios

Los comandos grant y revoke de SQL controlan el sistema de protección de objetos y comandos de SQL Server. Pueden concederse diversos tipos de permisos a los usuarios, grupos y roles mediante el comando grant y revocarse con el comando revoke . grant y revoke se usan a fin de conceder permisos a los usuarios para:

Crear bases de datos

Crear objetos en una base de datos

Page 122: 80575032 Libro de SQL y Tl SQL Excelente

Page 122 of 280

Tener acceso a tablas, vistas y columnas

Ejecutar procedimientos almacenados

Algunos comandos pueden ser utilizados por cualquier usuario a cualquier hora, sin necesidad de permiso alguno. Otros sólo los pueden emplear los usuarios con un estado determinado (por ejemplo, el administrador del sistema), y no es posible transferirlos.

La capacidad de asignar permisos para los comandos que pueden concederse y revocarse depende del estado de cada usuario (administrador del sistema, propietario de la base de datos o propietario del objeto de base de datos) o de si un usuario concreto recibió un permiso con la opción para conceder este permiso a otro usuario.

El propietario de una base de datos no recibe permisos sobre objetos que son propiedad de otros usuarios de forma automática. Sin embargo, el propietario de la base de datos o el administrador del sistema pueden adoptar cualquier permiso asumiendo la identidad del propietario del objeto mediante el comando setuser y escribiendo la instrucción grant o revoke apropiada.

Es posible asignar dos clases de permisos con grant y revoke : permisos de acceso a objetos y permisos de creación de objetos .

Los permisos de acceso a objetos controlan el uso de determinados comandos que proporcionan acceso a objetos de base de datos concretos. Por ejemplo, el usuario debe recibir explícitamente el permiso para usar el comando select con la tabla authors . Los permisos de acceso a objetos los concede y revoca el propietario del objeto en cuestión.

La siguiente instrucción concede a Mary y Joe permiso de acceso a objetos para realizar operaciones con insert y delete en la tabla titles :

grant insert, delete

on titles

to mary, joe

Los permisos de creación de objetos controlan el uso de los comandos que crean objetos y sólo pueden ser concedidos por el administrador del sistema o el propietario de la base de datos.

La siguiente instrucción revoca el permiso de creación de objetos para crear tablas y reglas en la base de datos actual de Mary:

revoke create table, create rule

from mary

Para obtener información completa sobre el uso de grant y revoke para los permisos de acceso a objetos y de creación de objetos, consulte la Guía del Usuario de las Características de Seguridad .

Obtención de información sobre bases de datos y tablas

SQL Server proporciona varios procedimientos almacenados del sistema para obtener información sobre bases de datos, tablas y otros objetos de base de datos. En esta sección se describen cuatro de ellos: sp_help , sp_helpdb , sp_helpconstraint y sp_spaceused .

Para obtener información completa sobre los procedimientos del sistema, consulte el Manual de Referencia de SQL Server .

Uso de sp_help en objetos de base de datos

El procedimiento del sistema sp_help proporciona información sobre un objeto de base de datos especificado (es decir, cualquier objeto enumerado en sysobjects ), un tipo de datos especificado (enumerado en systypes ) o todos los objetos y tipos de datos de la base de datos actual.

Esta es la sintaxis de sp_help :

sp_help [ objname ]

A continuación se muestra la salida de la tabla publishers :

Page 123: 80575032 Libro de SQL y Tl SQL Excelente

Page 123 of 280

Name Owner Type

-------------------------- ----------- --------

publisher dbo user table

Data_located_on_segment When_created

------------------------------ --------------------

default Jan 1 1900 12:00AM

Column_name Type Length Prec Scale

----------- ------- ------ ----- -----

pub_id char 4 NULL NULL

pub_name varchar 40 NULL NULL

city varchar 20 NULL NULL

state char 2 NULL NULL

Nulls Default_name Rule_name Identity

----- ------------- --------- --------

0 NULL NULL 0

1 NULL NULL 0

1 NULL NULL 0

1 NULL NULL 0

index_name index_description index_keys

-------------- ------------------------------------ ----------

pubind clustered, unique located on default pub_id

(1 row affected)

keytype object related_object object_keys

related_keys

------- ---------- -------------- -----------------------------

--------------------------

primary publishers -- none -- pub_id, *, *, *, *, *, *, *

*, *, *, *, *, *, *, *

foreign titles publishers pub_id, *, *, *, *, *, *, *

pub_id, *, *, *, *, *, *, *

(return status = 0)

Si ejecuta sp_help sin suministrar un nombre de objeto, el informe resultante muestra una lista breve de cada objeto de sysobjects , con su nombre, propietario y tipo de objeto. También muestra cada tipo de datos definido por el usuario de systypes y su nombre, tipo de almacenamiento y longitud, si se admiten valores nulos, y los nombres de los valores predeterminados o reglas vinculados a él. El informe indica, además, si se han definido columnas de claves primarias o externas para una tabla o vista con los procedimientos del sistema sp_primarykey o sp_foreignkey .

sp_help muestra los índices de una tabla, incluidos los índices creados mediante la definición de restricciones unique o primary key de instrucciones create table o alter table . Sin embargo, no ofrece información sobre las restricciones de integridad definidas para una tabla. Para obtener información sobre las restricciones de integridad, utilice sp_helpconstraint .

Uso de sp_helpdb en bases de datos

El procedimiento del sistema sp_helpdb proporciona información sobre una base de datos especificada, o sobre todas las bases de datos de SQL Server. sp_helpdb muestra información sobre el nombre, tamaño y uso de cada fragmento asignado a la base de datos con create o alter database . Su sintaxis es:

sp_helpdb [ dbname ]

A continuación se muestra cómo obtener un informe sobre pubs2 :

sp_helpdb pubs2

name db_size owner dbid created status

----- ------- ------ ---- --------------- -------------

pubs2 2 MB sa 4 Jan 10 1988 no se ha establecido ninguna opción

(1 row affected)

device size usage

----------------- ----------- --------------

pubsdev 2 MB data + log

(1 row affected)

Uso de sp_helpconstraint en tablas

Page 124: 80575032 Libro de SQL y Tl SQL Excelente

Page 124 of 280

El procedimiento del sistema sp_helpconstraint proporciona información sobre cualquier restricción de integridad especificada para una tabla. Esta información incluye el nombre de la restricción y la definición del valor predeterminado, restricción de clave única o primaria , restricción de referencia o restricción de verificación. Su sintaxis es:

sp_helpconstraint objname [, detail]

De forma predeterminada, sp_helpconstraint imprime sólo el nombre y la definición de la restricción de integridad. Si especifica la opción detail con este procedimiento del sistema, también se obtiene información sobre el usuario de la restricción o mensajes de error.

Por ejemplo, suponga que la tabla states se define así:

create table states

(rank smallint,

abbrev char(2),

name varchar(20) null,

population int check (population > 1000000),

constraint stateconstr primary key (rank, abbrev))

Para conseguir información sobre sus restricciones, ejecute sp_helpconstraint :

sp_helpconstraint states

name defn

----------------------- ---------------------------------------

states_popula_1088006907 CHECK (population > 1000000)

stateconstr PRIMARY KEY INDEX (rank, abbrev):

CLUSTERED,FOREIGN REFERENCE

(3 rows affected, return status = 0)

Uso de sp_spaceused en tablas

Para saber la cantidad de espacio que utiliza una tabla, utilice el procedimiento del sistema sp_spaceused . Su sintaxis es:

sp_spaceused [ objname ]

Este procedimiento del sistema también funciona con índices, que se describen en el Capítulo 11, "Creación de índices en tablas". sp_spaceused calcula y muestra el número de filas y páginas de datos utilizadas por una tabla o un índice agrupado o no agrupado. A continuación se muestra cómo obtener un informe sobre el espacio empleado por la tabla titles :

sp_spaceused titles

name rows reserved data index_size unused

------- ----- ---------- ----- --------- ------

titles 18 48 KB 6 KB 4 KB 38 KB

(0 rows affected)

Si no se introduce ningún nombre de objeto como parámetro, sp_spaceused muestra un resumen del espacio utilizado por todos los objetos de base de datos.

Chapter 8

Adición, modificación y eliminación de datos

Una vez que haya creado una base de datos, tablas e índices, querrá introducir datos en las tablas y trabajar con ellos (añadiendo, modificando y eliminando datos, según lo necesario).

En este capítulo se trata lo siguiente:

Introducción general a las formas en que se modifican datos

Reglas asociadas con la introducción de datos para determinados tipos de datos

Adición de nuevos datos en las tablas

Modificación de datos existentes en tablas

Modificación de datos text

Page 125: 80575032 Libro de SQL y Tl SQL Excelente

Page 125 of 280

Eliminación de datos de tablas

Eliminación (o truncado) de todas las filas de una tabla

Opciones disponibles para la modificación de datos

Reglas para la introducción de tipos de datos

Adición de datos nuevos

Modificación de datos existentes

Modificación de datos text e image

Eliminación de datos

Eliminación de todas las filas de una tabla

Opciones disponibles para la modificación de datos

El comando insert permite añadir nuevas filas a la base de datos. El comando update permite cambiar las filas existentes en la base de datos. El comando delete permite eliminar filas de la base de datos. El comando writetext permite añadir y modificar datos de tipo text e image sin escribir cambios largos en el diario de transacciones del sistema.

Estas operaciones se denominan colectivamente instrucciones de modificación de datos . El comando truncate table , que elimina todas las filas de una tabla, también se explica en este capítulo. Otro método para añadir datos a una tabla es transferirlos desde un archivo mediante el programa de utilidad de copia masiva, bcp . Para obtener información sobre estas facilidades, consulte el Manual de Referencia de SQL Server y el manual sobre utilidades de su sistema operativo.

Mediante las instrucciones insert , update o delete , es posible modificar datos en una sola tabla por instrucción. Sin embargo, las modificaciones que realice pueden basarse en los datos de otras tablas, e incluso de otras bases de datos. Esta es una mejora de Transact-SQL con respecto a las versiones estándar de SQL.

Los comandos de modificación de datos pueden aplicarse a las vistas además de a las tablas, aunque con algunas restricciones. Consulte el Capítulo 9, "Vistas: limitación del acceso a datos", para obtener más detalles al respecto.

Permisos

Los comandos de modificación de datos no están necesariamente a disposición de todos los usuarios. El propietario de la base de datos y los propietarios de los objetos de base de datos usan los comandos grant y revoke para decidir quiénes tendrán acceso a las distintas funciones de modificación de datos.

Es posible conceder permisos o privilegios a usuarios individuales, a grupos o a los usuarios en general, para cualquier combinación de comandos de modificación de datos. Los permisos se tratan en la Guía del Usuario de las Características de Seguridad .

Integridad de referencia

insert , update , delete , writetext y truncate table permiten modificar los datos de la base de datos. Sin embargo, si modifica los datos de una tabla sin alterar los datos relacionados de otras tablas, pueden producirse disparidades.

Por ejemplo, si descubre que la entrada au_id correspondiente a Sylvia Panteley es incorrecta y la cambia en la tabla authors , también deberá cambiarla en la tabla titleauthor y en cualquier otra tabla de la base de datos que contenga una columna con ese valor. Si no lo hace, no podrá encontrar datos como los nombres de los libros de Sylvia Panteley, porque será imposible realizar combinaciones con su columna au_id .

El problema general de mantener la consistencia de las modificaciones de datos en todas las tablas de una base de datos se denomina integridad de referencia. Una forma de solucionar este problema es crear procedimientos especiales, llamados disparadores, que se activan automáticamente al ejecutar los comandos insert , update y delete en tablas o columnas concretas (el comando truncate table no es atrapado por los disparadores). Otra posibilidad es definir restricciones de integridad de referencia para la tabla. Los disparadores se tratan en el Capítulo 15, "Disparadores: imposición de la integridad de referencia" y las restricciones de integridad en el Capítulo 7, "Creación de bases de datos y tablas".

Transacciones

En el diario de transacciones se escribe una copia del estado antiguo y nuevo de cada fila afectada por las distintas instrucciones de modificación, con excepción de writetext . Esto significa que si comienza una transacción ejecutando el

Page 126: 80575032 Libro de SQL y Tl SQL Excelente

Page 126 of 280

comando begin transaction , advierte que ha cometido un error y revierte la transacción, puede restaurar la base de datos a su estado anterior.

Note: Los cambios realizados en un SQL Server remoto mediante una llamada de procedimientos remotos (RPC) no se pueden revertir.

El modo de funcionamiento predeterminado de writetext no registra las transacciones. Esto evita que el diario de transacciones se llene con los larguísimos bloques de datos que pueden contener los campos text e image . Para registrar los cambios realizados con este comando, utilice la opción with log del comando writetext .

En el Capítulo 17, "Transacciones: mantenimiento de la consistencia y recuperación de datos". encontrará una explicación más completa sobre las transacciones.

Uso de la base de datos de muestra

Si sigue los ejemplos de este capítulo en su pantalla, es conveniente comenzar con una copia limpia de la base de datos pubs2 y limpiarla al terminar. Consulte al administrador del sistema para obtener una copia limpia de la base de datos pubs2 .

Si comienza con una copia limpia de la base de datos pubs2 , puede evitar que los cambios realizados sean permanentes incluyendo todas las instrucciones en una transacción y abortando la transacción una vez que termine con este capítulo. Inicie la transacción escribiendo lo siguiente:

begin tran modify_pubs2

Esta transacción se llama modify_pubs2 . Se puede cancelar la transacción en cualquier momento y restaurar la base de datos a la situación original, escribiendo:

rollback tran modify_pubs2

Reglas para la introducción de tipos de datos

Varios tipos de datos suministrados por SQL Server tienen reglas especiales para introducir y buscar datos. Estas reglas se detallan en los siguientes apartados. Para obtener más información sobre los tipos de datos, consulte el Capítulo 7, "Creación de bases de datos y tablas".

char , nchar , varchar , nvarchar y text

No olvide que todos los datos character , text y datetime se deben escribir entre comillas simples o dobles al ser introducidos y cuando se buscan. Utilice comillas simples si la opción quoted_identifier está definida como on (activada). Si emplea comillas dobles, SQL Server tratará el texto como un identificador. Consulte el Manual de Referencia de SQL Server para obtener más detalles sobre la inserción de datos text .

Si introduce cadenas más largas que la longitud especificada de una columna char , nchar, varchar o nvarchar , la entrada queda truncada. Active la opción string_rtruncation para recibir un mensaje de aviso cuando esto ocurra.

Hay dos formas de especificar comillas literales dentro de una entrada de caracteres. El primer método consiste en utilizar dos comillas. Por ejemplo, si comienza una entrada de caracteres con una comilla simple y desea incluir otra como parte de la entrada, emplee dos comillas simples seguidas: 'I don' 't understand'. Con comillas dobles: "He said, ""It's not really confusing""" .

El segundo método consiste en incluir una comilla entre comillas del otro tipo. En otras palabras, sitúe una entrada con comillas dobles entre comillas simples, o viceversa. Por ejemplo: 'George said, "There must be a better way" '.

Para introducir una cadena de caracteres más larga que la anchura de la pantalla, introduzca una barra invertida (\) antes de pasar a la siguiente línea.

La palabra clave like y los caracteres comodín descritos en el Capítulo 2, "Consultas: selección de datos de una tabla", pueden utilizarse para buscar datos de tipo character , text y datetime .

Consulte la sección sobre tipos de datos en el Manual de Referencia SQL Server para obtener información sobre los espacios en blanco finales en los datos character .

Page 127: 80575032 Libro de SQL y Tl SQL Excelente

Page 127 of 280

datetime y smalldatetime

Los formatos de visualización y de entrada de los datos datetime proporcionan una amplia gama de formatos de salida para las fechas, además de reconocer numerosos formatos de entrada. Los formatos de visualización y de entrada se controlan por separado. El formato de visualización predeterminado proporciona una salida que tiene el siguiente aspecto: "Apr 15 1987 10:23PM". El comando convert proporciona varias opciones para mostrar los segundos y milisegundos y presentar la fecha con ordenaciones distintas de sus componentes. Consulte el Capítulo 10, "Uso de funciones incorporadas en consultas", para obtener más información sobre la presentación de los valores de fecha.

SQL Server reconoce una amplia gama de formatos de entrada de datos para las fechas. Las mayúsculas y minúsculas siempre se ignoran y los espacios pueden tener cualquier ubicación entre los componentes de la fecha. Cuando introduzca valores de tipo datetime y smalldatetime , inclúyalos siempre entre comillas simples o dobles (use comillas simples si la opción quoted_identifier está activada; si emplea comillas dobles, SQL Server tratará la entrada como si fuera un identificador).

SQL Server reconoce por separado las dos partes (fecha y hora) de los datos, de modo que puede situar la hora antes o después de la fecha y omitir cualquiera de las dos partes. SQL Server proporciona valores predeterminados, descritos también a continuación. Si se omiten las dos partes, la fecha predeterminada es el 1 de enero de 1900, 12:00:00:000AM (January 1, 1900, 12:00:00:000AM).

Para datetime, la fecha más antigua que puede usarse es el 1 de enero de 1753 (January 1, 1753) y la última el 31 de diciembre de 9999 (December 31, 9999). Para smalldatetime , la fecha más antigua que puede usarse es el 1 de enero de 1900 y la última el 6 de junio de 2079 (June 6, 2079). Las fechas anteriores o posteriores se deben introducir, almacenar y manipular como valores char o varchar . SQL Server rechaza todos los valores que no puede reconocer como fechas comprendidas en los márgenes indicados.

Introducción de horas

El orden de los componentes de la hora es relevante para la parte horaria de los datos. Introduzca las horas, minutos y segundos, en este orden, y después AM, am, PM o pm. 12AM es medianoche y 12PM es mediodía. Para que un valor se reconozca como una hora, debe contener un signo de dos puntos (:) o el calificador AM/PM. Observe que smalldatetime sólo precisa hasta los minutos.

Los milisegundos pueden ir precedidos de un signo de dos puntos o de un punto. Si van precedidos de dos puntos, el número expresará milésimas de segundo y, si van precedidos de un punto, un solo dígito indicará décimas de segundo, dos dígitos centésimas de segundo y tres dígitos, milésimas de segundo. Por ejemplo, '12:30:20:1' expresa las 12:30 y 20 segundos y una milésima de segundo, mientras que '12:30:20.1' expresa las 12:30 y 20 segundos y una décima de segundo

A continuación se indican algunos de los formatos aceptables para la hora:

14:30

14:30[:20:999]

14:30[:20.9]

4am

4 PM

[0]4[:30:20:500]AM

Introducción de fechas

El comando set dateformat permite especificar el orden de los componentes de las fechas (mes, día y año) cuando se introducen como cadenas de números con separadores. Cambiar de idioma con set language también puede afectar al formato de fechas, según el formato de fecha predeterminado del idioma. El idioma predeterminado es us_english y el formato de fecha predeterminado es mdy . Consulte el comando set en el Manual de Referencia de SQL Server para obtener más información al respecto.

Note: dateformat sólo afecta a las fechas introducidas como números con separadores, como "4/15/90" o "20.05.88". No afecta a las fechas en las que el mes se indica en formato alfanumérico, como "April 15, 1990", o en las que no hay separadores, como "19890415".

SQL Server reconoce tres estilos básicos para la introducción de fechas. Cada uno de los formatos de fecha indicados a continuación debe ir entre comillas cuando se utilice y puede estar precedido o seguido de una especificación horaria, según lo descrito anteriormente.

El mes se introduce en formato alfanumérico.

Page 128: 80575032 Libro de SQL y Tl SQL Excelente

Page 128 of 280

o El mes puede ser una abreviatura de 3 caracteres o el nombre completo del mes, de acuerdo con la especificación del idioma utilizado.

o Las comas son opcionales. o No se realiza distinción entre mayúsculas y minúsculas. o Si sólo especifica los dos últimos dígitos del año, los valores menores que 50 se interpretan como "20yy"

("20aa"), mientras que el 50 y los valores mayores que 50 se interpretan como "19yy" ("19aa"). o Escriba el siglo sólo si omite el día o necesita especificar un siglo que no sea el predeterminado, según lo

descrito anteriormente. o Si falta el día en la fecha, se le asigna el primer día del mes predeterminadamente. o Cuando se especifica el mes en formato alfabético, el parámetro de dateformat (consulte el comando set )

siempre se ignora. o Estos son formatos válidos para especificar la fecha alfabéticamente:

Apr[il] [15][,] 1988

Apr[il] 15[,] [19]88

Apr[il] 1988 [15]

[15] Apr[il][,] 1988

15 Apr[il][,] [19]88

15 [19]88 apr[il]

[15] 1988 apr[il]

1988 APR[IL] [15]

[19]88 APR[IL] 15

1988 [15] APR[IL]

El mes se introduce con formato numérico en una cadena con separadores de barra (/), guión (-) o punto (.). o Se debe especificar el mes, día y año. o Las cadenas deben tener el siguiente formato: <num> <sep> <num> <sep> <num> [ <time spec> ] o

bien: [ <time spec> ] <num> <sep> <num> <sep> <num> o La interpretación de los valores que componen las fechas depende del parámetro de dateformat . Si el

orden no coincide con el parámetro, los valores no se interpretan como fechas, por estar fuera de margen, o se interpretan incorrectamente. Por ejemplo, "12/10/08" podría interpretarse como seis fechas distintas, dependiendo del parámetro de dateformat . Consulte el comando set para obtener más información al respecto.

o Para introducir "15 de abril de 1988" (April 15, 1988) en el orden mdy de dateformat , se pueden usar estos formatos:

[0]4/15/[19]88

[0]4-15-[19]88

[0]4.15.[19]88

Los demás órdenes de introducción se muestran a continuación con barras (''/") como separadores, aunque también pueden emplearse guiones o puntos:

15/[0]4/[19]88 (dmy)

[19]88/[0]4/15 (ymd)

[19]88/15/[0]4 (ydm)

[0]4/[19]88/15 (myd)

15/[19]88/[0]4 (dym)

La fecha se proporciona como una cadena de 4, 6 u 8 dígitos no separados, como una cadena vacía o con la hora, pero sin valores de fecha.

o El parámetro de dateformat siempre se ignora con este formato de entrada. o Si se introducen 4 dígitos, la cadena se interpreta como el año, mientras que el mes y el día se definen como

el 1 de enero. No es posible omitir el siglo. o Las cadenas de 6 y 8 dígitos siempre se interpretan como ymd; el mes y el día siempre deben tener 2

dígitos. El siguiente formato se reconoce: [19]880415 o Si se introduce una cadena vacía (" ") o no se indica fecha, se interpreta como la fecha base, el 1 de enero

de 1900. Por ejemplo, un valor horario de "4:33" sin ninguna fecha se interpreta como "January, 1, 1900, 4:33AM''.

Búsqueda de fechas y horas

Es posible utilizar la palabra clave like y los caracteres comodín con datos de tipo datetime y smalldatetime , así como con char , nchar, varchar , nvarchar y text . Cuando se usa like con valores datetime o smalldatetime , SQL Server convierte las fechas al formato estándar de datetime y luego a varchar . Puesto que el formato de visualización estándar no incluye segundos ni milisegundos, éstos no pueden buscarse con like y un patrón de coincidencia. Utilice la función de conversión de tipo , convert , para buscar los segundos y milisegundos.

Page 129: 80575032 Libro de SQL y Tl SQL Excelente

Page 129 of 280

Es conveniente usar like para buscar valores datetime o smalldatetime , dado que las entradas de estos tipos de datos pueden contener diversos componentes de fecha. Por ejemplo, si inserta el valor "9:20" en una columna llamada arrival_time , la cláusula:

where arrival_time = '9:20'

no lo encontraría, ya que SQL Server convierte la entrada en "Jan 1, 1900 9:20AM". Sin embargo, la siguiente cláusula sí lo encontraría:

where arrival_time like '%9:20%'

Si utiliza like y el día del mes es inferior a 10, deberá insertar dos espacios entre el mes y el día para hacer coincidir el valor datetime con su conversión a varchar . Igualmente, si la hora es menor que 10, la conversión colocará dos espacios entre el año y la hora. La cláusula like May 2% con un espacio entre "May" y "2" encontrará todas las fechas entre el 20 y el 29 de mayo, pero no el 2 de mayo. No es necesario insertar el espacio adicional con otras comparaciones de fecha, sino sólo con like , ya que los valores de fecha y hora se convierten a varchar sólo para la comparación con like .

binary , varbinary e image

Cuando se introducen o buscan datos binary , varbinary o image , éstos deben ir precedidos de "0x". Por ejemplo, para introducir "FF", teclee "0xFF".

Si introduce cadenas más largas que la longitud especificada de una columna binary o varbinary , la entrada se trunca sin previo aviso.

Una longitud de 10 para una columna binary o varbinary significa 10 bytes, cada uno de los cuales almacena 2 dígitos hexadecimales.

Al crear un valor predeterminado en una columna binary o varbinary , escríbalo precedido de "0x" .

Consulte la sección sobre tipos de datos en el Manual de Referencia de SQL Server para obtener información sobre los ceros finales en los valores hexadecimales.

money y smallmoney

Los valores monetarios introducidos con la notación E se interpretan como float . Esto puede hacer que se rechace una entrada o se pierda precisión al almacenarla como un valor money o smallmoney .

Los valores money y smallmoney pueden introducirse precedidos o no de un símbolo monetario, como el símbolo de dólar ($), el de yen (¥) o el de libra esterlina (£). Para introducir un valor negativo, coloque un signo menos tras el símbolo monetario. No incluya comas en la entrada.

No es posible introducir valores money o smallmoney con comas, aunque el formato de impresión predeterminado de los datos money o smallmoney coloca una coma detrás de cada tres dígitos. Cuando se muestran valores money o smallmoney , se redondean al céntimo más cercano. Todas las operaciones aritméticas excepto el módulo están disponibles con datos money .

float, real y double precision

Los tipos de datos numéricos aproximados, float , real y double precision , se introducen como una mantisa seguida por un exponente opcional. La mantisa puede incluir un signo positivo o negativo y un punto decimal. El exponente, que comienza tras el carácter "e" o "E" , puede incluir un signo, pero no un punto decimal.

Para evaluar los datos numéricos aproximados, SQL Server multiplica la mantisa por 10 elevado al exponente dado. A continuación se muestran algunos ejemplos de datos float , real y double precision :

Tabla 8-1: Evaluación de datos numéricos

Datos introducidos Mantisa Exponente Valor

10E2 10 2 10 * 102

15.3e1 15.3 1 15.3 * 101

-2.e5 -2 5 -2 * 105

Page 130: 80575032 Libro de SQL y Tl SQL Excelente

Page 130 of 280

2.2e-1 2,2 -1 2.2 * 10-1

+56E+2 56 2 56 * 102

La precisión binaria de la columna determina el número máximo de dígitos binarios permitidos en la mantisa. Para las columnas float, puede especificar una precisión de hasta 48 dígitos, mientras que para las columnas real y double precision, la precisión depende de la máquina. Si un valor excede la precisión binaria de una columna, SQL Server coloca un indicador de error en la entrada.

decimal y numeric

Los tipos de datos numéricos exacto s , dec , decimal y numeric , comienzan con un signo positivo o negativo opcional y pueden incluir un punto decimal. El valor de los datos numéricos exactos depende de la precisión ( precision ) y escala (s cale ) decimales de la columna, que se definen mediante la siguiente sintaxis:

datatype [( precision [, scale ])]

SQL Server trata cada combinación de precisión y escala como un tipo de datos concreto. Por ejemplo, numeric (10,0) y numeric (5,0) son dos tipos de datos distintos. La precisión y la escala determinan los límites de los valores que pueden almacenarse en una columna decimal o numeric :

La precisión especifica el número máximo de dígitos decimales que pueden almacenarse en la columna. Incluye todos los dígitos situados a la derecha o izquierda del punto decimal. Puede especificar una precisión de entre 1 y 38 dígitos o usar la precisión predeterminada de 18 dígitos.

La escala especifica el número máximo de dígitos que pueden almacenarse a la derecha del punto decimal y debe ser menor o igual a la precisión. Puede especificar una escala de entre 0 y 38 dígitos o usar la escala predeterminada de 0 dígitos.

Si un valor excede la precisión o la escala de una columna, SQL Server coloca un indicador de error en la entrada. Estos son algunos ejemplos válidos de datos dec y numeric :

Tabla 8-2: Precisiones y escalas válidas para datos numéricos

Datos introducidos Tipo de datos Precisión Escala Valor

12.345 numeric (5,3) 5 3 12.345

-1234.567 dec (8,4) 8 4 -1234.567

Las siguientes entradas exceden la precisión o la escala de la columna y dan errores como resultados:

Tabla 8-3: Precisiones y escalas inválidas para datos numéricos

Datos introducidos Tipo de datos Precisión Escala

1234.567 numeric (3,3) 3 3

1234.567 decimal (6) 6 1

int , smallint y tinyint

Se pueden insertar valores numéricos en las columnas int , smallint y tinyint con la notación E descrita en la sección anterior.

timestamp

No es posible insertar datos en una columna timestamp . Deberá insertar un valor nulo explícito, tecleando "NULL" en la columna, o usar un valor nulo implícito, proporcionando una lista de columnas que se salte la columna timestamp . SQL Server actualiza el valor timestamp automáticamente tras cada inserción o actualización. Consulte "Inserción de datos en columnas específicas" para obtener más información.

Adición de datos nuevos

Se puede utilizar el comando insert para añadir filas a la base de datos de dos formas: con la palabra clave values o con una instrucción select .

Page 131: 80575032 Libro de SQL y Tl SQL Excelente

Page 131 of 280

La palabra clave values se utiliza para especificar valores en algunas o todas las columnas de una fila nueva. Este es un ejemplo simplificado de la sintaxis del comando insert usando la palabra clave values :

insert table_name

values ( constant1 , constant2 , ...)

Se puede emplear una instrucción select dentro de una instrucción insert para obtener valores de una o varias tablas. Este es un ejemplo simplificado de la sintaxis del comando insert usando una instrucción select :

insert table_name

select column_list

from table_list

where search_conditions

Sintaxis de insert

A continuación se muestra la sintaxis completa del comando insert :

insert [into] [ database .[ owner .]]{ table_name | view_name } [( column_list )] {values ( constant_expression [, constant_expression ]...) | select_statement } Note: Cuando se añaden valores text e image con insert , todos los datos se escriben en el diario de transacciones. El comando writetext permite añadir estos valores sin registrar los grandes bloques de datos que pueden conformar los valores text o image . Consulte "Inserción de datos en columnas específicas" y "Modificación de datos text e image".

Adición de nuevas filas con values

Esta instrucción insert añade una nueva fila a la tabla publishers y asigna un valor a cada columna de la fila:

insert into publishers

values ('1622', 'Jardin, Inc.', 'Camden', 'NJ')

Observe que los valores de los datos se escriben en el mismo orden que los nombres de columna de la instrucción create table original, es decir, primero el número de ID, después el nombre, la ciudad y, finalmente, el estado. Los datos de values se colocan entre paréntesis y todos los datos de caracteres van entre comillas simples o dobles.

Utilice una instrucción insert distinta para cada fila que añada.

Inserción de datos en columnas específicas

Es posible añadir datos a algunas columnas de una fila, pero no a todas, especificando estas columnas y los datos que les correspondan. Todas las columnas excluidas de la lista de columnas deben definirse para permitir valores nulos. Las columnas excluidas también aceptan valores predeterminados. Si se salta una columna con un valor predeterminado vinculado a ella, se emplea dicho valor.

Esta forma del comando puede ser especialmente útil para insertar todos los valores de una fila excepto los text o image, y después utilizar writetext para añadir los valores más largos sin que se almacenen en el diario de transacciones. Asimismo, se puede emplear esta forma del comando para saltar los datos de tipo timestamp .

Para añadir datos sólo en dos columnas, por ejemplo, pub_id y pub_name , utilice un comando como el siguiente:

insert into publishers (pub_id, pub_name)

values ('1756', 'The Health Center')

El orden de enumeración de los nombres de columna debe coincidir con el de los valores. El siguiente ejemplo produce los mismos resultados que el anterior:

insert publishers (pub_name, pub_id)

values('The Health Center', '1756')

Ambas instrucciones insert sitúan "1756" en la columna del número de identificación y "The Health Center" en la del nombre del editor. Dado que la columna pub_id de publishers tiene un índice único, no es posible ejecutar las dos instrucciones insert . El segundo intento de insertar "1756" en la columna pub_id produce un mensaje de error.

Page 132: 80575032 Libro de SQL y Tl SQL Excelente

Page 132 of 280

La siguiente instrucción select muestra la fila que se ha añadido a publishers :

select *

from publishers

where pub_name = 'The Health Center'

pub_id pub_name city state

------- ----------------- ------ -------

1756 The Health Center NULL NULL

SQL Server introduce valores nulos en las columnas city y state porque no se ha indicado ningún valor para ellas en la instrucción insert y la tabla publisher permite valores nulos en estas columnas.

Valores generados por SQL Server para columnas IDENTITY

Cuando inserta una fila en una tabla con una columna IDENTITY, SQL Server genera automáticamente el valor de la columna. No incluya el nombre de la columna IDENTITY en la lista de columnas, ni su valor en la lista de valores.

Esta instrucción insert añade una nueva fila a la tabla sales_daily . Observe que la lista de columnas no incluye la columna IDENTITY, row_id :

insert sales_daily (stor_id)

values ("7896")

La siguiente instrucción muestra la fila añadida a sales_daily . SQL Server ha generado automáticamente el siguiente valor secuencial, 2, en row_id :

select * from sales_daily

where stor_id = "7896"

row_id stor_id

------ -------

2 7896

Valores nulos y predeterminados, columnas IDENTITY y errores

Cuando especifica valores sólo para algunas columnas de la fila, puede darse una de estas cuatro situaciones en las columnas sin valores:

Se introduce un valor predeterminado, si existe, en la columna o en el tipo de datos definido por el usuario. Consulte el Capítulo 12, "Definición de valores predeterminados y reglas para datos", o la entrada create default del Manual de Referencia de SQL Server para obtener información detallada.

Se introduce NULL si se especificó el valor nulo al crear la tabla y no existe ningún valor predeterminado para la columna o el tipo de datos. Consulte también la entrada create table del Manual de Referencia de SQL Server .

Se introduce un valor único y secuencial si la columna tiene la propiedad IDENTITY.

Aparece un mensaje de error y la fila no se añade si no se ha especificado el valor nulo y no existe ningún valor predeterminado.

La siguiente tabla muestra lo que aparece bajo estas circunstancias:

Tabla 8-4: Columnas sin valores

Predeterminada? No nula Nula IDENTITY

Sí El valor predeterminado El valor predeterminado Siguiente valor secuencial

No Mensaje de error NULL Siguiente valor secuencial

Se puede usar el procedimiento del sistema sp_help para obtener un informe sobre una tabla o valor predeterminado en particular, o sobre cualquier objeto enumerado en la tabla del sistema sysobjects . Para ver la definición de un valor predeterminado, utilice el procedimiento del sistema sp_helptext .

Inserción explícita de datos en una columna IDENTITY

Page 133: 80575032 Libro de SQL y Tl SQL Excelente

Page 133 of 280

En ocasiones, deseará introducir un valor específico en una columna IDENTITY, en lugar de aceptar el valor generado por el servidor. Por ejemplo, puede que quiera asignar el valor 101, en lugar del 1, a la columna IDENTITY de la primera fila insertada en la tabla, o insertar de nuevo una fila eliminada por error.

Sólo el propietario de la tabla, el propietario de la base de datos o el administrador del sistema pueden insertar un valor de forma explícita en una columna IDENTITY. Antes de insertar los datos, el usuario debe activar la opción identity_insert para la tabla. Sólo es posible activar identity_insert para una tabla de la base de datos cada vez.

Este ejemplo especifica un valor "semilla" de 101 para la columna IDENTITY:

set identity_insert sales_daily on insert into sales_daily (syb_identity, stor_id) values (101, '13-J-9')

Observe que la instrucción insert enumera todas las columnas, incluida IDENTITY, para las que se ha especificado un valor. Cuando la opción identity_insert está activada, todas las instrucciones insert ejecutadas para la tabla deben incluir una lista explícita de columnas. La lista de valores deberá incluir un valor para la columna IDENTITY, puesto que esta columna no admite valores nulos.

Note: SQL Server no impone la exclusividad del valor insertado. Se puede especificar cualquier número entero positivo que esté dentro del margen admitido por la precisión declarada de la columna. Para asegurarse de que sólo se aceptan valores de columna únicos, deberá crear un índice único en la columna IDENTITY antes de insertar las filas.

Restricción de los datos de columna: reglas

Se puede crear una regla y vincularla a una columna o a un tipo de datos definido por el usuario. Las reglas rigen los tipos de datos que pueden añadirse.

Un ejemplo de ello es la columna pub_id de la tabla publishers . Una regla llamada pub_idrule , que especifica los números de identificación de editores válidos, está vinculada a la columna. Las IDs válidas son "1389", "0736", "0877", "1622" y "1756", o cualquier número de cuatro dígitos cuyos primeros dos dígitos sean "99". Si trata de introducir cualquier otro número, obtendrá un mensaje de error.

Si recibe este tipo de mensaje de error, será conveniente examinar la definición de la regla. Utilice el procedimiento del sistema sp_helptext :

sp_helptext pub_idrule --------- 1 (1 row affected) text --------------------------------------------------- create rule pub_idrule as @pub_id in ("1389", "0736", "0877", "1622", "1756") or @pub_id like "99[0-9][0-9]" (1 row affected)

Para obtener información general sobre una regla específica, utilice sp_help . También puede emplear sp_help con un nombre de tabla como parámetro para averiguar si alguna de las columnas definidas en la tabla tiene una regla. En el Capítulo 12, "Definición de valores predeterminados y reglas para datos", se describen las reglas con mayor detalle.

Adición de filas nuevas con select

Para insertar valores en una tabla procedentes de una o más tablas diferentes, incluya una cláusula select en la instrucción insert . La cláusula select permite insertar valores en algunas o todas las columnas de una fila.

La inserción de valores en algunas columnas solamente puede ser útil si se desea tomar valores de una tabla existente. Después, puede usar update para añadir los valores de las demás columnas.

Page 134: 80575032 Libro de SQL y Tl SQL Excelente

Page 134 of 280

Antes de insertar valores en algunas columnas de una tabla, asegúrese de que exista un valor predeterminado o se haya especificado el valor nulo para las columnas donde no van a insertarse valores. De lo contrario, recibirá un mensaje de error.

Cuando se insertan filas de una tabla en otra, ambas tablas deben tener estructuras compatibles, es decir, las columnas coincidentes deben tener el mismo tipo de datos, o bien, tipos de datos que SQL Server convierta automáticamente.

Note: No es posible insertar datos de una tabla que permite valores nulos en una que no los permite, si alguno de los datos insertados es nulo.

Si las columnas están en el mismo orden en sus instrucciones create table respectivas, no es necesario especificar los nombres de las columnas en ninguna de las tablas. Suponga que existe una tabla newauthors que contiene algunas filas de información sobre autores en el mismo formato que authors . Para añadir a authors todas las filas de newauthors :

insert authors select * from newauthors

Para insertar filas en una tabla basada en los datos de otra tabla, no es necesario que las columnas de ambas estén enumeradas en el mismo orden en sus respectivas instrucciones create table . Puede usar las instrucciones insert o select para ordenar las columnas de modo que coincidan.

Por ejemplo, suponga que la instrucción create table de la tabla authors contiene las columnas au_id , au_fname , au_lname y address en este orden, mientras que newauthors contiene au_id , address , au_lname y au_fname . Deberá hacer que ambas secuencias coincidan en la instrucción insert , lo cual puede hacerse de estas dos maneras:

insert authors (au_id, address, au_lname, au_fname)

select * from newauthors

insert authors

select au_id, au_fname, au_lname, address

from newauthors

Si la secuencia de columnas de las dos tablas no coincide, SQL Server no puede completar la operación insert o la completa de forma incorrecta, colocando datos en columnas equivocadas. Por ejemplo, podrían aparecer datos de direcciones en la columna au_lname de nombres.

Columnas calculadas

Se puede usar columnas calculadas en una instrucción select dentro de una instrucción insert . Por ejemplo, suponga que una tabla llamada tmp contiene algunas filas nuevas para la tabla titles con algunos datos obsoletos, y que las cifras de price deben multiplicarse por dos. Una instrucción que permite incrementar los precios e insertar las filas tmp en titles tendría el siguiente aspecto:

insert titles

select title_id, title, type, pub_id, price*2,

advance, total_sales, notes, pubdate, contract

from tmp

Al realizar cálculos en una columna, no es posible usar la sintaxis select * . Cada columna debe especificarse por separado en la lista de selección.

Inserción de datos en algunas columnas

Se puede usar la instrucción select para añadir datos sólo a algunas columnas de una fila, exactamente igual que con la cláusula values . Simplemente, especifique las columnas a las que desea añadir los datos en la cláusula insert .

Por ejemplo, existen algunos autores en la tabla authors que no tienen ningún título y que, por consiguiente, no tienen entradas en la tabla titleauthor . Para extraer sus números de au_id de la tabla authors e insertarlos en la tabla titleauthor como marcadores de lugar, puede probar con esta instrucción:

insert titleauthor (au_id)

select au_id

from authors

where au_id not in

(select au_id from titleauthor)

Page 135: 80575032 Libro de SQL y Tl SQL Excelente

Page 135 of 280

Sin embargo, esta instrucción no es legal, ya que se requiere un valor para la columna title_id . No se permiten valores nulos y tampoco se ha especificado un valor predeterminado. Puede introducir el valor ficticio "xx1111 " para titles_id empleando una constante, como se indica a continuación:

insert titleauthor (au_id, title_id)

select au_id, "xx1111"

from authors

where au_id not in

(select au_id from titleauthor)

La tabla titleauthor contiene ahora cuatro filas nuevas con entradas para la columna au_id , entradas ficticias para title_id y valores nulos para las otras dos columnas.

Inserción de datos de la misma tabla

Se pueden insertar datos en una tabla basados en otros datos de la misma tabla. En esencia, esto significa copiar una fila completa o parte de ella.

Por ejemplo, se puede insertar una nueva fila en la tabla publishers basada en los valores de una fila existente de la misma tabla. Asegúrese de cumplir la regla de la columna pub_id . Así es como se hace:

insert publishers

select "9999", "test", city, state

from publishers

where pub_name = "New Age Books"

(1 row affected)

select * from publishers

pub_id pub_name city state

------- --------------------- ------- ------

0736 New Age Books Boston MA

0877 Binnet & Hardley Washington DC

1389 Algodata Infosystems Berkeley CA

9999 test Boston MA

(4 rows affected)

El ejemplo inserta las dos constantes ("9999" y "test") y los valores de las columnas city y state en la fila que se ajusta a la consulta.

Modificación de datos existentes

Se puede utilizar el comando update para modificar filas independientes, grupos de filas o todas las filas de una tabla. El comando update va seguido del nombre de la tabla o vista. Como ocurre con todas las instrucciones de modificación de datos, sólo es posible cambiar los datos de una tabla cada vez.

El comando update especifica la fila o filas que se desean modificar y los datos nuevos. Estos últimos pueden ser una constante o expresión indicadas por el usuario o datos tomados de otras tablas.

Si una instrucción update viola una restricción de integridad, la actualización no se lleva a cabo y aparece un mensaje de error. La actualización se cancela, por ejemplo, si afecta a la columna IDENTITY de la tabla, o si alguno de los valores añadidos no es del tipo de datos correcto o viola una regla definida para una de las columnas o tipos de datos implicados.

SQL Server no impide ejecutar un comando update que actualice la misma fila más de una vez. Sin embargo, debido a la forma en que se procesa update , las actualizaciones realizadas con una misma instrucción no se acumulan. Es decir, si una instrucción update modifica dos veces la misma fila, la segunda actualización no se basa en los valores resultantes de la primera, sino en los originales. Los resultados son imprevisibles, puesto que dependen del orden de procesamiento.

Consulte el Capítulo 9, "Vistas: limitación del acceso a datos", para obtener información sobre las restricciones de la actualización de vistas.

Note: El comando update se registra. Si está modificando grandes bloques de datos text o image , será conveniente emplear el comando writetext , que no se registra. Además, existe un límite aproximado de 125K por cada instrucción update . Consulte la explicación de writetext en "Modificación de datos text e image".

Page 136: 80575032 Libro de SQL y Tl SQL Excelente

Page 136 of 280

Sintaxis de update

Esta es una versión simplificada de la sintaxis de update para actualizar filas especificadas con una expresión:

update table_name

set column_name = expression

where search_conditions

Por ejemplo, si Reginald Blotchet-Halls decide cambiar su nombre por el de Goodbody Health para potenciar su proceso de visualización, la manera de modificar su fila en la tabla authors es la siguiente:

update authors

set au_lname = "Health", au_fname = "Goodbody"

where au_lname = "Blotchet-Halls"

Esta instrucción de sintaxis simplificada actualiza una tabla basada en datos de otra tabla:

update table_name

set column_name = expression

from table_name

where search_conditions

El siguiente ejemplo actualiza la columna total_sales de la tabla titles para reflejar las ventas más recientes registradas en la tabla salesdetail :

update titles

set total_sales = total_sales + qty

from titles, sales, salesdetail

where titles.title_id = salesdetail.title_id

and salesdetail.stor_id = sales.stor_id

and sales.date in (select max(sales.date) from sales)

En el ejemplo anterior se supone que sólo se registra un conjunto de ventas para un título y una fecha determinados, y que las actualizaciones están al día. La sintaxis completa de update es:

update [[ database .] owner .]{ table_name | view_name }

set [[[ database .] owner .]{ table_name . |

view_name. }] column_name1 =

{ expression1 | null | ( select_statement )}

[, column_name2 = { expression2 | null |

( select_statement )}]...

[from [[ database .] owner .]{ table_name | view_name }

[, [[ database .] owner .]{ table_name |

view_name }]]...

[where search_conditions ]

Uso de la cláusula set con update

La cláusula set especifica las columnas y los valores modificados. La cláusula where determina qué fila o filas se van a actualizar. Observe que, si no incluye una cláusula where , las columnas especificadas de todas las filas se actualizarán con los valores indicados en la cláusula set .

Note: Antes de realizar los ejemplos de esta sección, cerciórese de que sabe cómo volver a instalar la base de datos pubs2 .

Por ejemplo, si todas las editoriales de la tabla publishers trasladan sus sedes principales a Atlanta (Georgia), la tabla se actualiza de la siguiente manera:

update publishers

set city = "Atlanta", state = "GA"

Análogamente, puede sustituir los nombres de todos los editores por NULL con esta instrucción:

update publishers

set pub_name = null

Page 137: 80575032 Libro de SQL y Tl SQL Excelente

Page 137 of 280

También es posible utilizar valores de columnas calculadas en una actualización. Para multiplicar por dos todos los precios de la tabla titles , use esta instrucción:

update titles

set price = price * 2

Puesto que no hay cláusula where , el cambio de precios se aplica a todas las filas de la tabla.

Uso de la cláusula where con update

La cláusula where especifica qué filas deben actualizarse. Por ejemplo, en el caso poco probable de que se cambiara el nombre de California del norte por el de Pacifica (abreviado como PC) y las personas de Oakland votasen cambiar el nombre de su ciudad por uno más interesante, como Big Bad Bay City, esta sería la manera de actualizar la tabla authors para todos los anteriores residentes de Oakland, cuyas direcciones ya no estarían al día:

update authors

set state = "PC", city = "Big Bad Bay City"

where state = "CA" and city = "Oakland"

Sería necesaria otra instrucción para cambiar el nombre del estado de los residentes de otras ciudades del norte de California.

Uso de Cláusula from con update

Utilice la cláusula from para transferir datos de una o más tablas a la tabla que esta actualizando.

Por ejemplo, anteriormente en este capítulo se dió un ejemplo que insertaba nuevas filas para autores sin títulos en la tabla titleauthor , rellenando la columna au_id y colocando valores ficticios o nulos en las demás. Si uno de estos autores, Dirk Stringer, escribe un libro, The Psychology of Computer Cooking , se asigna un número de identificación de título a su libro en la tabla titles . Se puede modificar su fila en la tabla titleauthor añadiendo un número de identificación de título para él:

update titleauthor

set title_id = titles.title_id

from titleauthor, titles, authors

where titles.title =

"The Psychology of Computer Cooking"

and authors.au_id = titleauthor.au_id

and au_lname = "Stringer"

Observe que una instrucción update sin la combinación au_id cambia todos los title_ids de la tabla titleauthor y les asigna el mismo número de identificación que a The Psychology of Computer Cooking . Si dos tablas son idénticas en estructura, pero una tiene campos NULL y algunos valores nulos y la otra tiene campos NOT NULL, es imposible insertar los datos de la tabla NULL en la tabla NOT NULL con una instrucción select . En otras palabras, un campo que no permite valores nulos no puede actualizarse seleccionando elementos de un campo que sí los permite, si alguno de los datos es nulo.

Modificación de datos text e image

El comando writetext se usa para modificar valores text o image cuando no se desea almacenar los largos valores de texto en el diario de transacciones de la base de datos. Los comandos update , que también pueden emplearse para columnas text o image , siempre se registran. En el modo predeterminado, los comandos writetext no se registran.

Note: Para emplear writetext en su estado predeterminado y no registrado, el administrador del sistema debe usar sp_dboption para activar select into/bulkcopy . Esto permite la inserción de datos no registrados. Después de usar writetext , es necesario ejecutar dump database . Un volcado de transacciones realizado tras la introducción de cambios no registrados en la base de datos no puede utilizarse en una operación de load transaction .

El comando writetext escribe sobre todos los datos de la columna a la que afecta. Para que writetext funcione correctamente, la columna debe contener un puntero de texto válido. Existen dos formas de crear un puntero de texto:

Insertar datos reales en la columna text o image mediante insert .

Actualizar la columna con datos o un valor nulo mediante update .

Page 138: 80575032 Libro de SQL y Tl SQL Excelente

Page 138 of 280

Puesto que una columna text "inicializada" usa 2K de espacio de almacenamiento, aunque sólo contenga dos palabras, SQL Server ahorra espacio al no inicializar las columnas text cuando se colocan valores nulos explícitos o implícitos en ellas con insert . Este comando no inicializa una columna text :

insert blurbs

values ("172-32-1176", NULL)

Después de una instrucción insert como la anterior, se puede usar esta instrucción update para inicializar la columna text :

update blurbs

set copy=NULL

where au_id="172-32-1176"

Una vez inicializado el puntero, se puede emplear writetext . El siguiente ejemplo de writetext añade un texto a una fila existente de la tabla blurbs :

declare @val varbinary(16)

select @val = textptr(copy) from blurbs

where au_id="172-32-1176"

writetext blurbs.copy @val

"This book is a must for true data junkies."

Este ejemplo coloca el puntero de texto en la variable local @ val. Después, writetext coloca la cadena de texto nueva en la fila a la que apunta @ val .

Eliminación de datos

Al igual que insert y update , delete puede utilizarse para operaciones tanto de una sola fila como de múltiples filas, pero es más adecuada para lo segundo. Como ocurre con las demás instrucciones de modificación de datos, es posible eliminar filas basadas en los datos de otras tablas.

Por ejemplo, si decide eliminar una fila de publishers (la fila añadida para Jardin, Inc.), escriba:

delete publishers

where pub_name = "Jardin, Inc."

Sintaxis de delete

Esta es una versión simplificada de la sintaxis de delete :

delete table_name

where column_name = expression

Esta es la instrucción con la sintaxis completa, que muestra cómo se pueden eliminar filas según expresiones especificadas o según los datos de otras tablas:

delete [from] [[ database .] owner .]{ table_name |

view_name }

[from [[ database .] owner .]{ table_name | view_name }

[, [[ database .] owner .]{ table_name |

view_name }]...]

[where search_conditions ]

La cláusula opcional from situada justo detrás de la palabra clave delete se incluye por motivos de compatibilidad con otras versiones de SQL. La cláusula from de la segunda línea es una mejora de SQL Server que permite realizar eliminaciones basándose en datos de otras tablas.

Uso de la cláusula where con delete

La cláusula where especifica qué filas deben eliminarse. Cuando no se indica ninguna cláusula where en la instrucción delete , se quitan todas las filas de la tabla.

Page 139: 80575032 Libro de SQL y Tl SQL Excelente

Page 139 of 280

Uso de la cláusula from con delete

La cláusula from en la segunda posición de una instrucción delete es una función especial de Transact-SQL que permite seleccionar datos de una o varias tablas y eliminar los datos correspondientes de la tabla indicada en primer lugar. Las filas seleccionadas en la cláusula from especifican las condiciones de la operación delete .

Suponga que un complejo acuerdo corporativo tiene como resultado la adquisición de todos los autores y sus libros de Big Bad Bay City, anteriormente Oakland, por otro editor. Es necesario eliminar todos esos libros de la tabla titles inmediatamente y, sin embargo, no se conocen los títulos ni los números de identificación correspondientes a esos autores. La única información que se dispone son sus nombres y direcciones.

Se pueden borrar las filas de titles buscando los números de identificación de los autores cuyas filas tienen Big Bad Bay City como ciudad en la tabla authors y usando estos números para buscar los números de identificación de los libros en la tabla titleauthor . En otras palabras, se requiere una combinación de tres componentes para buscar las filas que se desea eliminar de la tabla titles .

Las tres tablas están incluidas en la cláusula from de la instrucción delete . Sin embargo, sólo se eliminan las filas de la tabla titles que cumplen con las condiciones de la cláusula where . Para eliminar las filas relevantes de otras tablas que no sean titles , habría que realizar operaciones independientes.

Esta es la instrucción necesaria:

delete titles

from authors, titles, titleauthor

where titles.title_id = titleauthor.title_id

and authors.au_id = titleauthor.au_id

and city = "Big Bad Bay City"

El disparador deltitle de la base de datos pubs2 evita que la eliminación se lleve a cabo realmente, puesto que no permite borrar los títulos con ventas registradas en la tabla sales

Eliminación de todas las filas de una tabla

Utilice truncate table como método rápido para eliminar todas las filas de una tabla. Casi siempre es más rápido que una instrucción delete sin condiciones, porque delete registra todos los cambios, mientras que truncate table sólo registra la desasignación de páginas de datos completas. truncate table libera inmediatamente todo el espacio ocupado por los datos e índices de la tabla. El espacio liberado lo puede usar entonces cualquier objeto. Las páginas de distribución de todos los índices también quedan desasignadas. No olvide ejecutar update statistics tras añadir nuevas filas a la tabla.

Al igual que con delete , una tabla vaciada con el comando truncate table permanece en la base de datos, junto con sus índices y otros objetos asociados, a no ser que se introduzca un comando drop table .

Sintaxis de truncate table

La sintaxis de truncate table es:

truncate table [[ database .] owner .] table_name

Por ejemplo, para eliminar todos los datos de la tabla sales , escriba:

truncate table sales

El permiso para usar el comando truncate table , al igual que drop table , corresponde predeterminadamente al propietario de la tabla, y no es transferible.

Un comando truncate table no se ve afectado por un disparador delete . Consulte el Capítulo 15, "Disparadores: imposición de la integridad de referencia", para obtener detalles sobre los disparadores.

Chapter 9

Page 140: 80575032 Libro de SQL y Tl SQL Excelente

Page 140 of 280

Vistas: limitación del acceso a datos

Las vistas se pueden utilizar para centrar, simplificar y personalizar la percepción de cada usuario de la base de datos. Las vistas también proporcionan un mecanismo de seguridad al permitir que los usuarios sólo tengan acceso a los datos que necesitan. En este capítulo se describen éstas y otras ventajas.

En este capítulo se trata lo siguiente:

Una introducción general al uso de vistas

Creación de vistas

Recuperación de datos mediante vistas

Actualización de datos mediante vistas

Generación de información sobre vistas

Definición de vista

Creación de vistas

Recuperación de datos mediante vistas

Modificación de datos mediante vistas

Omisión de vistas

Uso de vistas como mecanismos de seguridad

Obtención de información sobre vistas

Definición de vista

Una vista es una forma alternativa de ver los datos de una o más tablas. Se puede pensar en una vista como un marco a través del cual pueden verse los datos en los que está interesado. Esta es la razón por la que se habla de ver los datos o cambiar los datos "mediante" una vista.

Una vista se deriva de una o más tablas reales cuyos datos están almacenados físicamente en la base de datos. Las tablas que originan la vista se denominan tablas base o tablas subyacentes. Una vista también se puede derivar de otra vista.

La definición de una vista, en términos de las tablas base de las que se deriva, se almacena en la base de datos. No se asocia ninguna copia de datos distinta a esta definición almacenada. Los datos que se ven se almacenan en las tablas subyacentes.

Una vista tiene exactamente el mismo aspecto que cualquier otra tabla de base de datos. Puede mostrarse y usarse prácticamente de la misma manera que cualquier otra tabla. Transact-SQL fue modificado para que no haya ninguna restricción en las consultas mediante vistas, y menos restricciones de las normales en la modificación de las vistas. Las excepciones se explican posteriormente en este capítulo.

Cuando se modifican los datos que se ven mediante una vista, en realidad se están cambiando los datos de las tablas subyacentes. A su vez, los cambios en los datos de las tablas subyacentes se reflejan automáticamente en las vistas que se derivan de ellas.

Ventajas de las vistas

Los ejemplos de este capítulo demuestran que las vistas pueden utilizarse para centrar, simplificar y personalizar la percepción que cada usuario tiene de la base de datos. Las vistas también proporcionan una medida de seguridad de fácil manejo. Además, pueden ser útiles cuando los cambios se realizan en la estructura de la base de datos y los usuarios prefieren trabajar con la base de datos en la forma en la que acostumbran.

Enfoque

Las vistas permiten a los usuarios centrarse en los datos concretos que les interesa y en las tareas específicas de las que son responsables. Los datos que no son de interés para un usuario concreto ni para una tarea específica pueden dejarse fuera de la vista.

Simplificación de la manipulación de datos

Page 141: 80575032 Libro de SQL y Tl SQL Excelente

Page 141 of 280

Las vistas no sólo simplifican la percepción que los usuarios tienen de los datos, sino también su forma de manipularlos. Las combinaciones, proyecciones y selecciones usadas con frecuencia pueden definirse como vistas para evitar que los usuarios tengan que especificar todas las condiciones y calificaciones cada vez que realicen una operación adicional con dichos datos.

Personalización

Gracias a las vistas, distintos usuarios pueden ver los mismos datos de formas diferentes, incluso si utilizan los mismos datos al mismo tiempo. Esta ventaja es especialmente importante cuando usuarios con diferentes intereses y niveles de especialización comparten la misma base de datos.

Seguridad

Mediante una vista, los usuarios pueden consultar y modificar sólo los datos que pueden ver. El resto de la base de datos no es visible ni accesible.

Con los comandos grant y revoke , el acceso de cada usuario a la base de datos puede limitarse a objetos de base de datos especificados, incluidas las vistas. Si la vista y todas las tablas y vistas de las que deriva son propiedad del mismo usuario, éste podrá conceder permiso a otros usuarios para utilizar la vista y, al mismo tiempo, denegar el permiso para usar sus tablas subyacentes y vistas. Este es un mecanismo de seguridad sencillo pero eficaz. Consulte la Guía de Administración de Seguridad para obtener información detallada sobre los comandos grant y revoke .

Mediante la definición de vistas diferentes y la concesión selectiva de permisos para las mismas, es posible limitar un usuario o cualquier combinación de usuarios a distintos subconjuntos de datos. A continuación se ilustra el uso de las vistas con fines de seguridad:

Puede limitarse el acceso a un subconjunto de filas de una tabla base, es decir, un subconjunto dependiente del valor. Por ejemplo, se puede definir una vista que contenga sólo las filas de libros de negocios y psicología, a fin de mantener la información sobre otros tipos de libros oculta a ciertos usuarios.

Puede limitarse el acceso a un subconjunto de columnas de una tabla base, es decir, un subconjunto independiente del valor. Por ejemplo, se puede definir una vista que contenga todas las filas de la tabla titles , pero que omita las columnas royalty y advance , ya que esta información es confidencial.

Puede limitarse el acceso a un subconjunto de fila-y-columna de una tabla base.

Puede limitarse el acceso a las filas que califican una combinación de más de una tabla base. Por ejemplo, se puede definir una vista que combine las tablas titles , authors y titleauthor a fin de ver los nombres de los autores y los libros que han escrito. Esta vista ocultaría los datos personales sobre los autores y la información financiera sobre los libros.

Puede limitarse el acceso a un resumen estadístico de datos de la tabla base. Por ejemplo, mediante la vista category_price , el usuario sólo puede tener acceso al precio promedio de cada tipo de libro.

Puede limitarse el acceso a un subconjunto de otra vista o una combinación de vistas y tablas base. Por ejemplo, mediante la vista hiprice_computer , el usuario puede tener acceso al título y el precio de los libros sobre informática que cumplan las calificaciones de la definición de vista de hiprice .

A fin de crear una vista, el usuario debe recibir el permiso create view del propietario de la base de datos y tener los permisos apropiados sobre las tablas o vistas a las que se haga referencia en la definición de vista.

Si una vista hace referencia a objetos de base de datos diferentes, los usuarios de la vista deben ser usuarios válidos o invitados de cada una de las bases de datos.

Como propietario de un objeto a partir del cual otros usuarios han creado vistas, tenga en cuenta quién puede ver qué datos mediante qué vistas. Considere esta situación: el propietario de la base de datos ha concedido el permiso create view a " harold " y un usuario llamado " maude " ha concedido a " harold " el permiso para usar select desde una tabla propiedad de " maude " . Dados estos permisos, " harold " puede crear una vista que seleccione todas las columnas y filas de la tabla de " maude ". Si "maude" después revoca el permiso de " harold " para usar select desde su tabla, " harold " todavía podrá ver los datos de " maude " a través de la vista que él ha creado.

Independencia lógica de datos

Las vistas ayudan a proteger a los usuarios de los cambios realizados en la estructura de las tablas reales si tales cambios son necesarios.

Por ejemplo, supongamos que la base de datos se reestructura usando select into para dividir la tabla titles en estas dos nuevas tablas base y omitiendo titles :

Page 142: 80575032 Libro de SQL y Tl SQL Excelente

Page 142 of 280

titletext (title_id, title, type, notes)

titlenumbers (title_id, pub_id, price, advance, royalty, total_sales, pub_date)

Observe que la antigua tabla titles puede "regenerarse" combinando las columnas title_id de las dos tablas nuevas. Para proteger la estructura cambiada de la base de datos de los usuarios, puede crear una vista que sea la combinación de las dos tablas nuevas. Incluso le puede asignar el nombre titles .

Cualquier consulta o procedimiento almacenado que antes hacía referencia a la tabla base titles ahora hará referencia a la vista titles . En lo que respecta a los usuarios, las operaciones select siguen funcionando exactamente igual que antes. Los usuarios que sólo realizan la recuperación a partir de la vista nueva ni siquiera necesitan saber que se ha producido una reestructuración.

Desafortunadamente, las vistas sólo proporcionan independencia lógica parcial. Algunas instrucciones de modificación de datos no se permiten en la nueva titles debido a determinadas restricciones.

Ejemplos de vistas

El primer ejemplo es una vista derivada de la tabla titles . Supongamos que sólo está interesado en los libros con un precio superior a $15 y para los que se ha pagado un anticipo de más de $5000. Esta sencilla instrucción select hallaría las filas que cumplen las condiciones:

select *

from titles

where price > $15

and advance > $5000

Ahora supongamos que tiene que realizar muchas operaciones de recuperación y actualización en este conjunto de datos. Lógicamente, podría combinar las condiciones mostradas en la consulta anterior con cualquier comando que ejecute. Sin embargo, para mayor comodidad, puede crear una vista en la que sólo estén visibles los registros de interés:

create view hiprice

as select *

from titles

where price > $15

and advance > $5000

Cuando recibe este comando, SQL Server no ejecuta la instrucción select que sigue a la palabra clave as . En su lugar, almacena la instrucción select , que es de hecho la definición de la vista hiprice , en la tabla del sistema syscomments . También se realizan entradas en sysobjects y syscolumns para cada columna incluida en la vista.

Ahora, cuando se visualiza hiprice o se trabaja con ella, SQL Server combina la instrucción con la definición almacenada de hiprice . Por ejemplo, puede cambiar todos los precios de hiprice del mismo modo que cambiaría cualquier otra tabla:

update hiprice

set price = price * 2

SQL Server halla la definición de vista en las tablas del sistema y convierte este comando de actualización en la instrucción:

update titles

set price = price * 2

where price > $15

and advance > $5000

En otras palabras, SQL Server sabe, a partir de la definición de la vista, que los datos que hay que actualizar están en titles . También sabe que sólo debe aumentar los precios de las filas que cumplen las condiciones de las columnas price y advance , proporcionadas en la definición de vista, y las de la instrucción de actualización.

Al emitir la primera instrucción de actualización, es decir, la de hiprice , es posible ver su efecto en la vista o en la tabla titles . A la inversa, si hubiera creado la vista y luego hubiera ejecutado la segunda instrucción de actualización, que opera directamente en la tabla base, los precios cambiados también se hubieran visualizado mediante la vista.

La actualización de una tabla subyacente de una vista de modo que las diferentes filas califiquen a la vista afectará a la vista. Por ejemplo, suponga que el precio del libro You Can Combat Computer Stress aumenta a $25,95. Dado que ahora este libro cumple las condiciones de calificación de la instrucción de definición de la vista, se considera parte de la vista.

Page 143: 80575032 Libro de SQL y Tl SQL Excelente

Page 143 of 280

Sin embargo, si altera la estructura de la tabla subyacente de una vista mediante la adición de columnas, las columnas nuevas no aparecerán en una vista definida con una cláusula select * a menos que la vista se omita y vuelva a definirse. Esto se debe a que la abreviatura mediante asterisco se interpreta y amplía cuando la vista se crea por primera vez.

Creación de vistas

Los nombres de vistas deben ser únicos para cada usuario entre las tablas y vistas ya existentes. Si definió set quoted_identifier on , puede utilizar un identificador delimitado para la vista. En caso contrario, el nombre de la vista debe ajustarse a las reglas para identificadores proporcionadas en el Chapter 1.

Es posible crear vistas en otras vistas y procedimientos que hagan referencia a vistas. Es posible definir claves primarias, externas y comunes en las vistas. No es posible asociar reglas, valores predeterminados ni disparadores a las vistas, ni tampoco crear índices en ellas. No es posible crear vistas temporales, ni tampoco generarse vistas en tablas temporales.

Sintaxis de create view

A continuación se muestra la sintaxis completa para la creación de una vista:

create view [[ database .] owner .] view_name

[( column_name [, column_name ]...)]

as select [distinct] select_statement

[with check option]

Como se mostraba en el ejemplo de la sección anterior, no es necesario especificar ningún nombre de columna en la cláusula create de una instrucción de definición de vista. SQL Server da a las columnas de la vista los mismos nombres y mismos tipos de datos que las columnas a las que se hace referencia en la lista de selección de la instrucción select . La lista de selección puede ser " * ", como en el ejemplo, o una lista total o parcial de los nombres de columna de las tablas base.

Se pueden crear vistas que no contengan filas duplicadas. Utilice la palabra clave distinct de la instrucción select para garantizar que cada fila de la vista sea única.

Las vistas distinct no pueden actualizarse.

Siempre es válido especificar nombres de columna. Sin embargo, si se cumplen alguna de las siguientes condiciones, los nombres de columna deben especificarse en la cláusula create para todas las columnas de la vista:

Si cualquiera de las columnas de la vista se deriva de una expresión aritmética, un agregado, una función incorporada o una constante.

En caso contrario, dos o más columnas de la vista tendrían el mismo nombre. Esto suele ocurrir porque la definición de la vista incluye una combinación, y las columnas objeto de la combinación tienen el mismo nombre.

Si quiere asignar a una columna de la vista un nombre diferente del de la columna de la que se deriva. También puede cambiar el nombre de las columnas en la instrucción select . Se cambie o no el nombre de una columna de vista, ésta hereda el tipo de datos de la columna de la que se deriva.

A continuación se muestra una instrucción de definición de vista que cambia el nombre de una columna de la vista de su nombre en la tabla subyacente:

create view pub_view (Publisher, city, state)

as select pub_name, city, state

from publishers

A continuación se muestra un método alternativo de creación de la misma vista, pero cambiando el nombre de las columnas en la instrucción select :

create view pub_view2

as select Publisher = pub_name, city, state

from publishers

Los ejemplos de instrucciones de definición de vista proporcionados en una sección posterior muestran el resto de las reglas para la inclusión de nombres de columnas en la cláusula create .

En la siguiente sección se explica la instrucción select , el uso de la palabra clave distinct y la cláusula with check option de las definiciones de vista. El comando drop view se explica después.

Page 144: 80575032 Libro de SQL y Tl SQL Excelente

Page 144 of 280

Uso de la instrucción select con create view

La instrucción select de la instrucción create view define la vista. Es necesario tener el permiso select para seleccionar cualquier objeto referenciado en la instrucción select de una vista que se esté creando.

Una vista no tiene que ser necesariamente un simple subconjunto de filas y columnas de una tabla concreta, como en el ejemplo. Es posible crear una vista a partir de más de una tabla y otras vistas, con una instrucción select de cualquier grado de complejidad.

Existen ciertas restricciones sobre la instrucción select de una definición de vista:

No se pueden incluir cláusulas order by ni compute .

No se puede incluir la palabra clave into .

No se puede hacer referencia a una tabla temporal.

Definición de vista con proyección

Para crear una vista con todas las filas de la tabla titles , pero sólo con un subconjunto de sus columnas, escriba la instrucción:

create view titles_view

as select title, type, price, pubdate

from titles

Observe que no se incluye ningún nombre de columna en la cláusula create view . La vista titles_view heredará los nombres de columna que aparecen en la lista de selección.

Definición de vista con una columna calculada

A continuación se muestra una instrucción de definición de vista que crea una vista con una columna calculada generada a partir de las columnas price , royalty y total_sales :

create view accounts (title, advance, amt_due)

as select titles.title_id, advance, (price * royalty /100 ) * total_sales

from titles, roysched

where price > $15

and advance > $5000

and titles.title_id = roysched.title_id

and total_sales between lorange and hirange

En este ejemplo, es necesario incluir una lista de columnas en la cláusula create , ya que no hay ningún nombre que pueda heredar la columna calculada multiplicando price , royalty y total_sales . A la columna calculada se le da el nombre amt_due . Esta columna debe aparecer en la misma posición en la cláusula create que la de la expresión a partir de la cual se calcula en la cláusula select .

Definición de vista con una función agregada o incorporada

Una definición de vista que incluya una función agregada o incorporada debe incluir nombres de columna en la cláusula create . Por ejemplo:

create view categories (category, average_price)

as select type, avg(price)

from titles

group by type

Si crea un vista por razones de seguridad, debe tener cuidado cuando use las funciones agregadas y la cláusula group by . La extensión Transact-SQL que no limita las columnas que pueden incluirse en la instrucción select con group by también puede hacer que la vista devuelva más información de la necesaria. Por ejemplo:

create view categories (category, average_price)

as select type, avg(price)

from titles

where type = "business"

Page 145: 80575032 Libro de SQL y Tl SQL Excelente

Page 145 of 280

En el caso anterior, posiblemente se esperaba que la vista limitase sus resultados a las categorías de "negocios", pero los resultados tienen información sobre otras categorías. Para obtener más información sobre group by y esta extensión Transact-SQL para group by , consulte el Chapter 3.

Definición de vista con una combinación

Es posible crear una vista derivada de más de una tabla base. A continuación se muestra un ejemplo de una vista derivada de las tablas authors y publishers . La vista contiene los nombres y ciudades de los autores que viven en la misma ciudad que un editor, junto con el nombre y la ciudad de cada editor.

create view cities (authorname, acity, publishername, pcity) as select au_lname, authors.city, pub_name, publishers.city from authors, publishers where authors.city = publishers.city

Vistas derivadas de otras vistas

Se puede definir una vista en relación con otra vista, como en el siguiente ejemplo:

create view hiprice_computer

as select title, price

from hiprice

where type = 'popular_comp'

Vistas distinct

Es posible asegurarse de que las filas que contiene una vista son únicas, como se muestra en este ejemplo:

create view author_codes

as select distinct au_id

from titleauthor

Una fila es un duplicado de otra fila si todos los valores de sus columnas coinciden de forma exacta con los valores de las mismas columnas contenidos en otra fila. Dos valores nulos se consideran idénticos.

SQL Server aplica el requisito distinct a la definición de vista cuando accede a la vista por primera vez y antes de realizar cualquier proyección o selección. Las vistas tienen el mismo aspecto y comportamiento que cualquier tabla de base de datos. Si selecciona una proyección de la vista distinct (es decir, si selecciona algunas de las columnas de la vista, pero todas sus filas), puede obtener resultados que parezcan duplicados. Sin embargo, cada fila de la vista en sí continúa siendo única. Por ejemplo, supongamos que usted crea una vista distinct , myview , con tres columnas, a, b y c , que contiene estos valores:

Tabla 9-1: Valores de muestra de la vista distinct myview

a b c

1 1 2

1 2 3

1 1 0

Cuando introduce esta consulta:

select a, b from myview

el resultado tiene el siguiente aspecto:

a b

--- ---

1 1

1 2

1 1

La primera y tercera fila parece que están duplicadas. Sin embargo, las filas de la vista subyacente siguen siendo únicas.

Page 146: 80575032 Libro de SQL y Tl SQL Excelente

Page 146 of 280

Vistas que incluyen columnas IDENTITY

Se puede definir una vista que incluya una columna IDENTITY, como se muestra en este ejemplo:

create view sales_view

as select syb_identity, stor_id

from sales_daily

Se puede seleccionar la columna IDENTITY de la vista utilizando la palabra clave syb_identity , a menos que la vista:

Seleccione la columna IDENTITY más de una vez, o

Incluya columnas de más de una tabla, o

Calcule una columna nueva a partir de la columna IDENTITY, o

Incluya una función agregada.

Si una o más de estas condiciones es verdadera, SQL Server no reconoce la columna como una columna IDENTITY con respecto a la vista. Al ejecutar el procedimiento del sistema sp_help en la vista, la columna muestra un valor IDENTITY de 0.

Uso de la palabra clave with check option con create view

Normalmente, SQL Server no verifica las instrucciones insert y update en vistas para determinar si las filas afectadas están dentro del alcance de la vista. Una instrucción puede insertar una fila en la tabla base subyacente pero no en la vista, ni cambiar una fila existente para que deje de cumplir los criterios de selección de la vista.

Cuando se crea una vista con with check option, cada operación insert y update realizada mediante la vista se valida según los criterios de selección de la vista. Todas las filas insertadas o actualizadas mediante la vista deben permanecer visibles por medio de ésta, o la instrucción no se ejecuta correctamente.

A continuación se muestra un ejemplo de una vista, stores_cal , creada con with check option . Esta vista incluye información sobre las tiendas ubicadas en California, pero excluye la información sobre las tiendas ubicadas en cualquier otro estado. La vista se crea seleccionando todas las filas de la tabla stores cuya columna state tenga el valor "CA":

create view stores_cal

as select * from stores

where state = "CA"

with check option

Cuando se intenta insertar una fila mediante stores_cal , SQL Server verifica si la nueva fila se encuentra dentro del alcance de la vista. La siguiente instrucción insert no se ejecuta correctamente porque la fila nueva tendría un valor state de "NY", en lugar de "CA":

insert stores_cal

values ("7100", "Castle Books", "351 West 24 St.", "New York", "NY", "USA", "10011", "Net

30")

Cuando se intenta actualizar una fila mediante stores_cal , SQL Server verifica si la actualización no hará que la fila desaparezca de la vista. La siguiente instrucción update no se ejecuta correctamente porque cambiaría el valor de state de "CA" a "MA". Después de la actualización, la fila dejaría de estar visible mediante la vista.

update stores_cal

set state = "MA"

where stor_id = "7066"

Vistas derivadas de otras vistas

Si se crea una vista con with check option , todas las vistas derivadas de la vista "base" deben satisfacer su opción de verificación. Cada fila insertada mediante la vista derivada debe estar visible a través de la vista base. Cada una de las filas actualizadas mediante la vista derivada deben permanecer visibles a través de la vista base.

Considere la vista stores_cal30 , que se deriva de stores_cal . La vista nueva incluye información sobre tiendas de California con condiciones de pago "Net 30":

Page 147: 80575032 Libro de SQL y Tl SQL Excelente

Page 147 of 280

create view stores_cal30

as select * from stores_cal

where payterms = "Net 30"

Dado que stores_cal se creó con with check option , todas las filas insertadas o actualizadas mediante stores_cal30 deben estar visibles a través de stores_cal . Se rechazará cualquier fila con un valor state distinto de "CA".

Observe que stores_cal30 no tiene ninguna cláusula with check option propia. Esto significa que es posible insertar o actualizar una fila con un valor payterms distinto de "Net 30" mediante stores_cal30 . La siguiente instrucción update se ejecutaría correctamente, aunque la fila dejaría de estar visible mediante stores_cal30 :

update stores_cal30

set payterms = "Net 60"

where stor_id = "7067"

Limitaciones en vistas definidas con combinaciones externas

Las vistas definidas con combinaciones externas tienen algunas limitaciones que pueden generar resultados imprevistos cuando se recuperan datos de las mismas. Se debe tener cuidado al utilizar dichas vistas.

Si define una vista con una combinación externa y luego consulta la vista con una calificación en una columna de la tabla interna de la combinación externa, los resultados pueden ser distintos de los previstos. La calificación de la consulta no restringe el número de filas devueltas, pero afecta a las filas que contienen el valor NULL. Para las filas que no cumplen la calificación, aparece un valor NULL en las columnas de la tabla interna de dichas filas. Esto es resultado del hecho de que en Transact-SQL la representación interna de una consulta en una vista es una combinación de la definición de la vista y la calificación en la vista.

Por ejemplo, supongamos que existen las siguientes tablas:

Tabla A:

a

1

2

3

Tabla B:

b c

1 10

2 11

6 12

Luego cree una vista a partir de estas dos tablas. La definición de vista contiene una combinación externa:

create view A_B as

select a,b,c from A,B

where A.a*=B.b

Después ejecute la siguiente consulta, que genera los siguientes resultados:

select a,c from A_B where c = 10

a c ----- -----

1 10 Combina y califica en c

2 NULL Combina, pero no cumple las calificaciones

Page 148: 80575032 Libro de SQL y Tl SQL Excelente

Page 148 of 280

3 NULL

(3 rows affected)

No combina

La calificación (c = 10) no afecta al número de filas devueltas. Sin embargo, NULL aparece en la columna de la tabla interna para cada fila que no cumple la calificación o no se combina con filas de la tabla externa.

Recuperación de datos mediante vistas

Al recuperar datos mediante una vista, SQL Server comprueba si todos los objetos de base de datos referenciados en la instrucción existen y si son válidos en el contexto de la instrucción. Si las verificaciones son satisfactorias, SQL Server combina la instrucción con la definición almacenada de la vista y la convierte en una consulta de las tablas subyacentes de la vista, como se ha explicado en una sección anterior. Este proceso se llama resolución de vista .

Considere la instrucción de definición de vista descrita anteriormente en este capítulo y una consulta contra ella:

create view hiprice

as select *

from titles

where price > $15

and advance > $5000

select title, type

from hiprice

where type = 'popular_comp'

De forma interna, SQL Server combina la consulta de hiprice con su definición, convirtiendo la consulta en:

select title, type

from titles

where price > $15

and advance > $5000

and type = 'popular_comp'

En general, es posible consultar cualquier vista de cualquier modo como si fuera una tabla real. Se pueden utilizar combinaciones, cláusulas group by , subconsultas y otras técnicas de consulta en las vistas, en cualquier combinación. Sin embargo, tenga presente que si la vista se define con una combinación externa o una función agregada, al consultar la vista, los resultados pueden ser imprevistos. Consulte la sección anterior sobre limitaciones en definiciones de vistas.

Note: Se puede utilizar select en columnas text e image , pero no se permite el uso de los comandos readtext y writetext . Además, no es posible seleccionar la columna sensitivity de una vista.

Resolución de vistas

Cuando se define una vista, SQL Server comprueba si todas las tablas o vistas especificadas en la cláusula from existen, y muestra un mensaje de error si hay algún problema. Se realizan verificaciones similares al efectuar una consulta mediante la vista.

Entre el momento en que se define una vista y el momento en que se usa en una instrucción, las cosas pueden cambiar. Por ejemplo, una o más tablas o vistas indicadas en la cláusula from de la definición de vista pueden haberse omitido. O, también, una o más de las columnas especificadas en la cláusula select de la definición de vista pueden haberse cambiado de nombre.

Para resolver una vista totalmente, SQL Server comprueba que:

Todas las tablas, vistas y columnas de las que se deriva la vista todavía existen.

El tipo de datos de cada columna sobre la que depende una columna de vista no se ha cambiado a un tipo incompatible.

Las instrucciones update , insert o delete no violan las restricciones sobre modificación de vistas. Estas se explican en una sección posterior de este capítulo.

Si falla alguna de estas verificaciones, SQL Server muestra un mensaje de error.

Redefinición de vistas

Page 149: 80575032 Libro de SQL y Tl SQL Excelente

Page 149 of 280

A diferencia de muchos otros sistemas de administración de bases de datos, SQL Server permite redefinir una vista sin necesidad de redefinir otras vistas que dependen de ella, a menos que la redefinición imposibilite que SQL Server convierta la vista dependiente.

Como ejemplo, se muestran la tabla authors y tres vistas posibles. Cada vista satisfactoria se define utilizando la vista que la precede: view2 se crea a partir de view1 y view3 se crea a partir de view2 . De esta forma, view2 depende de view1 y view3 depende de las dos vistas precedentes.

Cada nombre de vista va seguido de la instrucción select usada para crear la vista.

view1 :

create view view1 as

select au_lname, phone from authors

where postalcode like "94%"

v iew2 :

create view view2 as

select au_lname, phone from view1

where au_lname like "[M-Z]%"

view3 :

create view view3 as

select au_lname, phone from view2

where au_lname = "MacFeather"

La tabla authors en la que se basan estas vistas se compone de estas columnas: au_id , au_lname , au_fname , phone , address , city , state y postalcode.

Se puede omitir view2 y sustituirse por otra vista, llamada también view2 , que contenga criterios de selección ligeramente diferentes, como au_lname , phone from view_1 where au_lname like "[M-P]". View3 , que depende de view2 , todavía es válida y no es necesario redefinirla. Cuando se utiliza una consulta que haga referencia a view2 o view3 , la resolución de la vista tiene lugar del modo habitual.

Si se redefine view2 de forma que view3 no pueda derivarse de ella, view3 pasará a ser inválida. Por ejemplo, si otra versión nueva de view2 contiene una sola columna, au_lname , en lugar de las dos columnas que view3 espera, view3 ya no puede usarse dado que no puede derivar la columna phone del objeto del que depende.

Sin embargo, view3 todavía existe y puede volver a utilizarse omitiendo la vista view2 inválida y volviendo a crear view2 con las columnas au_lname y phone .

En resumen, se puede cambiar la definición de una vista intermedia sin afectar a las vistas dependientes siempre que la lista select de las vistas dependientes siga siendo válida. Si se viola esta regla, una consulta que haga referencia a la vista inválida generará un mensaje de error.

Cambio de nombre de las vistas

Se puede cambiar el nombre de una vista con el procedimiento del sistema sp_rename , cuya sintaxis es la siguiente:

sp_rename ojbname , newname

Por ejemplo, para cambiar el nombre titleview a bookview :

sp_rename titles_view, bookview

Lógicamente, el nombre nuevo debe seguir las reglas para identificadores (no se puede utilizar sp_rename para especificar un identificador nuevo y delimitado para una vista). Sólo se puede cambiar el nombre de las vistas que se poseen. El propietario de la base de datos puede cambiar el nombre de la vista de cualquier usuario. La vista debe estar en la base de datos actual.

Alteración u omisión de objetos subyacentes

Page 150: 80575032 Libro de SQL y Tl SQL Excelente

Page 150 of 280

Pueden surgir problemas si se cambia el nombre de un objeto subyacente de una vista. Las vistas que dependen de una tabla o vista cuyo nombre ha cambiado pueden funcionar correctamente durante un tiempo. De hecho, funcionan hasta que SQL Server las recompila. La recompilación tiene lugar por diversas razones y sin notificación al usuario; por ejemplo, si se carga una base de datos o si un usuario omite y vuelve a crear una tabla u omite un índice. Debido a esto, los intentos de consultar o modificar la vista pueden hacer que SQL Server devuelva mensajes de error de forma repentina.

En este punto, es necesario omitir la vista y volver a crearla, de forma que su texto refleje el nombre nuevo del objeto del que depende. Para evitar dichos problemas, la forma más segura es no cambiar el nombre de ninguna tabla o vista referenciada por una vista, o bien modificar las definiciones de sus vistas dependientes al cambiar su nombre.

La situación es similar cuando la vista depende de una tabla o vista que se ha omitido. Cuando alguien intenta utilizar la vista, SQL Server genera un mensaje de error. Sin embargo, si se crea una tabla o vista nueva para sustituir a la que se ha omitido, la vista volverá a ser utilizable.

Si define una vista con una cláusula select * y luego altera la estructura de sus tablas subyacentes mediante la adición de columnas, las columnas nuevas no aparecerán. Esto se debe a que la abreviatura mediante asterisco se interpreta y amplía cuando se crea la vista por primera vez. Para ver las columnas nuevas mediante la vista, omita la vista y vuelva a crearla.

Modificación de datos mediante vistas

Aunque SQL Server no pone ninguna restricción en la recuperación de datos mediante vistas y Transact-SQL pone menos restricciones en la modificación de datos mediante vistas que otras versiones de SQL, existen varias clases de operaciones de modificación de datos no permitidas mediante vistas:

No se permiten las operaciones update , insert o delete que hacen referencia a una columna de la vista que es un cálculo, es decir, una columna calculada o una función incorporada.

No se permiten las operaciones update , insert o delete que hacen referencia a una vista que incluye agregados o agregados de fila, es decir, funciones incorporadas y una cláusula group by o compute .

No se permiten las operaciones insert, delete y update que hacen referencia a una vista distinct .

No se permiten instrucciones insert a menos que todas las columnas NOT NULL de las tablas subyacentes o las vistas se incluyan en la vista mediante la que se están insertando filas nuevas. SQL Server no tiene ningún modo de suministrar valores para las columnas NOT NULL de los objetos subyacentes.

Si una vista tiene una cláusula with check option , todas la filas insertadas o actualizadas mediante la vista (o mediante cualquier vista derivada) deben cumplir los criterios de selección de la vista.

No se permiten instrucciones delete en vistas de múltiples tablas.

No se permiten instrucciones insert en vistas de múltiples tablas creadas con with check option.

Se permiten instrucciones update en vistas de múltiples tablas con with check option . La actualización no se efectúa de forma correcta si alguna de las columnas afectadas aparece en la cláusula where , en una expresión que incluya columnas de más de una tabla.

No se permiten instrucciones insert y update en vistas distinct de múltiples tablas.

Las instrucciones update no pueden especificar un valor para una columna IDENTITY. El propietario de la tabla, el propietario de la base de datos o el administrador del sistema pueden insertar (mediante insert ) un valor explícito en una columna IDENTITY después de definir identity_insert on para la tabla base de la columna.

Si inserta o actualiza una fila mediante una vista de múltiples tablas, todas las columnas afectadas deben pertenecer a la misma tabla base.

writetext no se permite en las columnas text e image de una vista.

Cuando se intenta ejecutar update , insert o delete para una vista, SQL Server comprueba que no se viola ninguna de las restricciones anteriores ni ninguna de las reglas de integridad de datos.

¿Por qué algunas vistas pueden actualizarse y otras no? Si examina los ejemplos de cada uno de los tipos de vistas que no pueden actualizarse, entenderá mejor las restricciones.

Restricciones en la actualización de vistas

Columnas calculadas en la definición de vista

La primera restricción se aplica a las columnas de vistas derivadas de columnas calculadas o funciones incorporadas. Por ejemplo, la columna amt_due de la vista accounts , creada anteriormente, es una columna calculada.

create view accounts (title_id, advance, amt_due)

as select titles.title_id, advance, (price * royalty/100) * total_sales

from titles, roysched

Page 151: 80575032 Libro de SQL y Tl SQL Excelente

Page 151 of 280

where price > $15

and advance > $5000

and titles.title_id = roysched.title_id

and total_sales between lorange and hirange

Las filas visibles mediante accounts son:

select * from accounts

title_id advance amt_due

-------- -------- ---------

PC1035 7,000.00 32,240.16

PC8888 8,000.00 8,190.00

PS1372 7,000.00 809.63

TC3218 7,000.00 785.63

(4 rows affected)

Las operaciones update e insert no se permiten en la columna amt_due porque no hay forma de deducir los valores subyacentes de precio, derechos de autor o ventas anuales hasta la fecha, a partir de los valores que puedan introducirse en la columna amt_due . Las operaciones delete no tienen ningún sentido porque no hay ningún valor subyacente que eliminar.

group by o compute en la definición de vista

La segunda restricción se aplica a todas las columnas de vistas que contengan valores agregados, es decir, vistas cuya definición incluya una cláusula group by o compute . A continuación se muestra una vista definida con group by y las filas que se ven a través de ella:

create view categories (category, average_price)

as select type, avg(price)

from titles

group by type

select * from categories

category average_price

------------- -------------

UNDECIDED NULL

business 13.73

mod_cook 11.49

popular_comp 21.48

psychology 13.50

trad_cook 15.96

(6 rows affected)

No tendría sentido insertar filas (mediante insert ) en la vista categories . ¿A qué grupo de filas subyacentes pertenecería una fila insertada? No es posible realizar actualizaciones en la columna average_price porque no hay forma de saber cómo deberían cambiar los precios subyacentes a partir de los valores introducidos en dicha columna.

En teoría, se podrían permitir eliminaciones y actualizaciones en la columna category , pero SQL Server no las admite.

Valores nulos en objetos subyacentes

La tercera restricción se aplica a instrucciones insert si hubiera alguna columna NOT NULL en las tablas o vistas de las que se deriva la vista.

Por ejemplo, supongamos que no se permiten valores nulos en una columna de una tabla sobre la que se basa una vista. Generalmente, cuando se insertan filas nuevas (con insert ) mediante una vista, todas las columnas de las tablas subyacentes que no están incluidas en la vista reciben valores nulos. Si no se permiten valores nulos en una o más de estas columnas, no se permitirán inserciones mediante la vista.

Considere la vista:

create view titleview

as select title_id, price, total_sales

from titles

where type = 'business'

Page 152: 80575032 Libro de SQL y Tl SQL Excelente

Page 152 of 280

La columna title de la tabla subyacente titles no admite valores nulos, por lo que no es posible realizar ninguna operación insert mediante titleview . Aunque la columna title ni siquiera existe en la vista, su prohibición de valores nulos convierte en ilegal cualquier inserción en la vista.

De forma similar, si la columna title_id tiene un índice único, las actualizaciones o inserciones que duplicarían los valores de la tabla subyacente se rechazan, incluso si la entrada no duplica ningún valor de la vista.

Vistas creadas con with check option

La cuarta restricción determina los tipos de modificaciones que pueden realizarse mediante vistas con opciones de verificación. Si una vista tiene una cláusula with check option , cada fila insertada o actualizada mediante la vista debe estar visible dentro de la vista. Esto se cumple ya inserte o actualice la vista directa o indirectamente mediante otra vista derivada.

Vistas de múltiples tablas

La quinta restricción determina los tipos de modificaciones que pueden realizarse mediante vistas que combinan columnas de múltiples tablas. SQL Server prohibe las instrucciones delete en las vistas de múltiples tablas, pero permite las instrucciones update y insert que no se permitirían en otros sistemas.

Puede insertar o actualizar una vista de múltiples tablas si:

La vista no tiene ninguna cláusula with check option .

Todas las columnas que se insertan o actualizan pertenecen a la misma tabla base.

Por ejemplo, considere la siguiente vista, que incluye columnas de titles y publishers y no tiene ninguna cláusula with check option :

create view multitable_view

as select title, type, titles.pub_id, state

from titles, publishers

where titles.pub_id = publishers.pub_id

Una sola instrucción insert o de actualización puede especificar valores tanto para las columnas de titles como para la columna de publishers . La siguiente instrucción update se ejecuta de forma correcta:

update multitable_view

set type = "user_friendly"

where type = "popular_comp"

Pero esta instrucción fracasa porque afecta a columnas de titles y publishers :

update multitable_view

set type = "cooking_trad",

state = "WA"

where type = "trad_cook"

Vistas que incluyen columnas IDENTITY

La última restricción determina los tipos de modificaciones que pueden realizarse en vistas que incluyen columnas IDENTITY. Por definición, las columnas IDENTITY no son actualizables. Las actualizaciones mediante una vista no pueden especificar un valor de columna IDENTITY.

Las inserciones en columnas IDENTITY están limitadas al propietario de la tabla, el propietario de la base de datos y el administrador del sistema. Para permitir dichas inserciones mediante una vista, defina set identity_insert o n para la tabla base de la columna. No es suficiente con definir set identity_insert o n para la vista mediante la que se está realizando la inserción.

Omisión de vistas

Para eliminar una vista de la base de datos, utilice el comando drop view , cuya sintaxis es la siguiente:

Page 153: 80575032 Libro de SQL y Tl SQL Excelente

Page 153 of 280

drop view [[ database .] owner .] view_name

[, [[ database .] owner .] view_name ]...

Como se ha indicado, puede omitir más de una vista a la vez. Sólo su propietario (o el propietario de la base de datos) puede omitir una vista.

A continuación se muestra el modo de omitir la vista hiprice :

drop view hiprice

Cuando se ejecuta el comando drop view , la información sobre la vista indicada se elimina de las tablas del sistema sysprocedures , sysobjects , syscolumns , syscomments , sysprotects y sysdepends . También se eliminan todos los privilegios para dicha vista.

Si una vista depende de una tabla o de otra vista que se ha omitido, SQL Server genera un mensaje de error si alguien intenta utilizar la vista. Si se crea una tabla o vista nueva para sustituir a la que se ha omitido, con el mismo nombre, la vista se convierte de nuevo en utilizable, siempre que existan las columnas referenciadas en la definición de vista.

Uso de vistas como mecanismos de seguridad

El permiso para acceder al subconjunto de datos de una vista debe concederse o revocarse de forma explícita, independientemente de los permisos vigentes en las tablas subyacentes de la vista. Los datos de una tabla subyacente que no está incluida en la vista se ocultan de los usuarios que tienen autorización para acceder a la vista pero no para acceder a la tabla subyacente.

Por ejemplo, posiblemente no se deseará que determinados usuarios tengan acceso a las columnas de titles relacionadas con dinero y ventas. En tal caso, se puede generar una vista de titles que omita dichas columnas y luego conceder a todos los usuarios el permiso sobre la vista y únicamente al departamento de ventas el permiso sobre la tabla. Por ejemplo:

revoke all on titles to public

grant all on bookview to public

grant all on titles to sales

Para obtener información sobre cómo conceder o revocar permisos (mediante grant y revoke , respectivamente), consulte la Guía del Usuario de las Características de Seguridad .

Obtención de información sobre vistas

Varios procedimientos del sistema proporcionan información sobre las vistas a partir de las tablas del sistema.

Se puede obtener un informe sobre una vista con el procedimiento del sistema sp_help . Por ejemplo:

sp_help hiprice

Name Owner type Created_on

--------- ------ ----- -------------------

hiprice dbo view Feb 12 1987 11:57AM

Data_located_on_segment When_created

------------------------------ --------------------

Column_name Type Length Precision Scale

----------- ------- ------ --------- -----

title_id tid 6 NULL NULL

title varchar 80 NULL NULL

type char 12 NULL NULL

pub_id char 4 NULL NULL

price money 8 NULL NULL

advance money 8 NULL NULL

royalty int 4 NULL NULL

total_sales int 4 NULL NULL

notes varchar 200 NULL NULL

pubdate datetime 8 NULL NULL

Null Default_name Rule_name Identity

------ ------------ --------- --------

0 NULL NULL 0

0 NULL NULL 0

Page 154: 80575032 Libro de SQL y Tl SQL Excelente

Page 154 of 280

0 NULL NULL 0

1 NULL NULL 0

1 NULL NULL 0

1 NULL NULL 0

1 NULL NULL 0

1 NULL NULL 0

1 NULL NULL 0

0 NULL NULL 0

No existe ninguna clave definida para este objeto.

(return status = 0)

Para mostrar el texto de la instrucción create view , ejecute el procedimiento del sistema sp_helptext :

sp_helptext hiprice

----------

1

(1 row affected)

text

--------------------------------------------

create view hiprice

as select *

from titles

where price > $15

and advance > $5000

(1 row affected, return status = 0)

El procedimiento del sistema sp_depends muestra todos los objetos que la vista o tabla referencian en la base de datos actual, así como todos los objetos que hacen referencia a dicha vista o tabla. A continuación se muestra un ejemplo:

sp_depends titles

Cosas incluidas en la base de datos actual que hacen referencia al objeto.

object type

------------- ---------------------------

dbo.hiprice vista

dbo.titleview vista

dbo.reptq1 procedimiento almacenado

dbo.reptq2 procedimiento almacenado

dbo.reptq3 procedimiento almacenado

(return status = 0)

Para obtener información completa sobre los procedimientos del sistema, consulte el Manual de Referencia de SQL Server .

Chapter 10

Uso de funciones incorporadas en consultas

Transact-SQL proporciona distintos tipos de funciones incorporadas que devuelven distintos tipos de información desde la base de datos. Estas funciones son extensiones Transact-SQL para SQL.

Se pueden utilizar funciones incorporadas en la lista select , en la cláusula where y en cualquier parte donde se permita una expresión. También es posible usarlas como parte de un procedimiento almacenado o programa. SQL Server proporciona una gran variedad de funciones incorporadas.

En este capítulo se trata lo siguiente:

Funciones del sistema, la mayoría de las cuales devuelven información de las tablas del sistema

Funciones de cadena, que manipulan valores char , nchar , varchar , nvarchar , binary y varbinary .

Funciones de texto, que manipulan valores text e image

Funciones matemáticas, que realizan operaciones trigonométricas y geométricas, además de otros tipos de manipulaciones de números

Page 155: 80575032 Libro de SQL y Tl SQL Excelente

Page 155 of 280

Funciones de fecha, que manipulan valores datetime y smalldatetime

Funciones de conversión de tipos de datos, que convierten expresiones de un tipo de datos a otro y que asignan formato a las fechas en una variedad de estilos

Funciones del sistema

Funciones de cadena

Funciones de texto

Funciones matemáticas

Funciones de fecha

Funciones de conversión de tipos de datos

Funciones del sistema

Las funciones del sistema devuelven información especial de la base de datos. Muchas de ellas proporcionan un método abreviado de consultar las tablas del sistema.

La sintaxis general de las funciones del sistema es:

select function_name ( argument [ s ])

Las funciones del sistema pueden utilizarse en la lista select , la cláusula where y en cualquier lugar donde se permita una expresión.

Por ejemplo, para buscar el número de identificación de usuario del colaborador que se conecta como " harold ", escriba:

select user_id("harold")

Suponiendo que la ID de usuario de "harold" es 13, el resultado será:

-------------

13

(1 row affected)

Generalmente, el nombre de la función indica el tipo de información que se devuelve.

La función del sistema user_name toma un número de ID como su argumento y devuelve el nombre de usuario:

select user_name(13)

---------

harold

(1 row affected)

Para hallar el nombre del usuario actual, es decir, su nombre, el argumento se omite:

select user_name()

---------

dbo

(1 row affected)

Tenga presente que el administrador del sistema se convierte en propietario de la base de datos que está utilizando al asumir la ID de usuario de servidor 1. Al usuario "invitado" siempre se le asigna la ID de usuario de servidor -1. Dentro de una base de datos, el nombre de usuario ( user_name ) del propietario de la base de datos siempre es "dbo"; su ID de usuario es 1. Dentro de una base de datos, la ID de usuario "invitado" siempre es 2.

Esta lista proporciona el nombre de cada función del sistema, el argumento que usa y el resultado que devuelve:

Tabla 10-1: Funciones del sistema, argumentos y resultados

Page 156: 80575032 Libro de SQL y Tl SQL Excelente

Page 156 of 280

Función Argumento Resultado

col_name ( object_id , column_id [, database_id ])

Devuelve el nombre de la columna.

col_length ( object_name , column_name )

Devuelve la longitud definida de la columna. Use datalength para ver el tamaño de datos real.

curunreservedpgs (dbid, lstart, unreservedpgs )

Devuelve el número de páginas libres de una sección del disco. Si la base de datos está abierta, el valor se toma de la memoria; si la base de datos no está en uso, el valor se toma de la columna u nreservedpgs de sysusages .

data_pgs ( object_id , { doampg | ioampg })

Devuelve el número de páginas usadas por la tabla ( doampg ) o el índice ( ioampg ). El resultado no incluye las páginas utilizadas para las estructuras internas.

datalength ( expression ) Devuelve la longitud de la expresión en bytes. e xpression suele ser un nombre de columna. Si e xpression es una constante de caracteres, debe incluirse entre comillas.

db_id ( [ database_name ] )

Devuelve el número de ID de la base de datos. d atabase_name debe ser una expresión de caracteres; si es una expresión de constantes, es necesario incluirla entre comillas. Si no se proporciona ningún d atabase_name , db_id devuelve el número de ID de la base de datos actual.

db_name ([ database_id ]) Devuelve el nombre de la base de datos. d atabase_id debe ser una expresión numérica. Si no se proporciona ninguna d atabase_id , db_name devuelve el nombre de la base de datos actual.

host_id ( ) Devuelve la ID de proceso principal del proceso cliente (no el proceso SQL Server).

host_name ( ) Devuelve el nombre de computadora principal actual del proceso cliente (no el proceso SQL Server).

index_col ( object_name , index_id , key_ # [, user_id ])

Devuelve el nombre de la columna indexada; devuelve NULL si o bject_name no es un nombre de tabla ni de vista.

isnull ( expression1 , expression2 ) Sustituye el valor indicado en e xpression2 cuando e xpression1 da como resultado NULL. Los tipos de datos de las expresiones deben convertirse de forma implícita, o es necesario usar la función c onvert .

lct_admin ({{ "lastchance" | "logfull" | "unsuspend" } , database_id } | "reserve" , log_pages })

Maneja el umbral de última oportunidad del segmento de diario.

lastchance crea un umbral de última oportunidad en la base de datos especificada.

logfull devuelve 1 si se ha cruzado el umbral de última oportunidad de la base de datos especificada y 0 en caso contrario.

unsuspend activa las tareas suspendidas de la base de datos e inhabilita el umbral de última oportunidad si éste se ha cruzado.

reserve devuelve el número de páginas de diario libres necesarios para volcar de forma correcta un diario de transacciones del tamaño indicado.

object_id ( object_name ) Devuelve la ID del objeto.

object_name ( object_id [, database_id ] ) Devuelve el nombre del objeto.

proc_role ( "sa_role" | "sso_role" | "oper_role" )

Comprueba si el usuario solicitante tiene el rol correcto para ejecutar el procedimiento. Si el rol es correcto, el resultado es 1. En caso contrario, el resultado es 0.

reserved_pgs ( object_id , { doampg | ioampg })

Devuelve el número de páginas asignadas a la tabla o índice. Esta función sí indica las páginas usadas para las estructuras internas.

rowcnt ( doampg ) Devuelve el número de filas de una tabla (valor estimado).

show_role ( ) Devuelve los roles activos actuales del usuario, si hay (sa_role, sso_role u oper_role). Si el usuario carece de roles, el resultado es NULL.

suser_id ([ server_user_name ]) Devuelve el número de ID del usuario de servidor de s yslogins. Si no se proporciona ningún s erver_user_name , el resultado es la ID de servidor del usuario actual.

Page 157: 80575032 Libro de SQL y Tl SQL Excelente

Page 157 of 280

suser_name ([ server_user_id ]) Devuelve el nombre del usuario de servidor. Las ID del usuario de servidor están almacenadas en s yslogins . Si no se proporciona ninguna s erver_user_id , el resultado es el nombre del usuario actual.

used_pgs ( object_id , doampg , ioampg ) Devuelve el número total de páginas usadas por una tabla y su índice agrupado.

tsequal ( timestamp , timestamp2 )

Compara valores t imestamp para evitar operaciones de actualización en una fila que se ha modificado desde que se seleccionara para examinarse. t imestamp es la marca horaria de la fila examinada. timestamp2 es la marca horaria de la fila almacenada. Esta función permite usar el modo de examinación sin llamar a DB-Library (consulte la sección sobre el modo de examinación).

user Devuelve el nombre del usuario.

user_id ([ user_name ]) Devuelve el número de ID del usuario. Indica el número de s ysusers en la base de datos actual. Si no se proporciona ningún u ser_name , el resultado es la ID del usuario actual.

user_name ([ user_id ]) Devuelve el nombre del usuario, basado en la ID del usuario de la base de datos actual. Si no se proporciona ninguna u ser_id , el resultado es el nombre del usuario actual.

valid_name ( character_expression ) Devuelve 0 si c haracter expression no es un identificador válido (caracteres ilegales o más de 30 bytes de longitud) y un número distinto de cero en caso contrario.

valid_user ( server_user_id )

Devuelve 1 si la ID especificada es un usuario o alias válido en al menos una base de datos de este SQL Server. Debe tener el rol s a_role o sso_role para usar esta función en una s erver_user_id distinta de la propia.

Cuando el argumento de una función del sistema es opcional, se utilizan la base de datos, computadora principal, usuario de servidor o usuario de base de datos actuales. Con la excepción de user , las funciones incorporadas siempre se usan con paréntesis, incluso si el argumento es NULL.

Ejemplos del uso de funciones del sistema

col_length

Esta consulta halla la longitud de la columna title de la tabla titles (la "x=" se incluye para que el resultado tenga un encabezado de columna):

select x = col_length("titles", "title")

x

--------

80

(1 row affected)

datalength

En contraste con col_length , que halla la longitud definida de una columna, datalength informa de la longitud real, en bytes, de los datos almacenados en cada fila. Esta función se utiliza en los tipos de datos varchar , nvarchar , varbinary , text e image , puesto que pueden almacenar longitudes variables. datalength de cualquier dato NULL devuelve NULL. Todos los demás tipos de datos informan de su longitud definida. A continuación se muestra un ejemplo que halla la longitud de la columna pub_name de la tabla publishers :

select Length=datalength(pub_name), pub_name

from publishers

Length pub_name

------ ------------------------

13 New Age Books

16 Binnet & Hardley

20 Algodata Infosystems

(3 rows affected)

isnull

Page 158: 80575032 Libro de SQL y Tl SQL Excelente

Page 158 of 280

Esta consulta halla el promedio de los precios de todos los títulos, sustituyendo el valor ''$10.00'' para todas las entradas NULL de price :

select avg(isnull(price,$10.00))

from titles

------------

14.24

(1 row affected)

user_name

Esta consulta busca la fila en sysusers donde el nombre es igual al resultado de aplicar la función del sistema user_name a la ID de usuario 1:

select name

from sysusers

where name = user_name(1)

name

------------------------

dbo

(1 row affected)

Funciones de cadena

Las funciones de cadena se utilizan para diversas operaciones en cadenas de caracteres o expresiones. Algunas funciones de cadena pueden usarse tanto en datos binarios como de caracteres. También es posible concatenar datos binarios, cadenas de caracteres o expresiones.

Las funciones de cadena incorporadas devuelven valores que suelen necesitarse para operaciones en datos de caracteres. Los nombres de funciones de cadena no son palabras clave.

La sintaxis de las funciones de cadena tiene este formato general:

select function_name ( arguments )

Se pueden concatenar expresiones binarias o de caracteres así:

select ( expression + expression [+ expression ]...)

Cuando se concatenan expresiones que no son de caracteres ni binarias, es necesario utilizar la función convert :

select "The price is " + convert(varchar(12),price)

from titles

La mayoría de las funciones de cadena sólo pueden utilizarse en tipos de datos char , nchar , varchar y nvarchar , así como en tipos de datos que se convierten implícitamente a char o varchar . Algunas funciones de cadena también pueden usarse en datos binary y varbinary . patindex puede utilizarse en columnas text , char , nchar , varchar y nvarchar .

La concatenación puede utilizarse en columnas binary y varbinary , así como en columnas char , nchar , varchar y nvarchar . Sin embargo, no es posible concatener columnas text.

Las funciones de cadena pueden estar anidadas y emplearse en cualquier lugar donde se permita una expresión. Cuando se usan constantes con una función de cadena, hay que incluirlas entre comillas dobles o simples.

La Tabla 10-2 muestra los argumentos utilizados en las funciones de cadena. Si una función usa más de una expresión del mismo tipo, los argumentos se numeran, como char_expr1 , char_expr2.

Tabla 10-2: Argumentos usados en funciones de cadena

Tipo de argumento

Puede sustituirse por

Page 159: 80575032 Libro de SQL y Tl SQL Excelente

Page 159 of 280

char_expr Un nombre de columna de tipo de caracteres, variable, o expresión constante de tipo char , varchar , nchar o nvarchar . Las funciones que aceptan nombres de columna text se indican en la explicación. Las expresiones constantes deben aparecer entre comillas.

expression Un nombre de columna binario o de caracteres, variable o expresión constante. Pueden ser datos char , varchar, ncha r o nvarchar , en cuanto a char_expr , más binary o varbinary .

pattern Una expresión de caracteres de tipo de datos char, nchar, varchar o nvarchar que puede incluir cualquiera de los caracteres comodín de coincidencia con el patrón admitidos por SQL Server.

approx_numeric Cualquier numérico aproximado ( float , real o double precision ), nombre de columna, variable o expresión constante.

integer_expr Cualquier número entero (como tinyint, smallint o int ), nombre de columna, variable o expresión constante. Los márgenes de tamaño máximo se mencionan a medida que se aplican.

start Una expresión entera ( integer_expr).

length Una expresión entera ( integer_expr).

Cada función también acepta argumentos que pueden convertirse implícitamente al tipo especificado. Por ejemplo, las funciones que aceptan expresiones numéricas aproximadas también aceptan las expresiones enteras. SQL Server convierte automáticamente el argumento al tipo deseado.

Tabla 10-3: Funciones de cadena, argumentos y resultados

Fun ción Argument o Resultado

ascii ( char_expr ) Devuelve el código ASCII del primer carácter de la expresión.

char ( integer_expr )

Convierte un valor integer de un solo byte en un valor character . char se utiliza generalmente como el inverso de ascii . integer_expr debe estar entre 0 y 255. Devuelve un tipo de datos char . Si el valor resultante es el primer byte de un carácter multibyte, el carácter puede estar indefinido.

charindex ( expression1, expression2 )

Examina expression2 para buscar la primera aparición de expression1 y devuelve un valor entero que representa su posición inicial. Si no se encuentra expression1 , devuelve 0. Si expression1 contiene caracteres comodín, charindex los trata como literales.

char_length ( char_expr )

Devuelve un valor entero que representa el número de caracteres de una expresión de caracteres o un valor text . Para los datos de longitud variable, char_length quita los espacios en blanco finales de la expresión antes de contar el número de caracteres. Para los juegos de caracteres multibyte, el número de caracteres de la expresión es generalmente menor que el número de bytes; use la función del sistema datalength para determinar el número de bytes.

difference ( char_expr1, char_expr2 )

Devuelve un valor entero que representa la diferencia entre dos valores soundex . Consulte soundex más adelante.

lower ( char_expr ) Convierte mayúsculas en minúsculas. Devuelve un valor de caracteres.

ltrim ( char_expr ) Quita los espacios en blanco iniciales de la expresión de caracteres. Sólo se quitan los valores equivalentes al carácter de espacio en la especificación de caracteres especiales de SQL.

patindex

("% pattern %", char_expr [ using { bytes | chars | characters }] )

Devuelve un valor entero que representa la posición inicial de la primera aparición de pattern en la expresión de caracteres especificada; cero si no se encuentra pattern . De forma predeterminada, patindex devuelve el desplazamiento en caracteres. Para devolver el desplazamiento en bytes, es decir, cadenas de caracteres multibyte, hay que especificar using bytes . El carácter comodín '%' debe preceder y seguir a pattern , excepto cuando se buscan caracteres iniciales o finales. Consulte la sección sobre caracteres comodín en el Manual de Referencia de SQL Server para obtener una descripción de los caracteres comodín que pueden emplearse en pattern . Puede utilizarse en datos text .

replicate ( char_expr, integer_expr )

Devuelve una cadena con el mismo tipo de datos que char_expr , que contiene la misma expresión repetida el número especificado de veces o tantas veces como quepa en un espacio de 255 bytes, cualquiera que sea inferior.

reverse ( char_expr ) Devuelve el inverso de char_expr ; si char_expr es "abcd", devuelve "dcba".

right ( char_expr, integer_expr )

Devuelve la parte de la expresión de caracteres que empieza por el número de caracteres desde la derecha. El valor de retorno tiene el mismo tipo de datos que la expresión de caracteres.

rtrim ( char_expr ) Quita los espacios en blanco finales. Sólo se quitan los valores equivalentes al carácter

Page 160: 80575032 Libro de SQL y Tl SQL Excelente

Page 160 of 280

de espacio en la definición de caracteres especiales de SQL.

soundex ( char_expr ) Devuelve un código soundex de cuatro caracteres para cadenas de caracteres que se componen de una secuencia contigua de letras romanas válidas de un solo byte o de doble byte.

space ( integer_expr ) Devuelve una cadena con el número indicado de espacios de un solo byte.

str ( approx_numeric [, length [, decimal ] ])

Devuelve una representación de caracteres del número de coma flotante. length define el número de caracteres que se devolverán (incluido el punto decimal, todos los dígitos situados a la derecha e izquierda del punto decimal, y los espacios en blanco); decimal define el número de dígitos decimales que se devolverán.

length y decimal son opcionales. Si se especifican, deben ser no negativos. La longitud predeterminada es 10; el decimal predeterminado es 0. str redondea la porción decimal del número para que los resultados quepan dentro de la longitud especificada.

stuff ( char_expr1 , start , length , char_expr2 )

Elimina los caracteres length de char_expr1 en start , después inserta char_expr2 en char_expr1 en start . Para eliminar caracteres sin insertar otros caracteres, char_expr2 debería ser NULL, no " ", que indica un solo espacio.

substring ( expression , start , length )

Devuelve parte de una cadena de caracteres o binaria. start especifica la posición de carácter donde empieza la subcadena. length especifica el número de caracteres de la subcadena.

upper ( char_expr ) Convierte minúsculas en mayúsculas. Devuelve un valor de caracteres.

Ejemplos del uso de funciones de cadena

charindex y patindex

Las funciones charindex y patindex devuelven la posición inicial de un patrón especificado. Ambas toman dos argumentos, pero funcionan de forma ligeramente diferente, puesto que patindex puede utilizar caracteres comodín, pero charindex no. charindex sólo puede utilizarse en columnas char , nchar , varchar y nvarchar ; patindex funciona en estas columnas y en columnas text .

Ambas funciones toman dos argumentos. El primero es el patrón cuya posición se desea. Con patindex , es necesario incluir signos de porcentaje antes y después del patrón, a menos que se esté buscando el patrón como el primer carácter (se omite el % inicial) o el último (se omite el % final) de una columna. Para charindex , el patrón no puede incluir caracteres comodín. El segundo argumento es una expresión de caracteres, generalmente un nombre de columna, en el que SQL Server busca el patrón especificado.

Para encontrar la posición en la que el patrón "wonderful" comienza en una fila determinada de la columna notes de la tabla titles usando ambas funciones, escriba esta consulta:

select charindex("wonderful", notes),

patindex("%wonderful%", notes)

from titles

where title_id = "TC3218"

------------- -------------

46 46

(1 row affected)

Si no limita las filas que deben buscarse, la consulta devolverá todas las filas de la tabla y mostrará valores cero para aquellas filas que no contengan el patrón. En el siguiente ejemplo, patindex busca todas las filas de sysobjects que empiecen con "sys" y cuyo cuarto carácter sea a, b, c o d:

select name

from sysobjects

where patindex("sys[a-d]%", name) > 0

name

------------------------------

sysalternates

sysattributes

syscharsets

syscolumns

syscomments

sysconfigures

sysconstraints

Page 161: 80575032 Libro de SQL y Tl SQL Excelente

Page 161 of 280

syscurconfigs

sysdatabases

sysdepends

sysdevices

(11 rows affected)

str

La función str convierte números en caracteres, con argumentos opcionales para la especificación de la longitud del número (incluido el signo, el punto decimal y los dígitos a la derecha e izquierda del punto decimal) y el número de posiciones después del punto decimal.

Los argumentos de longitud y decimal de str (si se proporcionan) deben ser positivos. La longitud predeterminada es 10. El valor decimal predeterminado es 0. La longitud debe ser suficiente como para que quepa el punto decimal y el signo del número. La parte decimal del resultado se redondea para que quepa dentro de la longitud especificada. Sin embargo, si la parte entera del número no cabe dentro de la longitud, str devuelve una fila de asteriscos con la longitud especificada.

Por ejemplo:

select str(123.456, 2, 4)

--

**

(1 row affected)

Un approx_numeric corto se justifica a la derecha en la longitud especificada y un approx_numeric largo se trunca hasta el número especificado de decimales.

stuff

La función stuff inserta una cadena dentro de otra. stuff elimina una longitud de caracteres especificada de expr1 en la posición inicial y luego inserta la cadena expr2 en la cadena expr1 en la posición inicial. Si la posición inicial o la longitud es negativa, se devuelve una cadena NULL.

Si la posición inicial es mayor que expr1 , se devuelve una cadena NULL. Si la longitud que debe eliminarse es mayor que expr1 , se elimina hasta el último carácter en expr1 . Por ejemplo:

select stuff("abc", 2, 3, "xyz")

----

axyz

(1 row affected)

Para utilizar stuff a fin de eliminar un carácter, sustituya expr2 por NULL, no por comillas vacías. El uso de " " para especificar un carácter nulo lo sustituye por un espacio.

select stuff("abcdef", 2, 3, null)

---

aef

(1 row affected)

select stuff("abcdef", 2, 3, "")

----

a ef

(1 row affected)

soundex y difference

La función soundex convierte una cadena de caracteres en un código de cuatro dígitos para su uso en una comparación. Las vocales se ignoran en la comparación. Los caracteres no alfabéticos terminan la evaluación soundex . Esta función siempre devuelve algún valor. Estos dos nombres tienen códigos soundex idénticos:

Page 162: 80575032 Libro de SQL y Tl SQL Excelente

Page 162 of 280

select soundex ("smith"), soundex ("smythe")

----- -----

S530 S530

La función difference compara los valores soundex de dos cadenas y evalúa la similitud entre ellos, devolviendo un valor de 0 a 4. Un valor de 4 es la mejor coincidencia posible. Por ejemplo:

select difference("smithers", "smothers")

---------

4

(1 row affected)

select difference("smothers", "brothers")

---------

2

(1 row affected)

La mayoría de las funciones de cadena restantes son fáciles de usar y de entender. Por ejemplo:

Tabla 10-4: Ejemplos de funciones de cadena

Instrucción Resultado

select right("abcde", 3) cde

select right("abcde", 6) abcde

select upper("torso") TORSO

select ascii("ABC") 65

substring

El siguiente ejemplo usa la función substring . En él se muestra el apellido y la letra inicial de cada autor, por ejemplo, "Bennet A".

select au_lname, substring(au_fname, 1, 1)

from authors

La función substring hace lo que su nombre implica: devuelve una parte de una cadena de caracteres o binaria.

La función substring siempre toma tres argumentos. El primero puede ser una cadena de caracteres o binaria, un nombre de columna o una expresión con valor de cadena que incluya un nombre de columna. El segundo indica la posición donde debe empezar la subcadena. El tercero especifica la longitud, en número de caracteres, de la cadena que ha de devolverse.

Este es el aspecto de la sintaxis de substring :

substring( expression , start , length )

Por ejemplo, a continuación se indica cómo especificar los caracteres segundo, tercero y cuarto de la constante de caracteres "abcdef":

select x = substring("abcdef", 2, 3)

x

---------

bcd

Concatenación

Es posible concatenar expresiones binarias o de caracteres (combinar dos o más cadenas de caracteres o binarias, datos de caracteres o binarios, o una combinación de los mismos) mediante el operador de concatenación de cadenas +.

Si concatena cadenas de caracteres, incluya cada expresión de caracteres entre comillas simples o dobles.

Esta es la sintaxis de la concatenación:

Page 163: 80575032 Libro de SQL y Tl SQL Excelente

Page 163 of 280

select ( expression + expression [+ expression ]...)

A continuación se muestra cómo combinar dos cadenas de caracteres:

select ("abc" + "def")

-------

abcdef

(1 row affected)

Esta consulta muestra los nombres de autor de California bajo el encabezado de columna Moniker , en el orden apellido-nombre y con una coma y un espacio después del apellido:

select Moniker = (au_lname + ", " + au_fname)

from authors

where state = "CA"

Moniker

-------------------------------------------------

White, Johnson

Green, Marjorie

Carson, Cheryl

O'Leary, Michael

Straight, Dick

Bennet, Abraham

Dull, Ann

Gringlesby, Burt

Locksley, Chastity

Yokomoto, Akiko

Stringer, Dirk

MacFeather, Stearns

Karsen, Livia

Hunter, Sheryl

McBadden, Heather

(15 rows affected)

Para concatenar tipos de datos numéricos o datetime , es necesario usar la función convert :

select "The due date is " + convert(varchar(30),

pubdate)

from titles

where title_id = "BU1032"

---------------------------------------

The due date is Jun 12 1985 12:00AM

(1 row affected)

Concatenación y cadenas vacías

La cadena vacía ("" o ") se evalúa como un solo espacio. Esta instrucción:

select "abc" + "" + "def"

da como resultado:

abc def

Funciones de cadena anidadas

Las funciones de cadena pueden anidarse. Por ejemplo, para mostrar el apellido y la primera inicial del cada autor, con una coma después del apellido y un punto después del primer nombre, puede teclear:

select (au_lname + "," + " " + substring(au_fname, 1, 1) + ".")

from authors

where city = "Oakland"

Page 164: 80575032 Libro de SQL y Tl SQL Excelente

Page 164 of 280

--------------------------------------------

Green, M.

Straight, D.

Stringer, D.

MacFeather, S.

Karsen, L.

(5 rows affected)

Para mostrar la pub_id y los dos primeros caracteres de cada title_id de los libros por encima de $20, escriba:

select substring(pub_id + title_id, 1, 6)

from titles

where price > $20

--------------

1389PC

0877PS

0877TC

(3 rows affected)

Funciones de texto

Las funciones de texto incorporadas se utilizan para operaciones en datos text e image . Los nombres de función de texto, argumentos y resultados se muestran en la Tabla 10-5.

Tabla 10-5: Funciones de texto incorporadas para datos text e image

Función Argumento Resultado

patindex

("% pattern %", char_expr [ using { bytes | chars | characters } ] )

Devuelve un valor entero que representa la posición inicial de la primera aparición de pattern en la expresión de caracteres especificada; cero si no se encuentra pattern . De forma predeterminada, patindex devuelve el desplazamiento en caracteres; para devolver el desplazamiento en bytes para cadenas de caracteres multibyte, hay que especificar using bytes . El carácter comodín % debe preceder y seguir a pattern , excepto cuando se buscan caracteres iniciales o finales. Consulte la sección sobre caracteres comodín del Manual de Referencia de SQL Server para obtener una descripción de los caracteres comodín que se pueden utilizar en pattern .

textptr ( text_columname ) Devuelve el valor del puntero de texto, un valor binario de 16 bytes. El puntero de texto se verifica para garantizar que apunte a la primera página de texto.

textvalid (" table_name .. col_name ", textpointer )

Verifica si es válido un puntero de texto dado. Tenga en cuenta que el identificador para una columna text o image debe incluir el nombre de la tabla. Devuelve 1 si el puntero es válido, 0 si el puntero no es válido.

set textsize

{ n | 0 }

Especifica el límite, en bytes, de los datos t ext o image que van a ser devueltos con una instrucción select . El valor actual se almacena en la variable global @@textsize . n es un número entero que especifica el límite en el número de bytes a devolver; 0 restaura el límite predeterminado de 32K.

Además de estas funciones, datalength (descrita en "Funciones del sistema") funciona en columnas text . También pueden usarse las variables globales @@textcolid , @@textdbid , @@textobjid , @@textptr y @@textsiz e para manipular datos text e image .

Ejemplos del uso de funciones de texto

Este ejemplo utiliza la función textptr para localizar la columna text , blurb , asociada con la title_id BU7832 de la tabla texttest . El puntero de texto, una cadena binaria de 16 bytes, se incluye en una variable local, @val , y se suministra como parámetro del comando readtext . readtext devuelve 5 bytes empezando en el segundo byte, con un desplazamiento de 1.

create table texttest

(title_id varchar(6),blurb text null, pub_id

char(4))

insert texttest values ("BU7832", "Straight Talk

About Computers is an annotated analysis of

what computers can do for you: a no-hype guide

for the critical user", "1389")

Page 165: 80575032 Libro de SQL y Tl SQL Excelente

Page 165 of 280

declare @val varbinary(16)

select @val = textptr(blurb) from texttest

where title_id = "BU7832"

readtext texttest.blurb @val 1 5

La función textptr devuelve una cadena binaria de 16 bytes. Es una buena idea poner esta cadena en una variable local, como en el ejemplo anterior, y utilizarla como referencia.

Una alternativa a la función textptr del ejemplo anterior es la variable global @@textptr :

create table texttest

(title_id varchar(6),blurb text null, pub_id

char(4))

insert texttest values ("BU7832", "Straight Talk

About Computers is an annotated analysis of

what computers can do for you: a no-hype guide

for the critical user", "1389")

readtext texttest.blurb @@textptr 1 5

El valor de @@textptr se define a partir de la última operación insert o update realizada en un campo text o image por el proceso actual de SQL Server. Las inserciones y actualizaciones efectuadas por otros procesos no afectan al proceso actual.

La conversión explícita mediante la función convert se admite de text a char , nchar , varchar o nvarchar , y de image a varbinary o binary , pero los datos text o image se truncan a 255 bytes. La conversión de datos text o image a tipos de datos distintos de los indicados no se admite, ni implícita ni explícitamente.

Funciones matemáticas

Las funciones matemáticas incorporadas devuelven valores que normalmente son necesarios para realizar operaciones en datos matemáticos.

Las funciones matemáticas tienen este formato general:

function_name ( arguments )

La tabla a continuación muestra los tipos de argumentos utilizados en las funciones matemáticas incorporadas:

Tabla 10-6: Argumentos usados en las funciones matemáticas

Tipo de argumento

Puede sustituirse por

approx_numeric Cualquier numérico aproximado ( float , real o double precision ), nombre de columna, variable, expresión constante, o una combinación de los mismos.

integer Cualquier número entero ( tinyint , smallint o int), nombre de columna, variable, expresión constante, o una combinación de los mismos.

numeric Cualquier numérico exacto ( numeric , dec , decimal , tinyint , smallint o int ), numérico aproximado ( float , real o double precision ), o columna money , variable, expresión constante, o una combinación de los mismos

power Cualquier numérico exacto, numérico aproximado o columna money , variable, expresión constante, o una combinación de los mismos.

Cada función también acepta argumentos que pueden convertirse implícitamente al tipo especificado. Por ejemplo, las funciones que aceptan tipos numéricos aproximados también aceptan tipos de enteros. SQL Server convierte automáticamente el argumento al tipo deseado.

Si una función incluye más de una expresión del mismo tipo, las expresiones están numeradas (por ejemplo, approx_numeric1 , approx_numeric2 ).

A continuación se muestran las funciones matemáticas, sus argumentos y los resultados que devuelven:

Page 166: 80575032 Libro de SQL y Tl SQL Excelente

Page 166 of 280

Tabla 10-7: Funciones matemáticas

Func ión

Argumento Resultado

abs ( numeric ) Devuelve el valor absoluto de una expresión dada. Los resultados son del mismo tipo y tienen la misma precisión y escala que la expresión numérica.

acos ( approx_numeric ) Devuelve el ángulo (en radianes) cuyo coseno es el valor especificado.

asin ( approx_numeric ) Devuelve el ángulo (en radianes) cuyo seno es el valor especificado.

atan ( approx_numeric ) Devuelve el ángulo (en radianes) cuya tangente es el valor especificado.

atn2 ( approx_numeric1 , approx_numeric2 )

Devuelve el ángulo (en radianes) cuya tangente es ( approx_numeric1 / approx_numeric2 ).

ceiling ( numeric ) Devuelve el número entero más pequeño mayor o igual que el valor especificado. Los resultados son del mismo tipo que la expresión numérica. Para expresiones numeric y decimal , los resultados tienen una precisión igual que la de la expresión y una escala de 0.

cos ( approx_numeric ) Devuelve el coseno trigonométrico del ángulo especificado (en radianes).

cot ( approx_numeric ) Devuelve la cotangente trigonométrica del ángulo especificado (en radianes).

degrees ( numeric )

Convierte radianes en grados. Los resultados son del mismo tipo que la expresión numérica. Para expresiones numeric y decimal , los resultados tiene una precisión interna de 77 y una escala igual a la de la expresión. Cuando se utiliza el tipo de datos money, la conversión interna a float puede provocar una pérdida de precisión.

exp ( approx_numeric ) Devuelve el valor exponencial del valor especificado.

floor ( numeric ) Devuelve el número entero más grande menor o igual que el valor especificado. Los resultados son del mismo tipo que la expresión numérica. Para expresiones de tipo numeric o decimal , los resultados tendrán una precisión igual a la de la expresión y una escala de 0.

log ( approx_numeric ) Devuelve el logaritmo natural del valor especificado.

log10 ( approx_numeric ) Devuelve el logoritmo de base 10 del valor especificado.

pi () Devuelve el valor constante de 3.1415926535897936.

power ( numeric , power ) Devuelve el valor de numeric elevado a la potencia de power. Los resultados son del mismo tipo que numeric. Para expresiones de tipo numeric o decimal , los resultados tienen una precisión de 77 y una escala igual a la de la expresión.

radians ( numeric_expr )

Convierte grados a radianes. Los resultados son del mismo tipo que numeric. Para expresiones de tipo numeric o decimal , los resultados tienen una precisión interna de 77 y una escala igual a la de la expresión numérica. Cuando se utiliza el tipo de datos money, la conversión interna a float puede provocar una pérdida de precisión.

rand ([ integer ]) Devuelve un valor float aleatorio entre 0 y 1, utilizando el integer opcional como valor semilla.

round ( numeric , integer )

Redondea el valor numeric para que tenga dígitos integer significativos. Un valor entero positivo determina el número de dígitos significativos a la derecha del punto decimal; un entero negativo, el número de dígitos significativos a la izquierda del punto decimal. Los resultados son del mismo tipo que la expresión numérica y, para expresiones numeric y decimal , tienen una precisión interna de 77 y una escala igual a la de la expresión numérica.

sign ( numeric ) Devuelve el signo de numeric : positivo (+1), cero (0) o negativo (-1). Los resultados son del mismo tipo y tienen la misma precisión y escala que la expresión numérica.

sin ( approx_numeric ) Devuelve el seno trigonométrico del ángulo especificado (medido en radianes).

sqrt ( approx_numeric ) Devuelve la raíz cuadrado del valor especificado.

tan ( approx_numeric ) Devuelve la tangente trigonométrica del ángulo especificado (medido en radianes).

Ejemplos del uso de funciones matemáticas

Las funciones matemáticas incorporadas operan en datos numéricos. Algunas funciones requieren datos de número entero y otras datos numéricos aproximados. Un número de funciones operan en tipos numéricos exactos, numéricos aproximados, money y float . De forma predeterminada, la precisión de las operaciones incorporadas en los datos de tipo float es de 6 posiciones decimales.

Se proporcionan trampas de error para manipular los errores de dominio o margen de las funciones matemáticas. Los usuarios pueden definir ( set ) las opciones arithabort y arithignore para determinar el modo en que se manipulan los errores. Para obtener más información sobre estas opciones, consulte la sección "Errores de conversión".

A continuación se muestran ejemplos sencillos de funciones matemáticas:

Page 167: 80575032 Libro de SQL y Tl SQL Excelente

Page 167 of 280

Tabla 10-8: Ejemplos de funciones matemáticas

Instrucción Resultado

select floor(123) select floor(123.45) select floor(1.2345E2) select floor(-123.45) select floor(-1.2345E2) select floor($123.45)

123 123.000000 123.000000 -124.000000 -124.000000 123.00

select ceiling(123.45) select ceiling(-123.45) select ceiling(1.2345E2) select ceiling(-1.2345E2) select ceiling($123.45)

124.000000 -123.000000 124.000000 -123.000000 124.00

select round(123.4545, 2) select round(123.45, -2) select round(1.2345E2, 2) select round(1.2345E2, -2)

123.4500 100.00 123.450000 100.000000

La función round(numeric, integer) devuelve siempre un valor. Si integer es negativo y supera el número de dígitos significativos de numeri c, SQL Server redondea sólo el dígito más significativo. Por ejemplo:

select round(55.55, -3)

devuelve el valor 100.000000 (el número de ceros a la derecha del punto decimal es igual a la escala de numeric ).

Funciones de fecha

Las funciones de fecha incorporadas se utilizan para mostrar información sobre fechas y horas. Estas funciones manipulan valores datetime y smalldatetime, y realizan operaciones aritméticas en ellos.

Las funciones de fecha pueden utilizarse en la lista select , la cláusula where o cualquier lugar que permita una expresión.

Los valores con el tipo de datos datetime son almacenados internamente por SQL Server como dos números enteros de 4 bytes. Los primeros 4 bytes almacenan el número de días antes o después de la fecha base, 1 de enero de 1900 (January 1, 1900). La fecha base es la fecha de referencia del sistema. No se permiten valores datetime anteriores al 1 de enero de 1753. Los otros 4 bytes de la representación interna de los datos de fecha y hora almacenan la hora del día hasta una precisión de 1/300 de un segundo.

El tipo de datos smalldatetime almacena las fechas y horas del día con menos precisión que datetime . Los valores smalldatetime se almacenan como dos números enteros de 2 bytes. Los primeros 2 bytes almacenan el número de días después del 1 de enero de 1900. Los otros 2 bytes almacenan el número de minutos desde la medianoche. Las fechas van desde el 1 de enero de 1900 hasta el 6 de junio de 2079, con una precisión al minuto.

El formato de visualización predeterminado de las fechas tiene el siguiente aspecto:

Apr 15 1987 10:23PM

Consulte la sección sobre convert , más adelante en este capítulo, para obtener más información sobre cómo cambiar el formato de visualización de datetime o smalldatetime . Cuando se introducen valores datetime o smalldatetime , hay que incluirlos entre comillas simples o dobles. SQL Server reconoce una amplia variedad de formatos de entrada de datos de fecha y hora. Para obtener más información sobre los valores datetime y smalldatetime , consulte el Capítulo 7, "Creación de bases de datos y tablas", y el Capítulo 8, "Adición, modificación y eliminación de datos".

La siguiente tabla muestra las funciones de fecha y los resultados que generan:

Tabla 10-9: Funciones de fecha

Función Argumento Resultado

getdate ( ) Fecha y hora actuales del sistema.

datename ( datepart , date ) Parte de un valor datetime o smalldatetime como una cadena ASCII.

Page 168: 80575032 Libro de SQL y Tl SQL Excelente

Page 168 of 280

datepart ( datepart , date ) Parte de un valor datetime o smalldatetime , por ejemplo, el mes, como un valor entero.

datediff (datepart, date, date)

La cantidad de tiempo entre la segunda y la primera de las dos fechas, convertida al componente de fecha especificado, por ejemplo, meses, días, horas.

dateadd (datepart, number, date)

Una fecha generada al añadir componentes de fecha a otra fecha.

Las funciones datename , datepart , datediff y dateadd toman como argumentos un componente de fecha (año, mes, hora, etc.). La siguiente tabla enumera cada componente de fecha, su abreviatura, si hubiera alguna, y los valores enteros posibles para dicho componente de fecha. La función datename genera valores ASCII donde se necesitan, como para el día de la semana.

Tabla 10-10: Componentes de fecha

Componente de fecha Abreviatura Valores

year yy 1753-9999

quarter qq 1 - 4

month mm 1 - 12

week wk 1 - 366

day dd 1 - 31

dayofyear dy 1 - 54

weekday dw 1 - 7 (1 es domingo en us_english)

hour hh 0 - 23

minute mi 0 - 59

second ss 0 - 59

millisecond ms 0 - 999

Observe que los valores del componente de fecha weekday se ven afectados por el valor del idioma.

Obtención de la fecha actual: getdate

La función getdate genera la fecha y hora actuales en el formato interno de SQL Server para valores datetime y smalldatetime . getdate usa el argumento NULL, ().

Para hallar la fecha y hora actuales del sistema, escriba:

select getdate()

--------------------------

Jul 29 1991 2:50 PM

(1 row affected)

Podría utilizar getdate al diseñar un informe para que la fecha y hora actuales se impriman cada vez que se genere el informe. getdate también resulta útil para funciones como el registro de la hora en que tuvo lugar una transacción en una cuenta.

Búsqueda de componentes de fecha como números o nombres

Las funciones datepart y datename generan el componente especificado de un valor datetime o smalldatetime (el año, trimestre, día, hora, etc.) como un número entero o una cadena ASCII. Dado que smalldatetime sólo tiene una precisión de minutos, cuando se utiliza un valor smalldatetime con cualquiera de estas funciones, los segundos y milisegundos siempre son cero.

Los siguientes ejemplos toman la fecha del 29 de julio (July 29) que aparece en el ejemplo anterior.

select datepart(month, getdate())

--------------

7

(1 row affected)

Page 169: 80575032 Libro de SQL y Tl SQL Excelente

Page 169 of 280

select datename ( month , getdate ())

-------------

July

(1 row affected)

Cálculo de intervalos o fechas incrementales

La función datediff calcula la cantidad de tiempo en componentes de fecha entre la segunda y la primera de las dos fechas especificadas; en otras palabras, datediff halla un intervalo entre dos fechas. El resultado es un valor entero con signo igual al date2 - date1 , en componentes de fecha.

Esta consulta utiliza la fecha 30 de noviembre de 1985 y halla el número de días que han transcurrido entre pubdate y dicha fecha:

select newdate = datediff(day, pubdate,

"Nov 30 1985")

from titles

Para las filas de titles que tienen una pubdate del 21 de octubre de 1985, el resultado generado por la consulta anterior es 40, el número de días entre el 21 de octubre y el 30 de noviembre. Para calcular un intervalo en meses, la consulta es:

select interval = datediff(month, pubdate,

"Nov 30 1985")

from titles

Esta consulta genera el valor 1 para las filas con una pubdate en octubre y el valor 5 para las filas con una pubdate en junio. Cuando la primera fecha de la función datediff es posterior a la segunda fecha especificada, el valor resultante es negativo. Dado que dos de las filas de titles tienen valores pubdate que se han asignado utilizando la función getdate como valor predeterminado, estos valores se definen según la fecha en la que se creó la base de datos pubs y devuelven valores negativos en las dos consultas anteriores.

Si uno o ambos argumentos de fecha es un valor smalldatetime, se convierten en valores datetime internamente para el cálculo. Los segundos y milisegundos de los valores smalldatetime se definen automáticamente en 0 de cara al cálculo de diferencias.

Adición de un intervalo de fecha: dateadd

La función dateadd añade un intervalo a una fecha especificada. Por ejemplo, si las fechas de publicación de todos los libros de la tabla titles se modificasen en tres días, podría obtener las nuevas fechas de publicación con esta instrucción:

select dateadd(day, 3, pubdate)

from titles

-------------------

Jun 15 1985 12:00AM

Jun 12 1985 12:00AM

Jul 3 1985 12:00AM

Jun 25 1985 12:00AM

Jun 12 1985 12:00AM

Jun 21 1985 12:00AM

Sep 11 1986 11:02AM

Jul 3 1985 12:00AM

Jun 15 1985 12:00AM

Sep 11 1986 11:02AM

Oct 24 1985 12:00AM

Jun 18 1985 12:00AM

Oct 8 1985 12:00AM

Jun 15 1985 12:00AM

Jun 15 1985 12:00AM

Oct 24 1985 12:00AM

Jun 15 1985 12:00AM

Jun 15 1985 12:00AM

(18 rows affected)

Si el argumento de fecha se proporciona como un valor smalldatetime , el resultado también será smalldatetime . Puede utilizar dateadd para añadir segundos o milisegundos a un smalldatetime , pero sólo tiene sentido si la fecha resultante devuelta por dateadd cambia al menos en un minuto.

Page 170: 80575032 Libro de SQL y Tl SQL Excelente

Page 170 of 280

Funciones de conversión de tipos de datos

Las conversiones de tipo de datos cambian una expresión de un tipo de datos a otro y vuelve a dar formato a la información de fecha y hora. SQL Server realiza determinadas conversiones de tipo de datos de forma automática, que reciben el nombre de conversiones implícitas. Por ejemplo, si compara una expresión char y otra datetime , o una expresión smallint y otra int , o expresiones char de longitudes diferentes, SQL Server convierte automáticamente un tipo de datos a otro.

Otras conversiones de tipo de datos deben solicitarse de forma explícita, utilizando una de las funciones de conversión de tipos de datos incorporadas. Por ejemplo, antes de concatenar expresiones numéricas, es necesario convertirlas a expresiones de caracteres.

SQL Server proporciona tres funciones de conversión de tipos de datos, convert , inttohex y hextoint . Estas funciones pueden emplearse en la lista select , la cláusula where y cualquier lugar donde se permita una expresión.

SQL Server no permite convertir ciertos tipos de datos a otros tipos de datos, ni de forma implícita ni explícita. Por ejemplo, no se pueden convertir datos smallint a datetime , ni datos datetime a smallint . Las conversiones no admitidas generan mensajes de error.

Conversiones soportadas

La Figura 10-1: Conversiones de tipos de datos implícitas, explícitas y no soportadas resume las conversiones de tipos de datos soportadas por SQL Server:

Las conversiones marcadas como "I" se manipulan implícitamente y no requieren ninguna función de conversión de tipos de datos, aunque es posible utilizar la función convert en ellas sin error.

Las conversiones marcadas como "E" deben realizarse explícitamente, con la función de conversión de tipo de datos adecuada .

Las conversiones marcadas como "IE" se manipulan implícitamente cuando no existe una pérdida de precisión o escala y la opción arithabort numeric_truncation está activada, pero, en caso contrario, requieren una conversión explícita.

Las conversiones marcadas como "U" no se soportan. Si intenta realizar una conversión de este tipo, SQL Server generará un mensaje de error.

Las conversiones de un tipo en sí mismo se marcan como "-" . En general, SQL Server no prohibe la conversión explícita de un tipo en sí mismo, pero no tiene sentido.

Figure 10-3: Conversiones de tipos de datos implícitas, explícitas y no soportadas

Uso de la función de conversión general: convert

La función de conversión general, convert , se utiliza para realizar conversiones entre una amplia variedad de tipos de datos y especificar un nuevo formato de visualización para la información de fecha y hora. Su sintaxis es:

convert( datatype, expression [, style ] )

A continuación se muestra un ejemplo que emplea convert en la lista de selección:

select title, convert(char(5), total_sales)

from titles

where type = "trad_cook"

title

------------------------------------ -----

Onions, Leeks, and Garlic: Cooking

Secrets of the Mediterranean 125

Fifty Years in Buckingham Palace

Kitchens 15096

Sushi, Anyone? 5405

(3 rows affected)

En este ejemplo, la columna total_sales , una columna int , se convierte a una columna char (5) para que pueda utilizarse con la palabra clave like :

Page 171: 80575032 Libro de SQL y Tl SQL Excelente

Page 171 of 280

select title, total_sales

from titles

where convert(char(5), total_sales) like "15%"

and type = "trad_cook"

title

--------------------------------- -----

Fifty Years in Buckingham Palace

Kitchens 15096

(1 row affected)

Algunos tipos de datos esperan una longitud o una precisión y escala. Si no especifica una longitud, SQL Server utiliza la longitud predeterminada 30 para los datos de caracteres y binarios. Si no especifica una precisión o escala, SQL Server utiliza los valores predeterminados 18 y 0, respectivamente.

Reglas de conversión

En las siguientes secciones se describen las reglas que SQL Server tiene en cuenta al convertir tipos diferentes de información:

Conversión de datos de caracteres a un tipo de datos no de caracteres

Los datos de caracteres pueden convertirse a un tipo de datos no de caracteres (como el monetario, fecha y hora, numérico exacto o numérico aproximado) si se componen totalmente de caracteres que son válidos para el tipo nuevo. Los espacios en blanco iniciales se ignoran.

Los errores de sintaxis se generan cuando los datos incluyen caracteres inaceptables. Los siguientes son algunos ejemplos de caracteres que pueden generar errores de sintaxis:

Comas o puntos decimales en datos de números enteros

Comas en datos monetarios

Letras en datos numéricos exactos o aproximados o datos de flujo de bits

Nombres de meses mal escritos en datos de fecha y hora

Conversión de un tipo de caracteres a otro

Al convertir de un juego de caracteres multibyte a otro de un solo byte, los caracteres sin un equivalente de un solo byte se convierten en espacios en blanco.

Las columnas text pueden convertirse explícitamente a char, nchar , varchar o nvarchar . El límite viene determinado por la longitud máxima de los tipos de datos de caracteres, 255 bytes. Si no especifica la longitud, el valor convertido tiene una longitud predeterminada de 30 bytes.

Conversión de números a un tipo de caracteres

Los datos numéricos exactos y aproximados pueden convertirse a un tipo de caracteres. Si el tipo nuevo es demasiado corto para albergar la cadena completa, se genera un error de espacio insuficiente. Por ejemplo, la siguiente conversión intenta almacenar una cadena de 5 caracteres en un tipo de 1 carácter:

select convert(char(1), 12.34)

Espacio de resultado insuficiente para la conversión explícita del valor NUMERIC '12.34' en

un campo CHAR.

Redondeo durante la conversión con tipos monetarios

Los tipos money y smallmoney almacenan cuatro dígitos a la derecha del punto decimal, pero redondean hasta la centena más próxima (.01) para fines de visualización. Cuando los datos se convierten a un tipo monetario, se redondean hasta cuatro posiciones.

Si es posible, los datos convertidos de un tipo monetario siguen el mismo comportamiento de redondeo. Si el tipo nuevo es un numérico exacto con menos de tres posiciones decimales, los datos se redondean a la escala del tipo nuevo. Por ejemplo, cuando $4.50 se convierte a un valor entero, el resultado es 4:

select convert(int, $4.50)

Page 172: 80575032 Libro de SQL y Tl SQL Excelente

Page 172 of 280

-----------

4

Los datos convertidos a money o smallmoney se supone que están en unidades monetarias completas, como dólares, en lugar de unidades fraccionarias, como céntimos. Por ejemplo, el valor entero 4 se convertiría al equivalente monetario de 4 dólares, no 4 céntimos, en us_english.

Conversión de información de fecha y hora

Los datos que son reconocibles como una fecha pueden convertirse a datetime o smalldatetime . Los nombres de meses incorrectos provocan errores de sintaxis. Las fechas que se encuentran fuera del margen aceptable del tipo de datos generan errores de desbordamiento aritmético.

Cuando los valores datetime se convierten a smalldatetime , se redondean al minuto más próximo.

Conversión entre tipos numéricos

Los datos pueden convertirse de un tipo numérico a otro. Si el tipo nuevo es un numérico exacto cuya precisión o escala no es suficiente para albergar los datos, se pueden producir errores. Use las opciones arithabort y arithignore se para determinar el modo en que se manipulan estos errores.

Note: Las opciones arithabort y arithignore se han redefinido para SQL Server, Versión 10.0. Si utiliza estas opciones en sus aplicaciones, examínelas para asegurarse de que todavía funcionan correctamente.

Conversión de datos de tipo binario

Los datos binary y varbinary de SQL Server son específicos de la plataforma; el tipo de hardware que se utiliza determina el modo en que se almacenan e interpretan los datos. Algunas plataformas consideran el primer byte después del prefijo 0x como el más significativo; otras consideran el primer byte como el menos significativo.

La función convert trata los datos binarios de Sybase como si fueran una cadena de caracteres, en lugar de información numérica. convert no tiene en cuenta la importancia del orden de los bytes al convertir una expresión binaria a un valor entero o una expresión de número entero a un valor binario. Debido a esto, los resultados de la conversión pueden variar de una plataforma a otra.

Antes de convertir una cadena binaria a un número entero, convert elimina su prefijo 0x. Si la cadena se compone de un número de dígitos impar, SQL Server inserta un cero inicial. Si los datos son demasiado largos para el tipo entero, convert los trunca. Si los datos son demasiado cortos, convert los justifica a la derecha y los rellena con ceros.

Supongamos que se quiere convertir la cadena 0x00000100 a un número entero. En algunas plataformas, esta cadena representa el número 1; en otras, el número 256. Dependiendo de la plataforma que ejecute la función, convert devuelve 1 o 256 en otras.

Conversión de datos hexadecimales

Para los resultados de conversión que son fiables a través de plataformas, utilice las funciones hextoint e inttohex .

hextoint acepta literales o variables que se componen de dígitos y las letras de la A a la F en mayúsculas y minúsculas, con o sin un prefijo 0x. Estos son usos válidos de hextoint :

hextoint("0x00000100FFFFF")

hextoint("0x00000100")

hextoint("100")

hextoint elimina el prefijo 0x. Si los datos superan los ocho dígitos, hextoint los trunca. Si los datos tienen menos de ocho dígitos, hextoint los justifica a la derecha y los rellena con ceros. A continuación, hextoint devuelve el valor entero equivalente independiente de la plataforma. Las expresiones descritas anteriormente devuelven el mismo valor, 256, independientemente de la plataforma que ejecute la función hextoint .

La función inttohex acepta datos de valor entero y devuelve una cadena hexadecimal de 8 caracteres sin prefijo 0x. inttohex siempre devuelve los mismos resultados, independientemente de la plataforma que se esté utilizando.

Page 173: 80575032 Libro de SQL y Tl SQL Excelente

Page 173 of 280

Conversión de datos image a binary o varbinary

La función convert se puede utilizar para convertir una columna image a binary o varbinary . Los tipos de datos binary tienen una longitud máxima, que es de 255 bytes. Si no se especifica la longitud, el valor convertido tiene una longitud predeterminada de 30 caracteres.

Errores de conversión

En las siguientes secciones se describen los tipos de errores que pueden producirse durante las conversiones de tipos de datos.

Errores de desbordamiento aritmético y de división por cero

Los errores de división por cero se producen cuando SQL Server intenta dividir un valor numérico por cero. Los errores de desbordamiento aritmético se generan cuando las posiciones decimales del tipo nuevo no son suficientes para albergar los resultados. Esto ocurre durante:

Conversiones explícitas o implícitas a tipos exactos con una precisión o escala inferior.

Conversiones de datos explícitas o implícitas que se encuentran fuera del margen aceptable para un tipo monetario o de fecha y hora.

Conversiones de cadenas superiores a 4 bytes mediante hextoint.

Los errores de desbordamiento aritmético y de división por cero se consideran graves, independientemente de que se produzcan durante conversiones implícitas o explícitas. Use la opción arithabort arith_overflow para determinar el modo en que SQL Server manipula estos errores. El valor predeterminado, arithabort arith_overflow on , revierte toda la transacción o lote donde se genera el error. Si define arithabort arith_overflow off , SQL Server aborta la instrucción que origina el error, pero continúa procesando otras instrucciones de la transacción o lote. Puede utilizar la variable global @@error para verificar los resultados de la instrucción.

Utilice la opción arithignore arith_overflow para determinar si SQL Server muestra un mensaje después de estos errores. El valor predeterminado, off , muestra un mensaje de advertencia cuando se produce un error de división por cero o una pérdida de precisión. La definición de arithignore arith_overflow on suprime los mensajes de advertencia tras estos errores. La palabra clave arith_overflow puede omitirse sin efecto alguno.

Errores de escala

Cuando los resultados de una conversión explícita originan una pérdida de escala, los resultados se truncan sin ninguna advertencia. Por ejemplo, cuando convierte explícitamente un tipo numérico float , numeric o decimal a un integer , SQL Server supone que en realidad desea que el resultado sea un número entero y trunca todos los números a la derecha del punto decimal.

Durante las conversiones implícitas a tipos numeric o decimal , la pérdida de escala genera un error de escala. Use la opción arithabort numeric_truncation para determinar la gravedad de un error de ese tipo. El valor predeterminado, arithabort numeric_truncation on , aborta la instrucción que origina el error, pero continúa procesando otras instrucciones de la transacción o lote. Si define arithabort numeric_truncation off , SQL Server trunca los resultados de la consulta y sigue procesando.

Errores de dominio

La función convert genera un error de dominio cuando el argumento de la función se encuentra fuera del margen sobre el que se define la función. Esto debería ocurrir con poca frecuencia. Conversiones entre tipos binary e integer

Los tipos binary y varbinary almacenan datos de tipo hexadecimal que se componen de un prefijo 0x seguido de una cadena de dígitos y letras. Estas cadenas se interpretan de forma distinta en plataformas diferentes. Por ejemplo, la cadena 0x0000100 representa 65536 en las máquinas que consideran el byte 0 como el más significativo y 256 en las máquinas que consideran el byte 0 como el menos significativo. La función convert y las conversiones implícitas

Los tipos binarios pueden convertirse a valores enteros explícitamente, con la función convert , o implícitamente. Los datos pierden el prefijo 0x y después se rellenan con ceros si son demasiado cortos para el tipo nuevo, o se truncan si son demasiado largos.

convert y las conversiones de tipos de datos implícitas evalúan los datos binarios de forma distinta en plataformas diferentes. Debido a esto, los resultados pueden variar de una plataforma a otra. Emplee la función hextoint para la conversión

Page 174: 80575032 Libro de SQL y Tl SQL Excelente

Page 174 of 280

independiente de la plataforma de cadenas de caracteres hexadecimales a valores enteros y la función inttohex para la conversión independiente de la plataforma de valores enteros a valores hexadecimales. La función hextoint

La función hextoint se utiliza para las conversiones independientes de la plataforma de datos hexadecimales a valores enteros. hextoint acepta una cadena hexadecimal válida, con o sin un prefijo 0x, entre comillas, o el nombre de una columna de tipo de caracteres o variable.

hextoin t devuelve el entero equivalente de la cadena hexadecimal. La función siempre devuelve el mismo entero equivalente para una cadena de caracteres hexadecimal dada, independientemente de la plataforma en la que se ejecute. La función inttohex

La función inttohex se utiliza para conversiones independientes de la plataforma de valores enteros a cadenas hexadecimales. inttohex acepta cualquier expresión que dé como resultado un número entero. La función siempre devuelve el mismo equivalente hexadecimal para una expresión dada, independientemente de la plataforma en la que se ejecute. Conversión de columnas image a tipos binary

La función convert puede utilizarse para convertir una columna image a binary o varbinary . Los tipos de datos binary tienen una longitud máxima, que es de 255 bytes. Si no especifica la longitud, el valor convertido tiene una longitud predeterminada de 30 caracteres. Conversión de otros tipos de datos al tipo de bits

Los tipos numéricos exactos y aproximados pueden convertirse al tipo de bits de forma implícita. Los tipos de caracteres requieren una función convert explícita.

La expresión objeto de la conversión debe componerse sólo de dígitos, un punto decimal, un símbolo monetario y un signo de suma o resta. La presencia de otros caracteres genera errores de sintaxis.

El equivalente bit de 0 es 0. El equivalente bit de cualquier otro número es 1. Cambio del formato de visualización de las fechas

El parámetro style de convert proporciona una gran variedad de formatos de visualización de fechas al convertir datos datetime o smalldatetime a char o varchar . El argumento de número proporcionado como parámetro style determina el modo en que se muestran los datos. El año puede presentarse en dos o cuatro dígitos. Para obtener un año de 4 dígitos, incluido el siglo (yyyy), añada 100 a un valor style .

A continuación se muestra una tabla con los posibles valores de style y la variedad de formatos de fecha que puede utilizarse. Cuando utilice style con smalldatetime , los estilos que incluyen segundos o milisegundos mostrarán ceros en dichas posiciones.

Tabla 10-11: Conversión de formatos de fecha con el parámetro style

Sin siglo (yy) Con siglo (yyy0) Norma

Salida

- 0 o 100 Valor predeterminado mon dd yyyy hh:mm AM (o PM)

1 101 EE.UU. mm/dd/yy

2 2 Norma SQL yy.mm.dd

3 103 Inglés/francés dd/mm/yy

4 104 Alemán dd.mm.yy

5 105 dd-mm-yy

6 106 dd mon yy

7 107 mon dd, yy

8 108 hh:mm:ss

- 9 o 109 Valor predeterminado + milisegundos mon dd yyyy hh:mm:sss AM (o PM)

10 110 EE.UU. mm-dd-yy

11 111 Japón yy/mm/dd

12 112 ISO yymmdd

Los valores predeterminados, estilo 0 o 100, y 9 o 109, siempre devuelven el siglo (yyyy).

A continuación se muestra un ejemplo del uso del parámetro style de convert :

Page 175: 80575032 Libro de SQL y Tl SQL Excelente

Page 175 of 280

select convert(char(12), getdate(), 3)

Esto convierte la fecha actual al estilo ''3'', dd/mm/yy .

Chapter 11

Creación de índices en tablas

Es posible crear uno o más índices en una tabla a fin de acelerar el proceso de recuperación de datos. Los índices son transparentes para los usuarios que acceden a los datos de esa tabla; SQL Server decide automáticamente cuándo usar los índices creados para las tablas.

En este capítulo se trata lo siguiente:

Introducción general a los índices y algunas indicaciones sobre cuándo deben usarse

Creación de índices para una tabla

Uso de índices agrupados y no agrupados

Especificación de opciones de índices

Omisión de índices

Determinación de los índices que existen en una tabla

Definición de índice

Los índices ayudan a SQL Server a localizar datos. Aceleran el proceso de recuperación de información indicando a SQL Server la posición que ocupan los datos de una columna de tabla en el disco. Las tablas pueden tener más de un índice.

Los índices son transparentes para los usuarios. SQL no incluye ninguna sintaxis para hacer referencia a un índice en una consulta. Sólo es posible crear u omitir índices de una tabla; SQL Server decide si usarlos o no para cada una de las consultas ejecutadas para esa tabla. A medida que los datos de una tabla van cambiando con el tiempo, SQL Server puede cambiar los índices de la tabla de modo que reflejen esas modificaciones. También estos cambios son transparentes para los usuarios, SQL Server lleva a cabo esta tarea por su cuenta.

SQL Server admite los siguientes tipos de índices:

Indices compuestos : estos índices abarcan más de una columna. Este tipo de índice se usa cuando es más conveniente buscar dos o más columnas como unidad, debido a la relación lógica existente entre ellas.

Indices únicos : estos índices no permiten que dos filas de las columnas especificadas tengan el mismo valor. SQL Server verifica si existen valores duplicados cuando se crea el índice (si ya existen datos) y cada vez que se añaden datos.

Indices agrupados o no agrupados : los índices agrupados obligan a SQL Server a que ordene y vuelva a ordenar continuamente las filas de la tabla de modo que su orden físico sea siempre el mismo que el orden lógico (o indexado). Sólo se permite un índice agrupado por tabla. Los índices no agrupados no requieren que el orden físico de las filas sea el mismo que el orden indexado. Todos los índices no agrupados pueden proporcionar acceso a los datos con un criterio de ordenación diferente.

Estos tipos de índices se describen con mayor detalle más adelante en este capítulo.

Comparación de las dos formas de creación de índices

Es posible crear índices en las tablas usando la instrucción create index (descrita en este capítulo), o bien usando las restricciones de integridad unique o primary key del comando create table . Sin embargo, estas restricciones de integridad están limitadas de las siguientes formas:

No podrá crear índices no únicos.

No podrá usar las opciones proporcionadas por el comando create index para adaptar el funcionamiento de los índices.

Sólo podrá omitir estos índices como una restricción usando la instrucción alter table .

Si la aplicación que usa requiere estas funciones, deberá crear los índices mediante create index . De lo contrario, las restricciones de integridad unique o primary key ofrecen una forma más sencilla de definir un índice para una tabla. Para

Page 176: 80575032 Libro de SQL y Tl SQL Excelente

Page 176 of 280

obtener información sobre las restricciones unique y primary key , consulte el Capítulo 7, "Creación de bases de datos y tablas".

Indicaciones para el uso de índices

Los índices aceleran la recuperación de datos. La inclusión de un índice en una columna supone con frecuencia la diferencia entre una respuesta inmediata a una consulta y una larga espera.

Si esto es así, sería lógico suponer que lo adecuado es incluir un índice en cada columna. La razón más importante por la que esto no es así, es que la construcción de un índice lleva tiempo y ocupa espacio de almacenamiento.

Por ejemplo, tenga en cuenta que los índices no agrupados se vuelven a crear de forma automática cuando un índice agrupado se reconstruye.

Otra razón es que la inserción, eliminación o actualización de datos de columnas indexadas lleva más tiempo que el precisado por las no indexadas. Sin embargo, este coste se ve compensado con creces gracias a la enorme mejora que supone el uso de índices para el rendimiento de los procesos de recuperación.

A continuación se indican algunas directrices sobre cuándo utilizar índices:

Si planea realizar inserciones manuales en la columna IDENTITY, cree un índice único a fin de garantizar que las inserciones no asignen un valor que ya se haya usado.

Una columna a la que se acceda con frecuencia según criterios de ordenación, es decir, una especificada en la cláusula order by , probablemente debería indexarse a fin de que SQL Server pudiera beneficiarse del orden indexado.

Las columnas que se usan de forma regular en combinaciones siempre deberían indexarse, dado que el sistema puede llevar a cabo la combinación con mayor rapidez si las columnas están ordenadas según criterios de ordenación.

La columna que almacena la clave primaria de la tabla tiene con frecuencia un índice agrupado, especialmente si se combina a menudo con columnas de otras tablas (no olvide que sólo hay un índice agrupado por tabla).

Una columna en la que se realizan búsquedas frecuentes de márgenes de valores puede ser una opción adecuada para la asignación de un índice agrupado. Una vez encontrada la fila con el primer valor del margen, se garantiza que las filas con los valores subsiguientes serán físicamente adyacentes. Un índice agrupado no ofrece ventajas tan importantes para las búsquedas sobre valores únicos.

Existen algunos casos en los que los índices no son útiles:

Las columnas a las que casi nunca o nunca se hace referencia en las consultas no obtienen ninguna ventaja de los índices, puesto que el sistema casi nunca o nunca tiene que buscar filas basándose en los valores de dichas columnas.

Las columnas que sólo tienen dos o tres valores, como varón y mujer, o sí y no, tampoco se benefician de los índices.

Si el sistema tiene que buscar en una columna no indexada, lo hace examinando las filas una a una. El tiempo que se tarda en llevar a cabo este tipo de barrido es directamente proporcional al número de filas de la tabla.

Creación de índices para acelerar la recuperación de datos

Los índices se crean en las columnas para acelerar la recuperación de datos. El formato más sencillo del comando create index es:

create index index_name

on table_name ( column_name )

Para crear un índice en la columna au_id de la tabla authors , el comando es el siguiente:

create index au_id_ind

on authors(au_id)

El nombre del índice debe cumplir con las reglas para identificadores. Los nombres de columna y tabla especifican la columna que se desea indexar y la tabla que la contiene.

No es posible crear índices en columnas que tienen los tipos de datos bit , text o image .

Page 177: 80575032 Libro de SQL y Tl SQL Excelente

Page 177 of 280

Es necesario ser el propietario de una tabla para poder ejecutar create o drop a fin de crear u omitir un índice. El propietario de una tabla puede crear u omitir un índice en cualquier momento, independientemente de que haya datos en la tabla. Es posible crear índices en tablas de otra base de datos calificando el nombre de la tabla.

Sintaxis de create index

La sintaxis completa del comando create index es:

create [unique] [clustered | nonclustered]

index index_name

on [[ database .] owner .] table_name ( column_name

[, column_name ]...)

[with {{fillfactor | max_rows_per_page}= x,

ignore_dup_key, sorted_data,

[ignore_dup_row | allow_dup_row]}]

[on segment_name ]

En los siguientes apartados se explican las diversas opciones del comando create index .

Note: La extensión on segment_name de create index permite colocar el índice en un segmento que apunte a un dispositivo de bases de datos específico o a un conjunto de dispositivos de bases de datos. Antes de crear un índice en un segmento, consulte al administrador del sistema o al propietario de la base de datos a fin de obtener una lista de los segmentos que puede utilizar. Algunos segmentos pueden estar asignados a tablas o índices específicos por razones de rendimiento, o por otras consideraciones.

Indexación de más de una columna: índices compuestos

Es necesario especificar uno o más nombres de columna si se desea crear un índice compuesto sobre los valores combinados de todas las columnas especificadas.

Los índices compuestos se usan cuando es conveniente buscar dos o más columnas como una unidad. Por ejemplo, la tabla friends_etc tiene un índice compuesto en pname y sname . Ponga todas las columnas que deben incluirse en el índice compuesto según los criterios de ordenación dentro del paréntesis después del nombre de la tabla, como a continuación:

create index nmind

on friends_etc(pname, sname)

Las columnas de un índice compuesto no tienen que estar en el mismo orden que las columnas de la instrucción create table . El orden de pname y sname se puede invertir en la instrucción de creación de índices anterior.

Es posible combinar hasta 16 columnas en un mismo índice compuesto. Todas las columnas de un índice compuesto deben estar en la misma tabla. El tamaño máximo permitido de los valores de índice combinados es de 256 bytes. Es decir, la suma de las longitudes de las columnas que componen el índice compuesto no puede exceder de 256.

Es posible especificar dos o más nombres de columna al crear un índice. Estas columnas, junto con la columna sensitivity , forman un índice compuesto de los valores combinados de las columnas. Los índices compuestos se emplean cuando es conveniente buscar dos o más columnas como una unidad. Por ejemplo, la tabla friends_etc tiene un índice compuesto en pname , sname y sensitivity (añadida de forma automática por SQL Server). Cuando especifique las columnas en la instrucción create index , ponga todas las columnas que deben incluirse en el índice compuesto, salvo sensitivity , entre paréntesis según los criterios de ordenación después del nombre de la tabla, como a continuación:

create index nmind

on friends_etc(pname, sname)

Las columnas de un índice compuesto no tienen que estar en el mismo orden que las columnas de la instrucción create table . El orden de pname y sname podría invertirse en la instrucción de creación de índices anterior. SQL Server siempre añade sensitivity como la última columna de cada índice.

Uso de la opción unique

Un índice único es aquél en el que no se permite que dos filas tengan el mismo valor de índice, incluido el valor NULL. El sistema verifica la existencia de valores duplicados cuando el índice se crea, si ya existen datos, y realiza esta verificación cada vez que se añaden o modifican datos con una instrucción insert o update .

Page 178: 80575032 Libro de SQL y Tl SQL Excelente

Page 178 of 280

La especificación de un índice único sólo es útil cuando la unicidad es una característica de los datos propiamente dichos. Por ejemplo, no es conveniente asignar un índice único a una columna last_name (de apellidos), puesto que es probable que haya más de un "Smith" o "Wong" en tablas incluso de algunos centenares de filas.

Sin embargo, sí es adecuado asignar un índice único a la columna que contiene los números de la seguridad social. En este caso, la unicidad es una característica propia de los datos, puesto que cada persona tiene un número de seguridad social diferente. Además, un índice único puede hacer las veces de una verificación de integridad. Por ejemplo, la existencia de un número de seguridad social duplicado refleja con toda probabilidad un error en la introducción de los datos o por parte de la administración pública.

Si intenta crear un índice único en datos existentes que incluyen valores duplicados, el comando se aborta y SQL Server muestra un mensaje de error que indica el primer duplicado. No es posible crear un índice único en una columna que contiene valores nulos en más de una fila; éstos se consideran valores duplicados para fines de indexación.

Si intenta modificar datos que tienen asignado un índice único, el resultado depende de si ha usado la opción ignore_dup_key . Consulte la sección dedicada a las opciones de índices más adelante en este capítulo.

Es posible usar la palabra clave unique en índices compuestos. Esto no se ha llevado a cabo para el índice friends_etc creado anteriormente.

Inclusión de columnas IDENTITY en índices no únicos

La opción identity in nonunique index incluye de forma automática una columna IDENTITY en las claves de índice de una tabla para que todos los índices creados en la tabla sean únicos. Esta opción de base de datos hace que los índices lógicamente no únicos sean únicos internamente y permite usarlos para procesar cursores actualizables y lecturas de nivel de aislamiento 0.

La tabla ya debe contener una columna IDENTITY para que la opción de base de datos identity in nonunique index funcione, ya sea por una instrucción create table o al definir la opción de base de datos auto identity como true antes de crear la tabla.

Use identity in nonunique index si planea utilizar cursores y lecturas de nivel de aislamiento 0 en tablas con índices no únicos. El índice único hace que el cursor se coloque en la fila correcta la siguiente vez que se efectúa una operación fetch con dicho cursor.

Uso de las opciones fillfactor y max_rows_per_page

Casi nunca es necesario incluir las opciones fillfactor o max_rows_per_page en la instrucción create index . Estas opciones se proporcionan para mejorar el rendimiento y sólo son útiles cuando se crea un nuevo índice sobre datos existentes.

fillfactor

Con la opción fillfactor , el usuario puede especificar en qué medida debe llenar SQL Server cada página de índice. La cantidad de espacio libre en una página de índice se debe controlar porque cuando una página de índice se llena una vez que se han añadido suficientes filas, el sistema debe emplear algún tiempo en dividirla a fin de dejar espacio para nuevas filas.

El valor predeterminado es 0, que es el valor que se usa cuando no se especifica ningún factor de llenado. El administrador del sistema puede cambiar el valor predeterminado con el procedimiento del sistema sp_configure . Consulte la Guía de Administración del Sistema para obtener más información sobre fillfactor .

Los valores válidos de fillfactor especificados por el usuario están entre 1 y 100.

A continuación se muestra una instrucción create index que usa la opción fillfactor :

create index postalcode_ind

on friends_etc(postalcode)

with fillfactor = 100

Un valor fillfactor de 100 llena completamente todas las páginas y sólo es útil cuando se sabe de antemano que nunca va a cambiar ninguno de los valores de índice de la tabla.

max_rows_per_page

Page 179: 80575032 Libro de SQL y Tl SQL Excelente

Page 179 of 280

La opción max_rows_per_page limita el número de filas que SQL Server puede incluir en cada página de índice. Un valor max_rows_per_page bajo reduce la contienda de bloqueo y sólo resulta útil para las tablas a las que se accede con frecuencia. Los valores bajos también hacen que el índice ocupe espacio.

El valor predeterminado es 0, que se emplea cuando no se especifica un valor máximo. El usuario puede cambiar el valor con el procedimiento del sistema sp_relimit .

Los valores max_rows_per_page especificados por el usuario están entre 1 y 256.

La siguientes instrucción create index utiliza la opción max_rows_per_page :

create index postalcode_ind

on friends_etc(postalcode)

with max_rows_per_page = 10

Uso de índices agrupados o no agrupados

Con un índice agrupado, SQL Server ordena las filas de forma continuada de modo que su orden físico sea el mismo que el orden lógico, es decir, el indexado. El nivel inferior o de hoja de un índice agrupado contiene las páginas de datos reales de la tabla. Los índices agrupados deben crearse antes que los no agrupados, ya que estos últimos se reconstruyen automáticamente cuando se crea un índice agrupado.

Por definición, sólo puede haber un índice agrupado por tabla. Este se crea a menudo en la clave primaria , es decir, la columna o columnas que identifican la fila de forma única.

Lógicamente, una clave primaria viene determinada por el diseño de la base de datos. Sin embargo, es posible definir de forma explícita las claves primarias, las claves externas y las claves comunes (pares de claves que se combinan con frecuencia) con los procedimientos del sistema sp_primarykey , sp_foreignkey y sp_commonkey . Puede mostrar información sobre las claves y sobre las columnas que son probables candidatos de combinación mediante sp_helpkey y sp_helpjoins , respectivamente.

Como alternativa, es posible especificar restricciones primary key con las instrucciones create table o alter table a fin de crear un índice e imponer los atributos de clave primaria para las columnas de la tabla. Para mostrar información sobre las restricciones, utilice sp_helpconstraint .

Para obtener una definición de las claves primarias y externas, consulte el Capítulo 15, "Disparadores: imposición de la integridad de referencia". Para obtener información completa sobre los procedimientos del sistema, consulte el Manual de Referencia de SQL Server.

Con un índice no agrupado, el orden físico de las filas no es el mismo que el indexado. El nivel de hoja de un índice no agrupado contiene punteros hacia las filas de las páginas de datos. Más concretamente, cada página hoja contiene un valor indexado y un puntero hacia la fila que contiene dicho valor. En otras palabras, un índice no agrupado tiene un nivel adicional entre la estructura de índice y los datos propiamente dichos.

Cada uno de los hasta 249 índices no agrupados permitidos en una tabla puede proporcionar acceso a los datos según un criterio de ordenación distinto.

La búsqueda de datos mediante un índice agrupado es casi siempre más rápido que mediante un índice no agrupado. Además, los índices agrupados suponen una ventaja cuando se recuperan muchas filas con valores clave contiguos, es decir, en las columnas donde se efectúan búsquedas frecuentes de márgenes de valores. Una vez que se encuentra la fila con el primer valor clave , se garantiza que las filas con valores indexados subsiguientes serán físicamente adyacentes, y no será necesaria ninguna búsqueda adicional.

Si no se usa la palabra clave clustered ni la palabra clave nonclustered , se crea un índice no agrupado.

A continuación se muestra la forma de crear el índice de la columna title_id de la tabla titles (si desea ejecutar este comando, primero debe omitir el índice con drop index ):

create clustered index titleidind

on titles(title_id)

Puesto que piensa que será necesario ordenar con frecuencia las personas de la tabla friends_etc según su código postal, debería crear un índice no agrupado en la columna postalcode de la siguiente manera:

Page 180: 80575032 Libro de SQL y Tl SQL Excelente

Page 180 of 280

create nonclustered index postalcodeind

on friends_etc(postalcode)

Un índice único no tendría ningún sentido en este caso, puesto que es probable que algunos de sus contactos tengan el mismo código postal. Un índice agrupado no sería adecuado tampoco, puesto que el código postal no es la clave primaria.

El índice agrupado de friends_etc debería ser un índice compuesto sobre las columnas de nombre y apellidos. Para crear este índice agrupado, primero omita el índice no agrupado nmind :

drop index friends_etc.nmind

Y luego cree el índice agrupado:

create clustered index nmind

on friends_etc(pname, sname)

Note: Dado que el nivel inferior (o de hoja) de un índice agrupado y sus páginas de datos son iguales por definición, la creación de un índice agrupado ( clustered ) y el uso de la extensión on segment_name traslada efectivamente la tabla desde el dispositivo donde se creó hasta el segmento indicado.

Consulte al administrador del sistema o al propietario de la base de datos antes de crear tablas o índices en los segmentos; algunos segmentos pueden estar reservados por razones de rendimiento.

Especificación de opciones de índices

Las opciones de índices ignore_dup_key, ignore_dup_row y allow_dup_row controlan lo que ocurre cuando se crea una clave o fila duplicada con insert o update . A continuación se muestra una tabla que indica cuándo se deben usar estas opciones de índices:

Tabla 11-1: Opciones de índices

Tipo de índice Opciones

Agrupado ignore_dup_row | allow_dup_row

Agrupado único ignore_dup_key

No agrupado Ninguna

No agrupado único ignore_dup_key

No agrupado único ignore_dup_row

Uso de la opción ignore_dup_key

Si intenta insertar un valor duplicado en una columna que tiene un índice único, el comando se cancela. Es posible evitar que se cancele una transacción grande incluyendo la opción ignore_dup_key con un índice unique .

El índice unique puede ser agrupado o no agrupado. Cuando se comienza la introducción de datos, cada intento de inserción de una clave duplicada se cancela, con un mensaje de error. Las claves no duplicadas se insertan de la forma habitual.

Note: Si intenta ejecutar una instrucción update que crea una clave duplicada, la actualización se cancela. Tras la cancelación, todas las transacciones que estaban activas en ese momento pueden continuar como si la actualización con update no hubiese tenido lugar.

No se puede crear un índice único en una columna que ya incluye valores duplicados, independientemente de que ignore_dup_key esté definida. Si lo intenta, SQL Server imprime un mensaje de error y una lista de valores duplicados. Hay que eliminar los duplicados antes de crear un índice único en la columna.

A continuación se muestra un ejemplo del uso de la opción ignore_dup_key :

create unique clustered index phone_ind

on friends_etc(phone)

with ignore_dup_key

Uso de las opciones ignore_dup_row y allow_dup_row

Page 181: 80575032 Libro de SQL y Tl SQL Excelente

Page 181 of 280

ignore_dup_row y allow_dup_row son opciones para la creación de un índice agrupado y no único. Estas opciones no son relevantes al crear un índice no agrupado y no único. Puesto que un índice no agrupado de SQL Server anexa internamente un número de identificación de fila único, no es necesario preocuparse por las filas duplicadas, ni siquiera por los valores de datos idénticos.

ignore_dup_row y allow_dup_row se excluyen mutuamente.

Si se define allow_dup_row , es posible crear un índice nuevo no único y agrupado en una tabla que incluye filas duplicadas y, a continuación, crear filas duplicadas subsiguientes con insert o update .

Si alguno de los índices de la tabla es único, el requisito de unicidad, que es el requisito más restrictivo, prevalece sobre la opción allow_dup_row . Por tanto, allow_dup_row sólo se aplica a tablas con índices no únicos. No puede usar esta palabra clave si hay un índice agrupado único en alguna de las columnas de la tabla.

La opción ignore_dup_row se utiliza para eliminar los duplicados de un lote de datos. Cuando se introduce una fila duplicada, esta fila se ignora y el comando insert en cuestión se cancela, con un mensaje de error informativo. Las filas no duplicadas se insertan de la forma habitual.

La opción ignore_dup_row se aplica sólo a las tablas con índices no únicos: no puede usar esta palabra clave si hay un índice único en alguna de las columnas de la tabla.

Note: Si intenta ejecutar una instrucción update que cree una fila duplicada, la actualización se cancelará. Tras la cancelación, las transacciones que estaban activas en ese momento pueden continuar como si la actualización no hubiese tenido lugar.

Esta tabla ilustra la forma en que allow_dup_row y ignore_dup_row afectan a los intentos de creación de un índice agrupado no único en una tabla que incluye filas duplicadas y a los intentos de introducción de filas duplicadas en una tabla.

Tabla 11-2: Opciones de filas duplicadas en índices

Opción Duplicados existentes Introducción de duplicados

Ninguna opción definida El comando create index no se ejecuta de forma correcta.

El comando de introducción de filas duplicadas no se ejecuta de forma correcta.

allow_dup_row definida El comando se ejecuta de forma correcta.

El comando se ejecuta de forma correcta.

ignore_dup_row<Default Para Font> definida

Se crea el índice, pero las filas duplicadas se eliminan; mensaje de error.

Se aceptan todas las filas, excepto las duplicadas; mensaje de error. Consulte la advertencia anterior.

Uso de la opción sorted_data

La opción sorted_data acelera la creación de un índice cuando los datos de la tabla ya están clasificados según criterios de ordenación, por ejemplo, cuando se ha usado bcp para copiar datos que ya se han ordenado en una tabla vacía. La velocidad aumenta de forma considerable en las tablas de gran tamaño y es varias veces superior en las tablas de más de un gigabyte. Esta opción puede utilizarse con cualquier otra opción create index sin ningún efecto sobre su funcionamiento.

Si se especifica sorted_data , pero los datos no están ordenados, aparece un mensaje de error y el comando se aborta.

Esta opción agiliza la creación de índices sólo para índices agrupados o índices no agrupados únicos. Sin embargo, la creación de un índice no agrupado y no único tendrá éxito siempre que no haya filas con claves duplicadas. Si existen filas con claves duplicadas, aparece un mensaje de error y el comando se aborta.

Uso de la opción on segment_name

La cláusula on segment_name permite especificar el nombre del segmento de base de datos donde debe crearse el índice. Es posible crear un índice no agrupado en un segmento distinto del de las páginas de datos. Por ejemplo:

create index titleind

on titles(title)

on seg1

Omisión de índices

Page 182: 80575032 Libro de SQL y Tl SQL Excelente

Page 182 of 280

El comando drop index se usa para quitar un índice de la base de datos. Su sintaxis es:

drop index table_name . index_name

[, table_name . index_name ]...

Cuando se ejecuta este comando, SQL Server quita los índices especificados de la base de datos, dejando libre el espacio de almacenamiento.

Sólo el propietario del índice puede omitirlo. El permiso drop index no puede transferirse a otros usuarios. El comando drop index no puede usarse en ninguna de las tablas del sistema de la base de datos master ni en la base de datos de usuario.

Es posible que quiera omitir un índice si no se usa en la mayoría de las consultas o en ninguna.

Para omitir el índice phone_ind de la tabla friends_etc , el comando es:

drop index friends_etc.phone_ind

Determinación de los índices que existen en una tabla

Para ver los índices que existen en una tabla, es posible usar el procedimiento del sistema sp_helpindex . A continuación se muestra un informe sobre la tabla friends_etc :

sp_helpindex friends_etc

index_name index_description index_keys

-------------- ---------------------------- -------------

nmind clustered located on default pname, sname

postalcode_ind nonclustered located on default postalcode

postalcodeind nonclustered located on default postalcode

(3 rows affected, return status = 0)

sp_help también informa sobre los índices de una tabla.

Actualización de estadísticas sobre los índices

El comando update statistics ayuda a SQL Server a tomar las mejores decisiones sobre qué índices debe usar cuando procesa una consulta, proporcionándole información actualizada sobre la distribución de los valores clave de los índices. Este comando debe utilizarse cuando se han añadido, modificado o eliminado grandes cantidades de datos de una columna indexada.

El permiso para ejecutar el comando update statistics está asignado de forma predeterminada al propietario de la tabla, y no es transferible. Su sintaxis es:

update statistics table_name [ index_name ]

Si no se especifica un nombre de índice, el comando actualiza las estadísticas de distribución de todos los índices de la tabla indicada. Si se especifica el nombre de un índice, sólo se actualizan las estadísticas de ese índice.

Se pueden buscar los nombres de los índices con el procedimiento del sistema sp_helpindex . Este procedimiento toma como parámetro un nombre de tabla.

A continuación se muestra cómo enumerar los índices de la tabla authors :

sp_helpindex authors

index_name index_description index_keys

---------- ----------------- ------------------

auidind clustered, unique au_id

aunmind nonclustered au_lname, au_fname

(2 rows affected)

Page 183: 80575032 Libro de SQL y Tl SQL Excelente

Page 183 of 280

Para actualizar las estadísticas de todos los índices, escriba:

update statistics authors

Para actualizar las estadísticas sólo del índice de la columna au_id , escriba:

update statistics authors auidind

Dado que Transact-SQL no requiere que los nombres de índice sean únicos en una base de datos, se debe indicar el nombre de la tabla a la que está asociado el índice. SQL Server ejecuta update statistics de forma automática cuando se crea un índice en los datos existentes.

Chapter 12

Definición de valores predeterminados y reglas para datos

Es posible definir un valor predeterminado para una columna de tabla o un tipo de datos definido por el usuario que inserte un valor automáticamente si no se introduce explícitamente un valor para dicha columna o tipo de datos. También es posible definir reglas para esa columna de tabla o tipo de datos a fin de restringir los tipos de valores que pueden insertarse en ellos.

En este capítulo se trata lo siguiente:

Introducción general a los valores predeterminados y las reglas

Creación y omisión de valores predeterminados

Efecto de los valores predeterminados sobre los valores nulos

Creación y omisión de reglas

Obtención de información sobre valores predeterminados y reglas

Definición de valor predeterminado y de regla

Creación de valores predeterminados

Omisión de valores predeterminados

Efecto de los valores predeterminados sobre los valores nulos

Creación de reglas

Omisión de reglas

Obtención de información sobre valores predeterminados y reglas

Definición de valor predeterminado y de regla

Un valor predeterminado es un valor que SQL Server inserta en una columna cuando el usuario no introduce uno explícitamente. En el campo de la administración de bases de datos, una regla especifica lo que está o no está permitido introducir en una columna concreta o en las columnas con un tipo de datos definido por el usuario. Los valores predeterminados y las reglas pueden usarse para mantener la integridad de los datos en toda la base de datos.

En un sistema de administración de bases de datos relacionales, todos los elementos de datos, es decir, cada columna determinada de cada fila concreta, deben contener algún valor, incluso aunque éste sea NULL (nulo). Tal como se describe en el Capítulo 7, "Creación de bases de datos y tablas", algunas columnas no aceptan el valor nulo. En estos casos, es necesario insertar otro valor, ya sea un valor introducido por el usuario de forma explícita o un valor predeterminado introducido por SQL Server.

Los valores predeterminados permiten especificar un valor que SQL Server deberá insertar en caso de que no se introduzca ningún valor explícito en una columna NULL o NOT NULL. Por ejemplo, puede crear un valor predeterminado que tenga el valor "???" o el valor "fill in later" ("llenar más tarde").

Las reglas imponen la integridad de los datos mediante sistemas cubiertos no sólo por el tipo de datos de una columna. Las reglas se pueden conectar a una columna específica, a varias columnas específicas o a un tipo de datos definido por el usuario concreto.

Cada vez que un usuario introduce un valor con una instrucción insert o update , SQL Server lo compara con la última regla vinculada a la columna en cuestión. Los datos introducidos antes de la creación y vinculación de una regla no se verifican.

Page 184: 80575032 Libro de SQL y Tl SQL Excelente

Page 184 of 280

Note: Es posible vincular una regla de tipo de caracteres a una columna de tipo numérico, aunque no tenga ningún sentido hacerlo. Las reglas se contrastan cuando se intenta ejecutar una instrucción insert o update , no en el momento de vincularlas.

En este capítulo se explica cómo crear valores predeterminados y reglas mediante create default y create rule , y cómo asociar valores predeterminados y reglas a una columna o a un tipo de datos definido por el usuario mediante los procedimientos del sistema sp_bindefault , sp_bindrule , sp_unbindefault y sp_unbindrule .

Comparación de valores predeterminados y reglas con restricciones de integridad

Como alternativa al uso de valores predeterminados y reglas, es posible usar la cláusula default y la restricción de integridad check de la instrucción create table para llevar a cabo algunas de las mismas tareas. Sin embargo, dichos elementos son específicos a esa tabla y no pueden vincularse a columnas de otras tablas ni a tipos de datos definidos por el usuario. Para obtener más información acerca de las restricciones de integridad, consulte el Capítulo 7, "Creación de bases de datos y tablas".

Creación de valores predeterminados

Es posible crear y omitir valores predeterminados en cualquier momento, antes o después de haber introducido los datos en una tabla. Cree un valor predeterminado con el comando create default y omítalo con el comando drop default .

Un valor predeterminado puede conectarse a una columna en particular, a varias columnas o a todas las columnas de la base de datos que tengan un tipo de datos definido por el usuario determinado. Utilice el procedimiento del sistema sp_bindefault para asociar un valor predeterminado a una columna o tipo de datos definido por el usuario. Quite la asociación mediante sp_unbindefault .

A continuación se muestran algunos puntos que hay que comprobar al crear y vincular valores predeterminados:

Cerciórese de que el tamaño de la columna es suficiente para el valor predeterminado. Una columna char (2) no puede contener una cadena de caracteres de 17 bytes como "Nobody knows yet".

Tenga cuidado cuando introduzca valores predeterminados distintos en un tipo de datos definido por el usuario y en una columna individual de dicho tipo. Si vincula primero el valor predeterminado del tipo de datos y luego el de la columna, este último sustituye al valor predeterminado del tipo de datos definido por el usuario únicamente para la columna indicada. El valor predeterminado del tipo de datos definido por el usuario se vincula a todas las demás columnas que tengan ese tipo de datos. Sin embargo, una vez vinculado otro valor predeterminado a una columna que tenía un valor predeterminado asociado a su tipo, la columna deja de estar bajo la influencia de los valores predeterminados vinculados a su tipo de datos. Este tema se trata con mayor detalle más adelante en este capítulo.

Esté atento a los conflictos que puedan producirse entre los valores predeterminados y las reglas. Cerciórese de que la regla permite el valor predeterminado, ya que, de lo contrario, la regla podría eliminarlo.

Si una regla permite entradas entre 1 y 100, por ejemplo, y el valor predeterminado está definido en 0, la regla hará que el valor predeterminado se rechace cada vez que se intente insertar y el resultado será un error, a no ser que la columna acepte valores NULL, en cuyo caso se introducirá NULL. Será necesario cambiar el valor predeterminado o la regla.

Sintaxis de create default

La sintaxis del comando create default es:

create default [ owner .] default_name

as constant_expression

Los valores predeterminados deben cumplir las reglas para identificadores. Sólo es posible crear valores predeterminados en la base de datos actual.

Dentro de una base de datos, los nombres de los valores predeterminados deben ser únicos para cada usuario. No puede crear dos valores predeterminados con el nombre phonedflt . Sin embargo, como usuario "invitado", puede crear un valor predeterminado phonedflt aunque dbo. phonedflt ya exista porque los nombres de los propietarios los diferencian entre sí.

A continuación se indica cómo crear el valor predeterminado "Oakland" para usarlo con la columna city de la tabla friends_etc (la tabla cuya creación se trató en el Capítulo 7, "Creación de bases de datos y tablas") y posiblemente con otras columnas o tipos de datos de usuario. Mientras sigue este ejemplo, puede usar cualquier nombre de ciudad que resulte útil para la distribución demográfica de las personas que tenga previsto introducir en su tabla personal. Para crear el valor predeterminado:

Page 185: 80575032 Libro de SQL y Tl SQL Excelente

Page 185 of 280

create default citydflt as "Oakland"

Después de as puede usar cualquier constante. Las constantes de caracteres y de fecha deben incluirse entre comillas; las constantes de tipo monetario, de números enteros y de punto flotante no las requieren. Los datos binarios deben ir precedidos de 0x y los datos monetarios, de un símbolo de dólar ($). El valor predeterminado tiene que ser compatible con el tipo de datos de la columna. No puede usar "ninguno", por ejemplo, como valor predeterminado para una columna numérica, pero 0 (cero) sí es adecuado.

Si especifica NOT NULL al crear una columna y no asocia un valor predeterminado a esa columna, SQL Server generará un mensaje de error siempre que alguien olvide introducir una entrada en dicha columna.

Con frecuencia, los valores predeterminados se generan al crear la tabla. Sin embargo, en una sesión en la que desee introducir múltiples filas con los mismos valores en una o más columnas, puede ser conveniente crear un valor predeterminado especial para dicha sesión antes de comenzar.

Vinculación de valores predeterminados

Una vez creado un valor predeterminado, utilice el procedimiento del sistema sp_bindefault para vincular el valor a una columna o un tipo de datos definido por el usuario.

create default phonedflt as "UNKNOWN"

Se ha definido un valor predeterminado. Ahora es necesario vincularlo a la columna o tipo de datos definido por el usuario adecuados con el procedimiento del sistema sp_bindefault .

sp_bindefault phonedflt, "authors.phone"

El valor predeterminado tendrá efecto sólo si no hay ninguna entrada en la columna phone de la tabla authors . No introducir ninguna entrada es distinto de insertar un valor nulo.

Note: Para obtener el valor predeterminado, debe ejecutar un comando insert o update con una lista de columnas que no incluya la columna con el valor predeterminado.

El valor predeterminado sólo se aplica a las filas nuevas y no cambia de forma retroactiva las filas existentes. Lógicamente, dicho valor sólo tiene efecto cuando no se realiza ninguna entrada. Si el usuario suministra un valor para la columna, aunque sea NULL, el valor predeterminado no tiene ningún efecto.

A continuación se muestra cómo vincular citydflt a la columna city de friends_etc :

sp_bindefault citydflt, "friends_etc.city"

Observe que el nombre de la tabla y la columna están entre comillas debido a la puntuación incrustada, es decir, el punto.

Note: No es posible vincular un valor predeterminado a un tipo de datos del sistema, porque el objeto de destino sería demasiado extenso. Tampoco se puede vincular un valor predeterminado a una columna timestamp , porque SQL Server genera valores para columnas de este tipo. Es posible vincular un valor predeterminado a la columna IDENTITY o a un tipo de datos definido por el usuario con la propiedad IDENTITY, pero estos valores predeterminados se ignoran. Cada vez que se inserta una fila en una tabla sin especificar un valor para la columna IDENTITY, SQL Server asigna un valor mayor en una unidad que el último valor asignado.

Si crea un tipo de datos especial para todas las columnas de ciudades de todas las tablas de la base de datos, puede vincular citydflt al tipo de datos con la completa seguridad de que "Oakland" aparecerá sólo en los casos en que sea apropiado un nombre de ciudad. Por ejemplo, si el tipo de datos se llama citytype , a continuación se indica cómo se vincularía citydflt al mismo:

sp_bindefault citydflt, citytype

El parámetro futureonly puede usarse cuando se vincula un valor predeterminado a un tipo de datos de usuario. Este parámetro evita que las columnas existentes de ese tipo de datos de usuario hereden el nuevo valor predeterminado. Nunca se utiliza cuando se vincula un valor predeterminado a una columna. A continuación se indica cómo crear y vincular el nuevo valor

Page 186: 80575032 Libro de SQL y Tl SQL Excelente

Page 186 of 280

predeterminado "Berkeley" al tipo de datos citytype para su uso sólo en las columnas de tabla nuevas. "Oakland" seguirá apareciendo como valor predeterminado para todas las columnas de tabla existentes que usen citytype .

create default newcitydflt as "Berkeley"

sp_bindefault newcitydflt, citytype, futureonly

Si la mayor parte de las personas de la tabla viven en la misma zona de código postal, puede crear un valor predeterminado para ahorrar tiempo de introducción de datos. A continuación se indica uno adecuado para una sección de Oakland, junto con su vinculación:

create default zipdflt as "94609"

sp_bindefault zipdflt, "friends_etc.postalcode"

Esta es la sintaxis completa del procedimiento del sistema sp_bindefault :

sp_bindefault defname, objname [, futureonly]

defname es el nombre del valor predeterminado creado con create default . objname es el nombre de la tabla y la columna, o del tipo de datos definido por el usuario, a la que debe vincularse el valor predeterminado. Si el parámetro no tiene el formato table . column , el sistema supone que se trata de un tipo de datos definido por el usuario.

Todas las columnas de un tipo de datos definido por el usuario especificado quedan asociadas al valor predeterminado indicado, a no ser que:

Utilice el tercer parámetro opcional, futureonly , que evita que las columnas existentes de ese tipo de datos de usuario hereden el valor predeterminado; o bien

El valor predeterminado de la columna se haya cambiado previamente, en cuyo caso se mantiene el valor predeterminado original.

Los valores predeterminados vinculados a las columnas siempre tienen precedencia sobre los valores vinculados a los tipos de datos de usuario. Al vincular un valor predeterminado a una columna, se sustituirá el valor predeterminado vinculado al tipo de datos definido por el usuario de dicha columna, pero si se vincula un valor predeterminado a un tipo de datos, no se sustituye el valor predeterminado de una regla de una columna correspondiente al tipo de datos de que se trate definido por el usuario. En la siguiente tabla se indica la precedencia cuando se vinculan valores predeterminados a columnas y tipos de datos definidos por el usuario para los que ya existen valores predeterminados:

Tabla 12-1: Precedencia de valores predeterminados

Valor predeterminado nuevo vinculado a:

Valor predeterminado antiguo vinculado a:

Tipo de datos de usuario Column a

Tipo de datos de usuario Sustituye al valor predeterminado antiguo.

Ningún cambio; valor predeterminado antiguo.

Column a Sustituye al valor predeterminado antiguo.

Sustituye al valor predeterminado antiguo.

Las columnas existentes del tipo de datos definido por el usuario heredan el nuevo valor predeterminado, a no ser que su valor predeterminado se haya cambiado previamente o que el valor del tercer parámetro opcional sea futureonly . Las columnas nuevas del tipo de datos definido por el usuario siempre heredan el valor predeterminado.

Por ejemplo, supongamos que se crea una tabla llamada foes con una columna llamada city del tipo citytype , que es un tipo de datos definido por el usuario. Inicialmente, el tipo de datos definido por el usuario citytype no tiene ningún valor predeterminado. Tras crearse un valor predeterminado llamado citydflt , se vincula a la columna foes.city . Luego se vincula otro valor predeterminado, newcitydflt , al tipo de datos definido por el usuario citytype . Aunque foes.city es una columna citytype , el nuevo valor predeterminado no se vincula a ella, puesto que se ha cambiado previamente.

Note: No es posible vincular valores predeterminados a columnas y usarlos durante el mismo lote. sp_bindefault no puede estar en el mismo lote que las instrucciones insert que ejecutan el valor predeterminado.

Desvinculación de valores predeterminados

Page 187: 80575032 Libro de SQL y Tl SQL Excelente

Page 187 of 280

Desvincular un valor predeterminado significa desconectarlo de una columna o tipo de datos definido por el usuario en particular. Un valor predeterminado desvinculado sigue estando almacenado en la base de datos y está disponible para su uso en el futuro. Utilice el procedimiento del sistema sp_unbindefault para quitar la vinculación entre un valor predeterminado y una columna o tipo de datos.

A continuación se indica cómo desvincular el valor predeterminado actual de la columna city de la tabla friends_etc :

execute sp_unbindefault "friends_etc.city"

Ahora el valor predeterminado aún existe, pero no tiene ningún efecto sobre la columna city porque no está conectado a la misma.

Para desvincular un valor predeterminado del tipo de datos definido por el usuario citytype , ejecute este comando:

sp_unbindefault citytype

La sintaxis completa del procedimiento del sistema sp_unbindefault es:

sp_unbindefault objname [, futureonly]

Si el parámetro objname indicado no tiene el formato table . column , SQL Server supone que se trata de un tipo de datos definido por el usuario. Cuando se desvincula un valor predeterminado de un tipo de datos definido por el usuario, el valor predeterminado se desvincula de todas las columnas de ese tipo, a no ser que:

Indique el segundo parámetro opcional futureonly , que evita que las columnas existentes de ese tipo de datos pierdan su vinculación con el valor predeterminado, o bien

El valor predeterminado de una columna con ese tipo de datos definido por el usuario se haya cambiado y su valor actual sea distinto del valor predeterminado que se está desvinculando.

A continuación se muestra un ejemplo que ilustra el caso anterior:

1. Cree un tipo de datos definido por el usuario llamado nm . 2. Use nm en las instrucciones create correspondientes a las tablas friends_etc y enemies para crear las columnas

friends_etc . pname , friends_etc . sname y enemies . nickname. 3. Cree un valor predeterminado llamado nmdflt y vincúlelo a nm . 4. Cambie el valor predeterminado de enemies.nickname creando un nuevo valor predeterminado llamado nastydflt y

vinculándolo a enemies . nickname . 5. Ahora, si desvincula nmdflt de nm , sólo se verán afectadas friends.pname y friends.sname . Puesto que el valor

predeterminado original de enemies.nickname se ha cambiado, el valor predeterminado de esa columna no se desvincula, aunque esté definido como del tipo nm .

Omisión de valores predeterminados

Si desea quitar un valor predeterminado totalmente de una base de datos, utilice el comando drop default . El valor predeterminado debe desvincularse de todas las columnas y tipos de datos definidos por el usuario antes de poder omitirlo. Si trata de omitir un valor predeterminado que todavía está vinculado, SQL Server muestra un mensaje de error y el comando drop default no se ejecuta correctamente. Sin embargo, no es necesario desvincular y luego omitir un valor predeterminado para poder vincular otro nuevo. Basta con vincular otro valor predeterminado en su lugar.

A continuación se indica cómo quitar citydflt :

drop default citydflt

La sintaxis completa del comando drop default es:

drop default [ owner .] default_name

[, [ owner .] default_name ] ...

Sólo su propietario puede omitir un valor predeterminado.

Efecto de los valores predeterminados sobre los valores nulos

Page 188: 80575032 Libro de SQL y Tl SQL Excelente

Page 188 of 280

Si especifica NOT NULL al crear una columna y no genera un valor predeterminado para la misma, SQL Server muestra un mensaje de error cada vez que alguien inserta una fila y no introduce datos en dicha columna.

Cuando se omite un valor predeterminado de una columna NULL, SQL Server inserta NULL en esa posición cada vez que el usuario añade filas sin introducir ningún valor para esa columna. Cuando se omite un valor predeterminado de una columna NOT NULL, el programa muestra un mensaje de error cada vez que el usuario añade filas y no introduce de forma explícita ningún valor para esa columna.

La siguiente tabla ilustra la relación entre la existencia de un valor predeterminado y la definición de una columna como NULL o NOT NULL. Las entradas de la tabla muestran el resultado:

Tabla 12-2: Valores predeterminados y valores NULL

Definición de columna

Sin entrada Sin valor predeterminado

Sin entrada, Con valor predeterminado

Se introduce null Sin valor predeterminado

Se introduce null Valor predeterminado

NULL Nulo Valor predeterminado Nulo Nulo

NOT NULL Error Valor predeterminado Error Error

Creación de reglas

Las reglas se crean con el comando create rule y luego se vinculan a una columna o tipo de datos definido por el usuario con el procedimiento del sistema sp_bindrule . Es posible desvincular una regla de la columna o tipo de datos usando el procedimiento del sistema sp_unbindrule o vinculando una nueva regla a la columna o tipo de datos.

Sintaxis de create rule

La sintaxis del comando create rule es:

create rule [ owner .] rule_name

as condition_expression

Los nombres de las reglas deben ajustarse a las reglas para identificadores. Sólo es posible crear reglas en la base de datos actual.

Dentro de una base de datos, los nombres de las reglas deben ser únicos para cada usuario. Un usuario no puede crear dos reglas diferentes llamadas socsecrule . Sin embargo, dos usuarios distintos pueden crear una regla llamada socsecrule , porque sus respectivos nombres de usuario las diferencian entre sí.

A continuación se indica cómo crear una regla que permite cinco números pub_id distintos y un valor ficticio (99 seguido de dos dígitos cualesquiera):

create rule pub_idrule

as @pub_id in ("1389", "0736", "0877", "1622", "1756")

or @pub_id like "99[0-9][0-9]"

La cláusula as contiene el nombre del argumento de la regla, con el prefijo "@", y la definición de la regla propiamente dicha. El argumento hace referencia al valor de columna que se ve afectado por la instrucción update o insert .

En el ejemplo anterior, el argumento es @ pub_id , un nombre adecuado puesto que esta regla se va a vincular a la columna pub_id . Puede usar cualquier nombre para el argumento, pero el primer carácter debe ser "@". El uso del nombre de la columna o tipo de datos a que se va a vincular la regla puede ayudar a recordar cuál es su función.

La definición de la regla puede contener cualquier expresión válida en una cláusula where e incluir operadores aritméticos, operadores de comparación, like , in , between , etc.. Sin embargo, la definición de una regla no puede hacer referencia a ninguna columna ni a ningún otro objeto de base de datos directamente. Se pueden incluir funciones incorporadas que no hacen referencia a objetos de base de datos.

El siguiente ejemplo crea una regla que obliga a que los valores introducidos por el usuario sean compatibles con una "imagen" concreta. En este caso, cada valor introducido en la columna deberá comenzar por los dígitos "415", seguidos de siete o más caracteres:

Page 189: 80575032 Libro de SQL y Tl SQL Excelente

Page 189 of 280

create rule phonerule

as @phone like '415_ _ _ _ _ _ _'

Para asegurarse de que las edades introducidas para sus amigos están entre 1 y 120, pero nunca 17, intente con este comando:

create rule agerule

as @age between 1 and 120 and @age !=17

Vinculación de reglas

Una vez creada una regla, use el procedimiento del sistema sp_bindrule para vincular la regla a una columna o un tipo de datos definido por el usuario.

A continuación se muestra la sintaxis completa de sp_bindrule :

sp_bindrule rulename , objname [, futureonly]

rulename es el nombre de la regla creada con create rule . objname es el nombre de la tabla y la columna, o del tipo de datos definido por el usuario, a la que debe vincularse la regla. Si el parámetro no tiene el formato table.column , el sistema supone que se trata de un tipo de datos definido por el usuario.

El tercer parámetro opcional, futureonly , sólo tiene sentido cuando se vincula una regla a un tipo de datos definido por el usuario. Todas las columnas del tipo de datos definido por el usuario indicado quedan asociadas a la regla especificada, a no ser que se especifique futureonly , que evita que las columnas existentes del tipo de datos de usuario hereden la regla. Si la regla asociada a un tipo de datos definido por el usuario determinado se ha cambiado previamente, la regla cambiada se mantiene para las columnas existentes de ese tipo de datos definido por el usuario.

Note: No es posible vincular una regla a una columna del tipo de datos text , image o timestamp .

Vinculación de reglas a columnas

Para vincular una regla a una columna, utilice el procedimiento del sistema sp_bindrule con el nombre de la regla, y el nombre de tabla y de columna entre comillas. A continuación se indica cómo se vincula pub_idrule a publishers.pub_id :

sp_bindrule pub_idrule, "publishers.pub_id"

Como ejemplo adicional, a continuación se indica una regla que garantiza que los tres primeros dígitos de todos los códigos postales sean 946:

create rule postalcoderule946

as @postalcode like "946[0-9][0-9]"

Para vincularla a la columna postalcode de friends_etc , haga lo siguiente:

sp_bindrule postalcoderule946, "friends_etc.postalcode"

No es posible vincular columnas y usarlas durante el mismo lote. sp_bindrule no puede estar en el mismo lote que las instrucciones insert que ejecutan la regla.

Vinculación de reglas a tipos de datos definidos por el usuario

No se puede vincular una regla a un tipo de datos del sistema, pero sí a un tipo de datos definido por el usuario. Para vincular phonerule a un tipo de datos definido por el usuario llamado p# , escriba:

sp_bindrule phonerule, "p#"

Precedencia de las reglas

Las reglas vinculadas a las columnas siempre tienen precedencia sobre las vinculadas a los tipos de datos definidos por el usuario. Al vincular una regla a una columna, se sustituye la regla vinculada al tipo de datos definido por el usuario de esa

Page 190: 80575032 Libro de SQL y Tl SQL Excelente

Page 190 of 280

columna, pero al vincular una regla a un tipo de datos, no se sustituirá la regla vinculada a una columna de ese tipo de datos de usuario.

Una regla vinculada a un tipo de datos definido por el usuario se activa sólo cuando se intenta insertar un valor en una columna de base de datos del tipo de datos definido por el usuario, o actualizar dicha columna. Dado que las reglas no verifican las variables, evite asignar un valor a una variable de un tipo de datos definido por el usuario que pueda ser rechazada por una regla vinculada a una columna del mismo tipo de datos.

La siguiente tabla indica la precedencia cuando se vinculan reglas a columnas y tipos de datos de usuario donde ya existen reglas:

Tabla 12-3: Precedencia de las reglas

Regla nueva vinculada a : Regla antigua vinculada a:

Tipo de datos de usuario Columna

Tipo de datos de usuario Sustituye a la regla antigua. Sin cambios.

Columna Sustituye a la regla antigua. Sustituye a la regla antigua.

Al introducir datos que requieren restricciones temporales especiales en algunas columnas, se puede crear una nueva regla que ayude a verificar los datos. Por ejemplo, supongamos que se añaden datos a la columna debt de la tabla friends_etc . Se sabe que todas las deudas que se desean registrar hoy están entre $5 y $200. Para evitar la introducción accidental de una cantidad fuera de este margen, cree una regla como la siguiente (la definición de regla permite una entrada de $0.00 para mantener el valor predeterminado definido anteriormente para esta columna).

create rule debtrule

as @debt = $0.00 or @debt between $5.00 and $200.00

Vincule debtrule a la columna debt así:

sp_bindrule debtrule, "friends_etc.debt"

Note: Una vez creada y vinculada una regla, verifíquela siempre insertando datos. Muchos errores de creación y vinculación de reglas sólo pueden detectarse si se verifican mediante una instrucción insert o update .

Desvinculación de reglas

Desvincular una regla significa desconectarla de una columna o tipo de datos definido por el usuario en particular. La definición de una regla desvinculada permanece almacenada en la base de datos y queda disponible para su uso en el futuro.

Existen dos formas de desvincular una regla:

Use el procedimiento del sistema sp_unbindrule para quitar la vinculación entre una regla y una columna o tipo de datos definido por el usuario.

Use el procedimiento del sistema sp_bindrule para vincular una nueva regla a esa columna o tipo de datos. El valor antiguo queda desvinculado automáticamente.

A continuación se muestra cómo cancelar la asociación entre debtrule (o cualquier otra regla vinculada) y friends_etc.debt :

sp_unbindrule "friends_etc.debt"

La regla permanece en la base de datos, pero no tiene ninguna conexión con friends_etc.debt .

Para desvincular una regla del tipo de datos definido por el usuario p#, ejecute el siguiente comando:

sp_unbindrule "p#"

La sintaxis completa del procedimiento del sistema sp_unbindrule es:

sp_unbindrule objname [, futureonly]

Page 191: 80575032 Libro de SQL y Tl SQL Excelente

Page 191 of 280

Si el parámetro objname indicado no tiene el formato " table.column " , SQL Server supone que se trata de un tipo de datos definido por el usuario. Cuando se desvincula una regla de un tipo de datos definido por el usuario, la regla se desvincula de todas las columnas de ese tipo, a no ser que:

Indique el segundo parámetro opcional futureonly , que evita que las columnas existentes de ese tipo de datos pierdan su vinculación con la regla; o bien

La regla de una columna de ese tipo de datos definido por el usuario se haya modificado de modo que su valor actual sea distinto de la regla que se está desvinculando.

Omisión de reglas

Si desea quitar una regla de la base de datos completamente, use el comando drop rule . La regla debe desvincularse de todas las columnas y tipos de datos de usuario antes de poder omitirse. Si intenta omitir una regla que aún está vinculada, SQL Server muestra un mensaje de error y el comando drop rule no se ejecuta correctamente. Sin embargo, no es necesario desvincular y luego omitir una regla para poder vincular una nueva. Basta con vincular otra en su lugar.

A continuación se muestra cómo quitar phonerule después de desvincularla:

drop rule phonerule

La sintaxis completa del comando drop rule es:

drop rule [ owner .] rule_name

[, [ owner .] rule_name ] ...

Después de omitir una regla, los datos nuevos que se introduzcan en las columnas anteriormente regidas por ésta se introducirán sin restricciones. Los datos existentes no se verán afectados de ningún modo.

Sólo su propietario puede omitir una regla.

Obtención de información sobre valores predeterminados y reglas

El procedimiento del sistema sp_help , cuando se usa con un nombre de tabla, muestra las reglas y los valores predeterminados vinculados a las columnas. Este ejemplo muestra información sobre la tabla authors de la base de datos pubs , incluidas las reglas y los valores predeterminados:

sp_help authors

El procedimiento del sistema sp_help también informa sobre una regla vinculada a un tipo de datos definido por el usuario. Para verificar si una regla está vinculada al tipo de datos definido por el usuario p # , ejecute este comando:

sp_help "p#"

El procedimiento sp_helptext informa sobre la definición (la instrucción create ) de una regla o valor predeterminado.

Chapter 13

Uso de lotes y lenguaje de control de flujo

Transact-SQL permite agrupar una serie de instrucciones como un lote, ya sea de forma interactiva o desde un archivo del sistema operativo. También se pueden utilizar las estructuras de control de flujo ofrecidas por Transact-SQL para conectar las instrucciones utilizando estructuras de tipo de programación.

En este capítulo se trata lo siguiente:

Una introducción general a los lotes y al lenguaje de control de flujo

Las reglas asociadas con el uso de instrucciones en lotes

Uso del lenguaje de control de flujo

Definición de lote y de lenguaje de control de flujo

Page 192: 80575032 Libro de SQL y Tl SQL Excelente

Page 192 of 280

Reglas asociadas a lotes

Uso del lenguaje de control de flujo

Definición de lote y de lenguaje de control de flujo

Hasta aquí, cada ejemplo de la Guía del Usuario de Transact-SQL consistió de una instrucción individual. Las instrucciones individuales se ejecutan en SQL Server de una en una, introduciendo instrucciones y recibiendo resultados de forma interactiva. SQL Server también puede procesar instrucciones múltiples ejecutadas como un lote, tanto de forma interactiva como desde un archivo.

Un lote de instrucciones SQL se termina mediante una señal de fin de lote que indica a SQL Server que continúe y ejecute las instrucciones. La señal de fin de lote para la utilidad SQL autónoma isql es la palabra "go" sola en una línea. Para obtener más detalles, consulte el manual de programas de utilidad de SQL Server.

Desde el punto de vista técnico, una sola instrucción SQL puede constituir un lote, pero normalmente se piensa en un lote como un conjunto de instrucciones múltiples. Con frecuencia, un lote de instrucciones se escribe en un archivo del sistema operativo antes de enviarse a isql .

Transact-SQL proporciona palabras clave especiales llamadas lenguaje de control de flujo que permiten controlar el flujo de ejecución de las instrucciones. El lenguaje de control de flujo se puede utilizar en instrucciones sencillas, lotes, procedimientos almacenados y disparadores.

Sin el lenguaje de control de flujo, las instrucciones SQL se llevan a cabo de forma secuencial, conforme se producen. Las subconsultas correlacionadas, explicadas en el Capítulo 5, "Subconsultas: uso de consultas dentro de otras consultas", son una excepción parcial. El lenguaje de control de flujo permite que las instrucciones se conecten y se relacionen entre sí utilizando estructuras de tipo de programación.

El lenguaje de control de flujo, como if...else para la ejecución condicional de comandos y while para la ejecución repetitiva, permite refinar y controlar el funcionamiento de las instrucciones SQL. El lenguaje de control de flujo de Transact-SQL transforma el SQL estándar en un lenguaje de programación de muy alto nivel.

Reglas asociadas a lotes

Existen reglas que controlan qué instrucciones SQL pueden combinarse en un solo lote. Estas reglas de lotes incluyen lo siguiente:

Algunos comandos de base de datos no pueden combinarse con otras instrucciones en un lote. Se trata de los siguientes: create procedure create rule create default create trigger create view

Los comandos que sí pueden combinarse con otras instrucciones SQL en un lote incluyen: create database (salvo que no puede crear una base de datos y generar o acceder a los objetos de la base de datos nueva en un solo lote) create table create index

Las reglas y valores predeterminados no pueden vincularse a columnas y utilizarse durante el mismo lote. sp_bindrule y sp_bindefault no pueden estar en el mismo lote que las instrucciones insert que ejecutan la regla o valor predeterminado.

use debe ejecutarse en un lote anterior antes que las instrucciones que hacen referencia a los objetos de dicha base de datos.

No es posible realizar una operación drop con un objeto y después hacer referencia a éste o volver a crearlo en el mismo lote.

Cualquier opción definida con una instrucción set tendrá efecto al final del lote. Es posible combinar instrucciones set y consultas en el mismo lote, pero las opciones de set no se aplicarán a las consultas de dicho lote.

Ejemplos del uso de lotes

Los ejemplos de esta sección describen lotes que utilizan el formato de la utilidad isql , que tiene una clara señal de fin de lote: la palabra "go" sola en una línea. A continuación se muestra un lote que contiene dos instrucciones select en un solo lote:

select count(*) from titles

select count(*) from authors

go

-------------

18

Page 193: 80575032 Libro de SQL y Tl SQL Excelente

Page 193 of 280

(1 row affected)

-------------

23

(1 row affected)

Se puede crear una tabla y hacer referencia a ella en el mismo lote. Este lote crea una tabla, inserta una fila en ella y después selecciona todo lo que contiene:

create table test

(column1 char(10), column2 int)

insert test

values ("hello", 598)

select * from test

go

(1 row affected)

column1 column2

------- -------

hello 598

(1 row affected)

Una instrucción create view debe ser la única instrucción de un lote. Este lote contiene una sola instrucción, que crea una vista:

create view testview as

select column1 from test

go

Se puede combinar una instrucción use con otras instrucciones siempre que los objetos a los que haga referencia en las instrucciones subsiguientes estén en la base de datos donde empezó. Este lote selecciona de una tabla de la base de datos master y después abre la base de datos pubs 2 . El lote supone que se encuentra en la base de datos master del principio. Tras la ejecución del lote, pubs2 es la base de datos actual.

select count(*) from sysdatabases

use pubs2

go

-------------

9

(1 row affected)

Se puede combinar una instrucción drop con otras instrucciones siempre que no haga referencia o vuelva a crear el objeto omitido en el mismo lote. El ejemplo de lote final combina una instrucción drop con otra select :

drop table test

select count(*) from titles

go

------------

18

(1 row affected)

Si hay un error de sintaxis en algún punto del lote, no se ejecutará ninguna de las instrucciones. Por ejemplo, a continuación se muestra un lote con un error de escritura en la última instrucción, y los resultados:

select count(*) from titles

select count(*) from authors

slect count(*) from publishers

go

Msg 156, Level 15, State 1:

SQL Server 'MAGOO', LIne 3:

Sintaxis incorrecta junto a la palabra clave 'count'.

Los lotes que violan una regla del lote también generan mensajes de error. A continuación se muestran algunos ejemplos de lotes ilegales:

Page 194: 80575032 Libro de SQL y Tl SQL Excelente

Page 194 of 280

create table test

(column1 char(10), column2 int)

insert test

values ("hello", 598)

select * from test

create view testview as select column1 from test

go

Msg 111, Level 15, State 3:

Server 'hq', Line 6:

CREATE VIEW debe ser el primer comando en un batch de consulta.

create view testview as select column1 from test

insert testview values ("goodbye")

go

Msg 127, Level 15, State 1:

Server 'hq', Procedure 'testview', Line 3:

Este CREATE puede sólo contener 1 sentencia.

El siguiente lote funcionará si todavía está en la base de datos especificada en la instrucción use . Si lo intenta desde otra base de datos como master , recibirá un mensaje de error.

use pubs2

select * from titles

go

Msg 208, Level 16, State 1:

Server 'hq', Line 2:

Invalid object name 'titles'.

drop table test

create table test

(column1 char(10), column2 int)

go

Msg 2714, Level 16, State 1:

Server 'hq', Line 2:

Ya hay un objeto llamado 'test' en la base de datos.

Lotes enviados como archivos

Se pueden enviar uno o más lotes de instrucciones SQL a isql desde un archivo del sistema operativo. Un archivo puede incluir más de un lote, es decir, más de una serie de instrucciones, cada uno terminado con la palabra "go".

Por ejemplo, un archivo del sistema operativo podría contener los siguientes tres lotes:

use pubs2

go

select count(*) from titles

select count(*) from authors

go

create table test

(column1 char(10), column2 int)

insert test

values ("hello", 598)

select * from test

go

Estos son los resultados de enviar este archivo a la utilidad isql :

-------------

18

(1 row affected)

-------------

23

(1 row affected)

(1 row affected)

column1 column2

--------- ---------

hello 598

(1 row affected)

Page 195: 80575032 Libro de SQL y Tl SQL Excelente

Page 195 of 280

Consulte la sección sobre la utilidad isql del manual de programas de utilidad de SQL Server para obtener información específica del entorno sobre la ejecución de lotes almacenados en archivos.

Uso del lenguaje de control de flujo

El lenguaje de control de flujo se puede utilizar con instrucciones interactivas, en lotes y en procedimientos almacenados. El control de flujo y las palabras clave relacionadas y sus funciones son:

Tabla 13-1: Control de flujo y palabras clave relacionadas

Palabra clave Función

if Define una ejecución condicional.

...else Define una ejecución alternativa cuando la condición if es falsa.

begin Comienzo de un bloque de instrucciones.

...end Final de un bloque de instrucciones.

while Repite la ejecución de instrucciones mientras la condición es verdadera.

break Sale del final del siguiente bucle while más exterior.

...continue Reinicio del bucle while .

declare Declara variables locales.

goto label Va a un rótulo ( label:) , una posición en un bloque de instrucciones.

return Sale de forma incondicional.

waitfor Define el retardo para la ejecución del comando.

print Imprime un mensaje definido por el usuario o una variable local en la pantalla del usuario.

raiserror Imprime un mensaje definido por el usuario o una variable local en la pantalla del usuario y define un indicador del sistema en la variable global @@ error .

/* coment ario */

Inserta un comentario en cualquier punto de una instrucción SQL.

if...else

begin...end

while y break...continue

declare y variables locales

goto

return

print

raiserror

Mensajes definidos por el usuario para print y raiserror

waitfor

Comentarios

if ... else

La palabra clave if , con o sin la compañía de else , se utiliza para introducir una condición que determina si se ejecutará la instrucción siguiente. La instrucción SQL se ejecuta si la condición se cumple, es decir, si devuelve TRUE (verdadero).

La palabra clave else introduce una instrucción SQL alternativa que se ejecuta cuando la condición if devuelve FALSE (falso).

La sintaxis para if y else es:

if

boolean_expression

statement

[else

[if boolean_expression ]

statement ]

Page 196: 80575032 Libro de SQL y Tl SQL Excelente

Page 196 of 280

Una expresión booleana es una expresión que devuelve TRUE o FALSE. En ella se puede incluir un nombre de columna, una constante, cualquier combinación de nombres de columna y constantes conectados por operadores aritméticos o basados en bits, o una subconsulta, siempre que ésta devuelva un solo valor. Si la expresión booleana contiene una instrucción select , debe incluirse entre paréntesis y devolver un solo valor.

A continuación se muestra un ejemplo del uso de if sola:

if exists (select postalcode from authors

where postalcode = '94705')

print "Berkeley author"

Si uno o más de los códigos postales de la tabla de autores tiene el valor "94705", se imprimirá el mensaje "Berkeley author". La instrucción select de este ejemplo devuelve un solo valor, TRUE o FALSE, porque se usa con la palabra clave exists . Esta palabra clave funciona aquí al igual que en las subconsultas. Consulte el Capítulo 5, "Subconsultas: uso de consultas dentro de otras consultas".

A continuación se muestra un ejemplo con if y else que verifica la presencia de objetos creados por el usuario, todos los que tienen números de ID superiores a 50. Si existen objetos de usuario, la cláusula else selecciona sus nombres, tipos y números de ID.

if (select max(id) from sysobjects) < 50

print "There are no user-created objects in this database."

else

select name, type, id from sysobjects

where id > 50 and type = "U"

(0 rows affected)

name type id

------------ ----------

authors U 1088006907

publishers U 1120007021

roysched U 1152007135

sales U 1184007249

titleauthor U 1216007363

titles U 1248007477

stores U 1280007591

discounts U 1312007705

test U 1648008902

(9 rows affected)

Las estructuras if...else se utilizan frecuentemente en procedimientos almacenados en los que se verifica la existencia de algún parámetro.

Las pruebas if pueden estar anidadas dentro de otras pruebas if , ya sea dentro de otra construcción if o después de una else . La expresión de la prueba if sólo puede devolver un valor. Además, para cada estructura if...else , puede existir una instrucción select para if y otra para else . Para incluir más de una instrucción select , hay que utilizar las palabras clave begin...end . El número máximo de pruebas if que pueden anidarse varía con la complejidad de las instrucciones select (u otras estructuras de lenguaje) que se incluyan con cada estructura if...else .

begin...end

Las palabras clave begin y end se utilizan para englobar una serie de instrucciones a fin de que sean tratadas como una unidad por las estructuras de control de flujo como if...else . Una serie de instrucciones englobadas por begin y end se denomina bloque de instrucciones .

La sintaxis de begin...end es:

begin

statement block

end

He aquí un ejemplo:

if (select avg(price) from titles) < $15

begin

update titles

Page 197: 80575032 Libro de SQL y Tl SQL Excelente

Page 197 of 280

set price = price * 2

select title, price

from titles

where price > $28

end

Sin begin ni end , la condición if sólo se aplicaría a la primera instrucción SQL. La segunda instrucción se ejecutaría independientemente de la primera.

Los bloques begin ... end pueden anidarse dentro de otros bloques begin...end .

while y break...continue

while se utiliza para definir una condición para la ejecución repetida de una instrucción o un bloque de instrucciones. Las instrucciones se ejecutan reiteradamente siempre que la condición especificada sea verdadera.

La sintaxis es:

while boolean_expression

statement

En este ejemplo, las instrucciones select y update se repiten siempre que el precio promedio permanezca por debajo de $30:

while (select avg(price) from titles) < $30

begin

select title_id, price

from titles

where price > $20

update titles

set price = price * 2

end

(0 rows affected)

title_id price

------ -------

PC1035 22.95

PS1372 21.59

TC3218 20.95

(3 rows affected)

(18 rows affected)

(0 rows affected)

title_id price

------ -------

BU1032 39.98

BU1111 23.90

BU7832 39.98

MC2222 39.98

PC1035 45.90

PC8888 40.00

PS1372 43.18

PS2091 21.90

PS3333 39.98

TC3218 41.90

TC4203 23.90

TC7777 29.98

(12 rows affected)

(18 rows affected)

(0 rows affected)

break y continue controlan el funcionamiento de las instrucciones dentro de un bucle while . break permite salir del bucle while . Todas las instrucciones que aparecen después de la palabra clave end , que marca el final del bucle, se ejecutan. continue hace que el bucle while se inicie de nuevo, omitiendo cualquier instrucción después de continue menos dentro del bucle. break y continue se activan frecuentemente mediante una prueba if .

La sintaxis de break...continue es:

Page 198: 80575032 Libro de SQL y Tl SQL Excelente

Page 198 of 280

while boolean expression

begin

statement

[ statement ]...

break

[ statement ]...

continue

[ statement ]...

end

A continuación se muestra un ejemplo con while , break , continue e if que invierte el aumento producido en los ejemplos anteriores. Siempre que el precio promedio permanezca por encima de $20, todos los precios se reducen a la mitad. Después se selecciona el precio máximo. Si es inferior a $40, se sale del bucle while ; en caso contrario, intenta realizar el bucle de nuevo. continue permite que la instrucción print se ejecute sólo cuando el promedio está por encima de $20. Después de que termina el bucle while , se imprime un mensaje y una lista de los libros con el precio máximo.

while (select avg(price) from titles) > $20

begin

update titles

set price = price / 2

if (select max(price) from titles) < $40

break

else

if (select avg(price) from titles) < $20

continue

print "Average price still over $20"

end

select title_id, price from titles

where price > $20

print "Not Too Expensive"

(18 rows affected)

(0 rows affected)

(0 rows affected)

Average price still over $20

(0 rows affected)

(18 rows affected)

(0 rows affected)

title_id price

-------- -------

PC1035 22.95

PS1372 21.59

TC3218 20.95

(3 rows affected)

Not Too Expensive

Si hay dos o más bucles while anidados, la instrucción break sale al siguiente bucle exterior. Primero se ejecutan todas las instrucciones que aparecen después de la palabra clave end del bucle interno y luego se reinicia el bucle externo .

declare y variables locales

Una variable es una entidad a la que se asigna un valor. Este valor puede cambiar durante el lote o el procedimiento almacenado donde se utiliza la variable. SQL Server tiene dos tipos de variables: locales y globales. Las variables locales están definidas por el usuario, mientras que las variables globales las suministra el sistema y están predefinidas.

Las variables locales se declaran, nombran y escriben mediante la palabra clave declare , y reciben un valor inicial mediante una instrucción select . Dichas variables deben declararse, recibir un valor y utilizarse en su totalidad dentro del mismo lote o procedimiento.

Las variables locales se utilizan frecuentemente en un lote o procedimiento almacenado como contadores de bucles while o bloques if...else . Cuando se usan en procedimientos almacenados, las variables locales se declaran para su uso automático no interactivo por parte del procedimiento cuando éste se ejecuta.

Los nombres de las variables locales deben empezar con el símbolo "@" y después seguir las reglas para identificadores. A cada variable local se le debe asignar un tipo de datos definido por el usuario o un tipo de datos suministrado por el sistema distinto de text , image o sysname .

Page 199: 80575032 Libro de SQL y Tl SQL Excelente

Page 199 of 280

Las variables locales se declaran con esta sintaxis:

declare @ variable_name datatype

[, @ variable_name datatype ]...

Cuando se declara una variable, tiene el valor NULL. Los valores se asignan a las variables locales con una instrucción select . A continuación se muestra la sintaxis:

select @ variable_name = { expression | ( select_statement ) } [, @ variable =

{ expression | ( select_statement ) } ...]

[from clause ] [where clause ] [group by clause ]

[having clause ] [order by clause ] [compute clause ]

Las variables locales deben declararse y utilizarse en el mismo lote o procedimiento.

La instrucción select que asigna un valor a la variable local generalmente devuelve un solo valor. Una subconsulta que asigna un valor a la variable local debe devolver un sólo valor. A continuación se muestran algunos ejemplos:

declare @veryhigh money

select @veryhigh = max(price)

from titles

if @veryhigh > $20

print "Ouch!"

declare @one varchar(18), @two varchar(18)

select @one = "this is one", @two = "this is two"

if @one = "this is one"

print "you got one"

if @two = "this is two"

print "you got two"

else print "nope"

declare @tcount int, @pcount int

select @tcount = (select count(*) from titles),

@pcount = (select count(*) from publishers)

select @tcount, @pcount

Las instrucciones select que utilizan expresiones que devuelven más de un valor asignan a la variable el último valor devuelto.

Es más eficaz en términos de uso de memoria y de rendimiento escribir:

select @a = 1, @b = 2, @c = 3

que escribir:

select @a = 1

select @b = 2

select @c = 3

Una regla similar se aplica a las instrucciones declare . Es más eficaz escribir:

declare @a int, @b char(20), @c float

que escribir:

declare @a int

declare @b char(20)

declare @c float

La instrucción select que asigna valores a variables sólo tiene esa única misión; no puede utilizarse para devolver datos al usuario. La primera instrucción select del siguiente ejemplo asigna el precio máximo a la variable local @ veryhigh ; la segunda instrucción select es necesaria para mostrar el valor:

declare @veryhigh money

select @veryhigh = max(price)

from titles

select @veryhigh

Page 200: 80575032 Libro de SQL y Tl SQL Excelente

Page 200 of 280

Si la instrucción select que asigna valores a una variable devuelve más de un valor, se asigna a la variable el último valor devuelto. Esta consulta asigna a la variable el último valor devuelto por "select advance from titles":

declare @m money

select @m = advance from titles

select @m

(18 rows affected)

------------------------

8,000.00

(1 row affected)

Observe que la instrucción de asignación indica el número de filas afectadas (devueltas) por la instrucción select.

Si una instrucción select que asigna valores a una variable no devuelve ningún valor, la instrucción deja la variable intacta.

Las variables locales pueden utilizarse como argumentos para print o raiserror .

Variables y valores nulos

A las variables locales se les asigna el valor NULL cuando se declaran, y se les puede asignar el valor nulo mediante una instrucción select . El significado especial de NULL requiere que la comparación entre variables con valores nulos y otros valores nulos se ajuste a reglas especiales.

Esta tabla muestra los resultados de comparaciones entre columnas con valores nulos y expresiones con valores nulos usando operadores de comparación diferentes (una expresión puede ser una variable, un literal, o una combinación de variables, literales y operadores aritméticos).

Tabla 13-2: Comparación de valores nulos

Usando los operadores =, != o <> Usando los operadores <, >, <=, !< o !>

Comparando c olumn_value y c olumn_value FALSE FALSE

Comparando c olumn_value y e xpression TRUE FALSE

Comparando e xpression y c olumn_value TRUE FALSE

Comparando e xpression y e xpression TRUE FALSE

Por ejemplo, esta prueba:

declare @v int, @i int

if @v = @i select "null = null, true"

if @v > @i select "null > null, true"

muestra que sólo la primera comparación devuelve un valor verdadero:

-----------------

null = null, true

(1 row affected)

Este ejemplo devuelve todas las filas de la tabla titles donde advance tiene el valor NULL:

declare @m money

select title_id, advance

from titles

where advance = @m

title_id advance

-------- ----------------

MC3026 NULL

PC9999 NULL

declare y variables locales

Page 201: 80575032 Libro de SQL y Tl SQL Excelente

Page 201 of 280

Las variables globales son variables predefinidas suministradas por el sistema. Se distinguen de las variables locales por tener dos símbolos "@" precediendo a sus nombres, por ejemplo, @@ error .

Estas son las variables globales:

Tabla 13-3: Variables globales de SQL Server

Variable Contenido

@@char_convert Contiene 0 si la conversión del juego de caracteres no está en efecto. Contiene 1 si la conversión del juego de caracteres está en efecto.

@@client_csname Contiene el nombre del juego de caracteres del cliente. Se define como NULL si el juego de caracteres del cliente nunca fue inicializado; en caso contrario, contiene el nombre del último juego de caracteres utilizado.

@@client_csid Contiene la ID del juego de caracteres del cliente. Se define como -1 si el juego de caracteres del cliente nunca fue inicializado; en caso contrario, contiene la id de syscharsets del último juego de caracteres usado.

@@connections Contiene el número de logins o intentos de login.

@@cpu_busy Contiene la cantidad de tiempo, en pulsos, que la CPU empleó en realizar el trabajo de SQL Server desde la última vez que se inició.

@@error

Contiene 0 si la última transacción se ejecutó de forma correcta; en caso contrario, contiene el último número de error generado por el sistema. La variable global @@error se utiliza generalmente para verificar el estado de error, se haya ejecutado correctamente o no, de la última instrucción emitida. Una instrucción como if @@error != 0 seguida de return origina una salida por error.

@@identity

Contiene el último valor insertado en una columna IDENTITY mediante una instrucción insert o select into . @@identity se define cada vez que se inserta una fila en una tabla. Si una instrucción inserta múltiples filas, @@ identity refleja el valor IDENTITY de la última fila insertada. Si la tabla afectada no contiene una columna IDENTITY, @@identity se define en 0.

El valor de @@identity no se ve afectado por el fallo de una instrucción insert o select into , ni por la reversión de la transacción que la contenía. @@ identity conserva el último valor insertado en una columna IDENTITY, aunque la instrucción que la haya insertado no se consigne.

@@idle Contiene la cantidad de tiempo, en pulsos, que SQL Server estuvo inactivo.

@@io_busy Contiene la cantidad de tiempo, en pulsos, que SQL Server empleó para efectuar operaciones de entrada y salida.

@@isolation Contiene el nivel de aislamiento actual del programa Transact-SQL. @@isolation toma el valor del nivel activo (1 o 3).

@@langid Define la ID de idioma local del idioma en uso, según el valor de syslanguages.langid .

@@language Define el nombre del idioma en uso, según el valor de syslanguages.name .

@@maxcharlen Contiene la longitud máxima, en bytes, de los caracteres multibyte del juego de caracteres predeterminado.

@@max_connections

Contiene el número máximo de conexiones simultáneas que se pueden realizar con SQL Server en este entorno informático. El usuario puede configurar SQL Server para cualquier número de conexiones menor o igual que el valor de @@max_connections con sp_configure " number of user connections ".

@@ncharsize Contiene la longitud media, en bytes, de un carácter nacional.

@@nestlevel Contiene el nivel de anidación de la ejecución actual, inicialmente cero. Cada vez que un procedimiento almacenado o disparador llama a otro procedimiento almacenado o disparador, se incrementa el nivel de anidación. Si se supera el máximo de 16, la transacción se aborta.

@@pack_received Contiene el número de paquetes de entrada leídos por SQL Server.

@@pack_sent Contiene el número de paquetes de salida escritos por SQL Server.

@@packet_errors Contiene el número de errores generados mientras SQL Server enviaba y recibía paquetes.

@@procid Contiene la ID de procedimiento almacenado del procedimiento en ejecución.

@@rowcount Contiene el número de filas afectadas por la última consulta. @@rowcount es definida como cero por cualquier comando que no devuelve filas, como una instrucción if .

@@servername Contiene el nombre de este SQL Server.

@@spid Contiene el número de la ID de proceso de servidor del proceso actual.

@@sqlstatus Contiene información de estado resultante de la última instrucción fetch .

Page 202: 80575032 Libro de SQL y Tl SQL Excelente

Page 202 of 280

@@textcolid Contiene la ID de columna de la columna referenciada por @@ textptr . El tipo de datos de esta variable es tinyint .

@@textdbid Contiene la ID de base de datos de una base de datos que contiene un objeto con la columna referenciada por @@ textptr . El tipo de datos de esta variable es smallint.

@@textobjid Contiene la ID de objeto de un objeto que contiene la columna referenciada por @@ textptr . El tipo de datos de esta variable es int

@@textptr Contiene el puntero de texto de la última columna text o image insertada o actualizada por un proceso. El tipo de datos de esta variable es binary(16) (no confunda esta variable con la función textptr ).

@@textsize Contiene el límite del número de bytes de datos text o image devueltos por una instrucción select . El límite predeterminado es 32K bytes para isql ; el valor predeterminado depende del software del cliente. Puede cambiarse el límite de una sesión mediante set textsize .

@@textts Contiene la marca horaria de texto de la columna referenciada por @@ textptr . El tipo de datos de esta variable es varbinary(8) .

@@thresh_hysteresis Contiene la disminución de espacio libre necesaria para activar un umbral. Esta cantidad, también conocida como valor de histéresis, se mide en páginas de base de datos de 2K. Determina la proximidad a la que se pueden colocar los umbrales en un segmento de base de datos.

@@timeticks Contiene el número de microsegundos por pulso. La cantidad de tiempo por pulso es dependiente de la máquina.

@@total_errors Contiene el número de errores generados mientras SQL Server realizaba una lectura o escritura.

@@total_read Contiene el número de lecturas de disco realizadas por SQL Server desde la última vez que se inició.

@@total_write Contiene el número de escrituras de disco realizadas por SQL Server desde la última vez que se inició.

@@tranchained Contiene el modo de transacción actual del programa Transact-SQL. @@tranchained devuelve 0 para no encadenadas o 1 para encadenadas.

@@trancount Contiene el número de transacciones activas del usuario actual.

@@transtate Contiene el estado actual de una transacción después que se ejecuta una instrucción. Sin embargo, @@transtate no se borra para cada instrucción, al contrario de lo que ocurre con @@error .

@@version Contiene la fecha de la versión actual de SQL Server.

Para obtener información sobre el contenido de muchas de estas variables globales, hay que ejecutar el procedimiento del sistema sp_monitor . Para obtener información completa sobre los procedimientos del sistema, consulte el Manual de Referencia de SQL Server .

Si un usuario declara una variable local que tiene el mismo nombre que una variable global , dicha variable se trata como una variable local.

goto

La palabra clave goto origina una bifurcación incondicional a un rótulo definido por el usuario. goto y los rótulos pueden utilizarse en procedimientos almacenados y lotes. El nombre del rótulo debe ajustarse a las reglas para identificadores e ir seguido de un signo de dos puntos (:) la primera vez que se introduce. No va seguido de un signo de dos puntos cuando se utiliza con goto .

A continuación se muestra la sintaxis:

label :

goto label

A continuación se muestra un ejemplo que utiliza goto y un rótulo, un bucle while u una variable local como contador:

declare @count smallint

select @count = 1

restart:

print "yes"

select @count = @count + 1

while @count <=4

goto restart

Como en este ejemplo, goto generalmente se hace dependiente de un bucle while o una prueba if , o alguna otra condición, a fin de evitar un bucle infinito entre goto y el rótulo.

Page 203: 80575032 Libro de SQL y Tl SQL Excelente

Page 203 of 280

return

La palabra clave return sale de un lote o procedimiento de forma incondicional y puede usarse en cualquier momento de un lote o procedimiento. Cuando se utiliza en procedimientos almacenados, return puede aceptar un argumento opcional para devolver un estado al solicitante. Las instrucciones que aparecen después de return no se ejecutan.

La sintaxis es simplemente:

return [ int_expression ]

A continuación se muestra un ejemplo de un procedimiento almacenado que utiliza return , así como if...else y begin...end :

create procedure findrules @nm varchar(30) = null as

if @nm is null

begin

print "You must give a user name"

return

end

else

begin

select sysobjects.name, sysobjects.id, sysobjects.uid

from sysobjects, master..syslogins

where master..syslogins.name = @nm

and sysobjects.uid = master..syslogins.suid

and sysobjects.type = "R"

end

Si no se proporciona ningún nombre de usuario como parámetro cuando se llama a findrules , la palabra clave return hace que el procedimiento se detenga después de que el usuario haya recibido un mensaje en su pantalla. Si se proporciona un nombre de usuario, los nombres de las reglas propiedad del usuario se recuperan de las tablas del sistema correspondientes.

return es similar a la palabra clave break usada dentro de los bucles while .

Los ejemplos que utilizan valores de retorno se incluyen en el Capítulo 14, "Uso de procedimientos almacenados".

print

La palabra clave print , utilizada en el ejemplo anterior, muestra un mensaje definido por el usuario o el contenido de una variable local en la pantalla del usuario. La variable local debe declararse dentro del mismo lote o procedimiento en el que se utiliza. El mensaje en sí puede tener hasta 255 bytes de longitud.

La sintaxis es:

print { format_string | @ local_variable |

@@ global _ variable } [, arg_list ]

He aquí otro ejemplo:

if exists (select postalcode from authors

where postalcode = '94705')

print "Berkeley author"

A continuación se indica cómo utilizar print para mostrar el contenido de una variable local:

declare @msg char(50)

select @msg = "What's up doc?"

print @msg

print reconoce los marcadores de lugar de la cadena de caracteres que va a imprimirse. Las cadenas de formato pueden contener hasta 20 marcadores de lugar únicos colocados en cualquier orden. Estos marcadores se sustituyen por el contenido formateado de cualquier argumento que aparezca después de format_string cuando el texto del mensaje se envía al cliente.

Para permitir la reordenación de los argumentos cuando las cadenas de formato se traducen a un idioma con una estructura gramatical diferente, los marcadores de lugar se numeran. El marcador de lugar de un argumento aparece en este formato:

Page 204: 80575032 Libro de SQL y Tl SQL Excelente

Page 204 of 280

%nn! . Los componentes son un signo de porcentaje, un valor entero entre 1 y 20, y un signo de admiración. El valor entero representa la posición del marcador de lugar en la cadena en el idioma original. "%1!" es el primer argumento en la versión original, "%2!" es el segundo argumento, y así sucesivamente. Indicar la posición del argumento de este modo hace posible traducir correctamente, incluso cuando el orden en que aparecen los argumentos en el idioma de destino es distinto del orden en el idioma de origen.

Por ejemplo, suponga que el siguiente mensaje está en inglés:

%1! is not allowed in %2!.

La versión en alemán de este mensaje es:

%1! ist in %2! nicht zulässig.

La versión en japonés del mensaje es:

En este ejemplo, "%1!" en los tres idiomas representa el mismo argumento, y "%2!" también representa un solo argumento en los tres idiomas. Este ejemplo muestra la reordenación de los argumentos que, en ocasiones, es necesaria en el formato traducido.

No es posible omitir los números de los marcadores de lugar cuando éstos se usan en una cadena de formato, aunque los marcadores no tienen que utilizarse en orden numérico. Por ejemplo, no se pueden tener los marcadores de lugar 1 y 3 en una cadena de formato sin tener el marcador 2 en la misma cadena.

El parámetro opcional arg_list puede ser una serie de variables o de constantes. Un argumento puede ser cualquier tipo de datos excepto text o image ; se convierte al tipo de datos char antes de incluirse en el mensaje final. Si no se proporciona ninguna lista de argumentos, la cadena de formato debe ser el mensaje que ha de imprimirse, sin ningún marcador de lugar.

La longitud máxima de la cadena de salida de format_string más todos los argumentos después de la sustitución es de 512 bytes.

raiserror

raiserror muestra un error definido por el usuario o un mensaje de variable local en la pantalla del usuario y define un indicador del sistema para registrar el hecho de que se ha producido un error. Al igual que ocurre con print , la variable local debe declararse en el mismo lote o procedimiento en que se utiliza. El mensaje puede tener hasta 255 caracteres de longitud.

A continuación se muestra la sintaxis de raiserror :

raiserror error_number

[{ format_string | @ local_variable }] [, arg_list ]

[ extended_value = extended_value [{, extended_value = extended_value }...]]

El número de error ( error_number ) se sitúa en la variable global @@ error , que almacena el último número de error generado por SQL Server, independientemente de que esté asociado a un mensaje de error suministrado por el sistema o uno definido por el usuario. Los números de error de los mensajes de error definidos por el usuario deben ser superiores a 17000. Si error_number está entre 17000 y 19999, y no se ha especificado una cadena de formato ( format_string ) o ésta se encuentra vacía (""), SQL Server recupera texto de mensaje de error de la tabla sysmessages de la base de datos master . Estos mensajes de error los utilizan principalmente los procedimientos del sistema.

La longitud de la cadena de formato (format_string) está limitada a 255 bytes; la longitud máxima de la salida de format_string más todos los argumentos es de 512 bytes. Las variables locales utilizadas para los mensajes de raiserror deben ser char o varchar . La cadena de formato o la variable son opcionales. Si no se incluye ninguna, SQL Server usa el mensaje correspondiente al error_number de sysusermessages en el idioma predeterminado. Al igual que sucede con print , es posible sustituir variables o constantes definidas por arg_list en format_string .

Como opción, se pueden definir datos de error extendidos para que los use la aplicación Open Client(TM) (cuando se incluyen valores extendidos con raiserror ). Para obtener más información sobre los datos de error extendidos, consulte la documentación de Open Cliente o raiserror en el Manual de Referencia de SQL Server .

Page 205: 80575032 Libro de SQL y Tl SQL Excelente

Page 205 of 280

Use raiserror en lugar de print cuando desee almacenar un número de error en @@ error . Por ejemplo, a continuación se indica cómo podría utilizar raiserror en el procedimiento findrules :

raiserror 99999 "You must give a user name"

El nivel de gravedad de todos los mensajes de error definidos por el usuario es 16. Este nivel indica que el usuario ha cometido un error no fatal.

Mensajes definidos por el usuario para print y raiserror

Se puede llamar a mensajes de sysusermessages para que los use print o raiserror con el procedimiento del sistema sp_getmessage . Utilice el procedimiento del sistema sp_addmessage para crear un conjunto de mensajes.

El ejemplo que aparece a continuación utiliza sp_addmessage , sp_getmessage y print para instalar un mensaje en sysusermessages en inglés y alemán, recuperarlo para su uso en un procedimiento almacenado definido por el usuario e imprimirlo.

/*

** Instalar mensajes

** Primero, en inglés (langid = NULL)

*/

set language us_english

go

sp_addmessage 25001,

"There is already a remote user named '%1!' for remote server '%2!'."

go

/* Luego, en alemán*/

sp_addmessage 25001,

"Remotebenutzername '%1!' existiert bereits auf dem Remoteserver '%2!'.","german"

go

create procedure test_proc @remotename varchar(30),

@remoteserver varchar(30)

as

declare @msg varchar(255)

declare @arg1 varchar(40)

/*

** verificar que no hay ningún

** @remotename para el @remoteserver.

*/

if exists (select *

from master.dbo.sysremotelogins l,

master.dbo.sysservers s

where l.remoteserverid = s.srvid

and s.srvname = @remoteserver

and l.remoteusername = @remotename)

begin

exec sp_getmessage 25001, @msg output

select @arg1=isnull(@remotename,"null")

print @msg, @arg1, @remoteserver

return (1)

end

return(0)

go

waitfor

La palabra clave waitfor especifica una hora determinada del día, un intervalo de tiempo o un evento en el que debe tener lugar la ejecución de un bloque de instrucciones, un procedimiento almacenado o una transacción.

A continuación se muestra la sintaxis:

waitfor {delay " time " | time " time " | errorexit | processexit | mirrorexit}

La palabra clave delay indica a SQL Server que espere hasta que haya transcurrido el tiempo especificado. time indica a SQL Server que espere hasta la hora especificada, proporcionada en uno de los formatos aceptables para datos datetime .

Page 206: 80575032 Libro de SQL y Tl SQL Excelente

Page 206 of 280

Sin embargo, no es posible especificar fechas, no se permite el componente de fecha del valor datetime . El tiempo especificado con waitfor time o waitfor delay puede incluir horas, minutos y segundos, hasta un máximo de 24 horas. Emplee el formato "hh:mm:ss". Por ejemplo, waitfor time "16:23" indica a SQL Server que espere hasta las 4:23 pm. La instrucción waitfor delay "01:30" indica a SQL Server que espere una hora y 30 minutos. Para obtener una revisión de los formatos aceptables para los valores de time , consulte el Capítulo 8, "Adición, modificación y eliminación de datos".

errorexit indica a SQL Server que espere hasta que un proceso termine de forma anormal. processexit espera hasta que un proceso termina por cualquier razón. mirrorexit espera hasta que falla una lectura o una escritura de un dispositivo duplicado.

waitfor errorexit se puede utilizar con un procedimiento que destruya el proceso terminado de forma anormal a fin de liberar los recursos del sistema que de otro modo serían ocupados por un proceso infectado. Para averiguar cuál es el proceso infectado, verifique la tabla sysprocesses con el procedimiento del sistema sp_who .

Este ejemplo indica a SQL Server que espere hasta las 2:20 p.m. Después, actualiza la tabla chess con el siguiente movimiento y ejecuta un procedimiento almacenado llamado sendmessage , que inserta un mensaje en una de las tablas de Judy, informándole que ahora existe un nuevo movimiento en la tabla chess . He aquí el ejemplo:

begin

waitfor time "14:20"

insert chess(next_move)

values('Q-KR5')

execute sendmessage 'judy'

end

Para enviar el mensaje a Judy después de 10 segundos en lugar de esperar hasta las 2:20, sustituya esta instrucción waitfor en el ejemplo anterior:

waitfor delay "0:00:10"

Una vez emitido el comando waitfor , no puede utilizar su conexión a SQL Server hasta que llegue la hora o tenga lugar el evento especificado.

Comentarios

La notación del comentario se utiliza para anexar comentarios a instrucciones, lotes y procedimientos almacenados. Un comentario tiene el siguiente aspecto:

/* texto del comentario */

Los comentarios no tienen una longitud máxima y pueden insertarse en cualquier lugar, en una línea independiente o al final de una línea. Los comentarios con múltiples líneas también son correctos, siempre que cada comentario comience con una barra invertida y un asterisco, y finalice con un asterisco y una barra invertida. Todo lo que se encuentra entre "/*" y "*/" se trata como parte del comentario. Los comentarios se pueden anidar.

Una convención estilística utilizada frecuentemente para comentarios de varias líneas es comenzar la primera línea con "/*" y las líneas posteriores con "**". El comentario finaliza con "*/" como siempre. A continuación se muestra el aspecto que tiene:

select * from titles

/* Un comentario incluido aquí puede explicar las

** reglas relacionadas con el uso de un asterisco

** como una abreviatura en la lista de selección.*/

where price > $5

A continuación se muestra un procedimiento que incluye un par de comentarios:

/* este procedimiento busca las reglas por nombre

** de usuario*/

create procedure findrules2 @nm varchar(30) = null

as if @nm is null /* si no se indica ningún

** parámetro*/

print "You must give a user name"

else

begin

select sysobjects.name, sysobjects.id,

Page 207: 80575032 Libro de SQL y Tl SQL Excelente

Page 207 of 280

sysobjects.uid

from sysobjects, master..syslogins

where master..syslogins.name = @nm

and sysobjects.uid = master..syslogins.suid

and sysobjects.type = "R"

end

Chapter 14

Uso de procedimientos almacenados

Se pueden agrupar instrucciones SQL y el lenguaje de control de flujo en un procedimiento almacenado para mejorar el funcionamiento de SQL Server. Además, puede utilizar un grupo de procedimientos predefinidos, llamados procedimientos almacenados del sistema, para realizar tareas administrativas y actualizar las tablas del sistema.

En este capítulo se trata lo siguiente:

Introducción general a los procedimientos almacenados

Creación y ejecución de procedimientos almacenados

Obtención de información a partir de procedimientos almacenados

Reglas asociadas a procedimientos almacenados

Omisión y cambio de nombre de procedimientos almacenados

Uso de procedimientos almacenados del sistema

Obtención de información sobre procedimientos almacenados

Definición de procedimiento almacenado

Creación y ejecución de procedimientos almacenados

Obtención de información a partir de procedimientos almacenados

Reglas asociadas a procedimientos almacenados

Omisión de procedimientos almacenados

Cambio de nombre de los procedimientos almacenados

Uso de procedimientos almacenados como mecanismos de seguridad

Procedimientos del sistema

Obtención de información sobre procedimientos almacenados

Definición de procedimiento almacenado

Los procedimientos almacenados son grupos formados por instrucciones SQL y el lenguaje de control de flujo. Cuando se ejecuta un procedimiento, se prepara un plan de ejecución para que la subsiguiente ejecución sea muy rápida. Los procedimientos almacenados pueden:

Incluir parámetros

Llamar a otros procedimientos

Devolver un valor de estado a un procedimiento de llamada o lote para indicar el éxito o el fracaso del mismo y la razón de dicho fallo

Devolver valores de parámetros a un procedimiento de llamada o lote

Ejecutarse en SQL Server remotos

La posibilidad de escribir procedimientos almacenados mejora notablemente la potencia, eficacia y flexibilidad de SQL. Los procedimientos compilados mejoran la ejecución de las instrucciones y lotes de SQL de forma dramática. Además, los procedimientos almacenados pueden ejecutarse en otros SQL Server si el servidor del usuario y el remoto están configurados para permitir logins remotos. Escriba disparadores en su SQL Server local que ejecuten procedimientos en un servidor remoto siempre que determinados eventos, como las eliminaciones, actualizaciones o inserciones, tengan lugar a nivel local.

Los procedimientos almacenados se diferencian de las instrucciones SQL ordinarias y de los lotes de instrucciones SQL en que están precompilados. La primera vez que se ejecuta un procedimiento, el procesador de consultas de SQL Serverlo analiza y prepara un plan de ejecución que se almacena de forma definitiva en una tabla del sistema . Posteriormente, el procedimiento se ejecuta según el plan almacenado. Puesto que ya se ha realizado la mayor parte del trabajo de procesamiento de consultas, los procedimientos almacenados se ejecutan casi de forma instantánea.

Page 208: 80575032 Libro de SQL y Tl SQL Excelente

Page 208 of 280

SQL Server proporciona una gran variedad de procedimientos almacenados como herramientas adecuadas para el usuario. Estos procedimientos almacenados se llaman procedimientos del sistema.

Los procedimientos almacenados se crean con create procedure . Para ejecutar un procedimiento almacenado, ya sea un procedimiento del sistema o uno definido por el usuario, use el comando execute . También puede utilizar el nombre del procedimiento almacenado solo, siempre que sea la primera palabra de una instrucción o lote.

Ejemplos de creación y uso de procedimientos almacenados

La sintaxis para la creación de un procedimiento almacenado sencillo, sin funciones especiales como parámetros, es:

create procedure procedure_name

as SQL_statements

Los procedimientos almacenados son objetos de base de datos, y sus nombres deben ajustarse a las reglas para identificadores.

Es posible incluir cualquier número y cualquier tipo de instrucción SQL, salvo las instrucciones create . Consulte "Reglas asociadas a procedimientos almacenados". Un procedimiento puede ser tan sencillo como una sola instrucción que enumere los nombres de todos los usuarios de una base de datos:

create procedure namelist as select name from sysusers

Para ejecutar un procedimiento almacenado, emplee la palabra clave execute y el nombre del procedimiento almacenado, o simplemente especifique el nombre del procedimiento, siempre que se envíe a SQL Server solo o sea la primera instrucción de un lote. Puede ejecutar namelist de cualquiera de las siguientes formas:

namelist

execute namelist

exec namelist

Para ejecutar un procedimiento almacenado en un SQL Server remoto, debe proporcionar el nombre del servidor. La sintaxis completa de una llamada de procedimiento remoto es:

execute server_name .[ database_name ].[ owner ]. procedure_name

Los siguientes ejemplos ejecutan el procedimiento namelist en la base de datos pubs2 en el servidor GATEWAY:

execute gateway.pubs2..namelist

gateway.pubs2.dbo.namelist

exec gateway...namelist

El último ejemplo sólo funciona si pubs 2 es la base de datos predeterminada del usuario.

El nombre de la base de datos es opcional sólo si el procedimiento almacenado se encuentra en la base de datos predeterminada del usuario. El nombre del propietario es opcional sólo si el propietario de la base de datos ( " dbo " ) es el propietario del procedimiento o si el usuario lo posee. Lógicamente, es necesario tener permiso para ejecutar el procedimiento.

Un procedimiento puede incluir más de una instrucción.

create procedure showall as

select count(*) from sysusers

select count(*) from sysobjects

select count(*) from syscolumns

Cuando se ejecuta el procedimiento, los resultados de cada comando se muestran en el orden en que la instrucción aparece en el procedimiento.

showall

------------

5

(1 row affected)

Page 209: 80575032 Libro de SQL y Tl SQL Excelente

Page 209 of 280

------------

88

(1 row affected)

------------

349

(1 row affected, return status = 0)

Cuando el comando create procedure se ejecuta de forma correcta, el nombre del procedimiento se almacena en sysobjects y su texto en syscomments .

Se puede mostrar el texto de un procedimiento con el procedimiento del sistema sp_helptext :

sp_helptext showall

# Lines of Text

---------------

1

(1 row affected)

text

----------------------------------------

create procedure showall as

select count(*) from sysusers

select count(*) from sysobjects

select count(*) from syscolumns

(1 row affected, return status = 0)

Procedimientos almacenados y permisos

Los procedimientos almacenados pueden servir de mecanismos de seguridad, ya que un usuario puede recibir el permiso para ejecutar un procedimiento almacenado aunque no tenga permisos en las tablas o vistas referenciadas en el mismo ni permiso para ejecutar comandos específicos. Para obtener más detalles, consulte la Guía del Usuario de las Características de Seguridad .

Procedimientos almacenados y rendimiento

Conforme cambia la base de datos, los planes de consulta originales utilizados para acceder a sus tablas pueden volver a optimizarse recompilándolos con el procedimiento del sistema sp_recompile . Esto evitar tener que buscar, omitir y volver a crear cada procedimiento almacenado y disparador. El siguiente ejemplo marca cada procedimiento almacenado y disparador que accede a la tabla titles para que se recompile la próxima vez que se ejecute.

sp_recompile titles

Para obtener información detallada sobre sp_recompile , consulte el Manual de Referencia de SQL Server .

Creación y ejecución de procedimientos almacenados

La sintaxis completa de create procedure es:

create procedure [owner.]procedure_name[;number] [[ (]@parameter_name datatype [=

default] [output]

[, @parameter_name datatype [= default] [output]]...[)]] [with recompile]

as sql_statements

Sólo se puede crear un procedimiento en la base de datos actual.

El permiso para emitir create procedure está asignado de forma predeterminada al propietario de la base de datos, que puede transferirlo a otros usuarios.

A continuación se muestra la instrucción de sintaxis completa de execute :

[execute] [@return_status = ]

[[[ server .] database .] owner .] procedure_name [; number ]

[[@ parameter_name =] value |

Page 210: 80575032 Libro de SQL y Tl SQL Excelente

Page 210 of 280

[@ parameter_name =] @ variable [output]

[,[@ parameter_name =] value |

[@ parameter_name =] @ variable [output]...]]

[with recompile]

Note: Las llamadas de procedimientos remotos no se consideran parte de una transacción. Si ejecuta una llamada de procedimientos remotos después de begin transaction y luego usa rollback transaction , los cambios realizados por la llamada en los datos remotos no se revierten. El diseñador del procedimiento almacenado debe asegurarse de que se comprueban todas las condiciones que puedan originar una reversión antes de ejecutar una llamada de procedimientos remotos que altere los datos remotos.

Parámetros

Un parámetro es un argumento de un procedimiento almacenado. Es posible declarar uno o más parámetros de forma opcional en una instrucción create procedure . El usuario debe suministrar el valor de cada parámetro indicado en una instrucción create procedure al ejecutarse el procedimiento.

Los nombres de los parámetros deben estar precedidos del símbolo "@" y ajustarse a las reglas para identificadores. Es necesario asignarles un tipo de datos del sistema o uno definido por el usuario, y una longitud si es necesario para el tipo de datos. Los nombres de los parámetros son locales para el procedimiento que los crea; los mismos nombres de parámetros pueden utilizarse en otros procedimientos. Los nombres de parámetro, incluido el símbolo "@", pueden tener una longitud máxima de 30 bytes.

A continuación se muestra un procedimiento almacenado que resulta útil en la base de datos pubs2 . Dado el apellido y nombre de un autor, el procedimiento muestra los nombres de los libros escritos por la persona en cuestión, así como el editor de cada libro.

create proc au_info @lastname varchar(40),

@firstname varchar(20) as

select au_lname, au_fname, title, pub_name

from authors, titles, publishers, titleauthor

where au_fname = @firstname

and au_lname = @lastname

and authors.au_id = titleauthor.au_id

and titles.title_id = titleauthor.title_id

and titles.pub_id = publishers.pub_id

Ahora ejecute au_info :

au_info Ringer, Anne

au_lname au_fname title pub_name

-------- -------- --------------------- ----------

Ringer Anne The Gourmet Microwave Binnet

& Hardley

Ringer Anne Is Anger the Enemy? New Age

Books

(2 rows affected, return status = 0)

El siguiente procedimiento almacenado consulta las tablas del sistema. Dado un nombre de tabla como parámetro, el procedimiento muestra el nombre de la tabla, el nombre del índice y la ID del índice.

create proc showind @table varchar(30) as

select table_name = sysobjects.name,

index_name = sysindexes.name, index_id = indid

from sysindexes, sysobjects

where sysobjects.name = @table

and sysobjects.id = sysindexes.id

Los encabezados de columna, por ejemplo , table_name , se añadieron para facilitar la lectura de los resultados. A continuación se muestran los formatos de sintaxis aceptables para la ejecución de este procedimiento almacenado:

execute showind titles

exec showind titles

execute showind @table = titles

execute GATEWAY.pubs2.dbo.showind titles

showind titles

Page 211: 80575032 Libro de SQL y Tl SQL Excelente

Page 211 of 280

El último formato de sintaxis, sin exec ni execute , es aceptable siempre que la instrucción sea la única o la primera de un lote.

A continuación se muestran los resultados de ejecutar showind en la base de datos pubs2 con titles como parámetro:

table_name index_name index_id

---------- ---------- ----------

titles titleidind 1

titles titleind 2

(2 rows affected, return status = 0)

Note: Si proporciona los parámetros con el formato "@ parameter = value ", puede especificarlos en cualquier orden. En caso contrario, debe proporcionar los parámetros en el orden de su instrucción create procedure . Si suministra un valor con el formato "@ parameter = value ", todos los parámetros subsiguientes han de suministrarse de este modo.

Parámetros predeterminados

Se puede asignar un valor predeterminado al parámetro de la instrucción create procedure . Este valor, que puede ser cualquier constante, se toma como el argumento del procedimiento si el usuario no proporciona ninguno.

A continuación se muestra un procedimiento que muestra los nombres de todos los autores que han escrito un libro publicado por el editor introducido como parámetro. Si no se proporciona ningún nombre de editor, el procedimiento muestra los autores publicados por Algodata Infosystems.

create proc pub_info

@pubname varchar(40) = "Algodata Infosystems" as

select au_lname, au_fname, pub_name

from authors a, publishers p, titles t, titleauthor ta

where @pubname = p.pub_name

and a.au_id = ta.au_id

and t.title_id = ta.title_id

and t.pub_id = p.pub_id

Tenga en cuenta que si el valor predeterminado es una cadena de caracteres que contiene espacios en blanco o signos de puntuación incrustados, es necesario incluirlo entre comillas simples o dobles.

Cuando ejecuta pub_info , puede proporcionar cualquier nombre de editor como valor del parámetro. Si no suministra ningún parámetro, SQL Server utiliza el predeterminado, Algodata Infosystems.

exec pub_info

au_lname au_fname pub_name

-------------- ------------ --------------------

Green Marjorie Algodata Infosystems

Bennet Abraham Algodata Infosystems

O'Leary Michael Algodata Infosystems

MacFeather Stearns Algodata Infosystems

Straight Dick Algodata Infosystems

Carson Cheryl Algodata Infosystems

Dull Ann Algodata Infosystems

Hunter Sheryl Algodata Infosystems

Locksley Chastity Algodata Infosystems

(9 rows affected, return status = 0)

En este procedimiento, showind2 , se asigna "titles" como valor predeterminado del parámetro @ table :

create proc showind2 @table varchar(30) = titles

as

select table_name = sysobjects.name,

index_name = sysindexes.name, index_id = indid

from sysindexes, sysobjects

where sysobjects.name = @table

and sysobjects.id = sysindexes.id

Los encabezados de columna, por ejemplo , table_name , clarifican la presentación de los resultados. A continuación se indica lo que el procedimiento muestra para la tabla authors :

Page 212: 80575032 Libro de SQL y Tl SQL Excelente

Page 212 of 280

showind2 authors

table_name index_name index_id

----------- ------------- ----------

authors auidind 1

authors aunmind 2

(2 rows affected, return status = 0)

Si el usuario no proporciona ningún valor, SQL Server utiliza el valor predeterminado, titles .

showind2

table_name index_name index_id

----------- ----------- ---------

titles titleidind 1

titles titleind 2

(2 rows affected, return status =0)

Si se espera un parámetro, pero no se suministra ninguno y no se proporciona ningún valor en la instrucción create procedure , SQL Server muestra un mensaje de error con los parámetros que espera el procedimiento.

NULL como parámetro predeterminado

El valor predeterminado puede ser el valor NULL. En este caso, si el usuario no suministra ningún parámetro, SQL Server ejecuta el procedimiento almacenado sin mostrar ningún mensaje de error.

La definición del procedimiento puede especificar una acción para llevarse a cabo si el usuario no proporciona ningún parámetro verificando si el valor del parámetro es nulo. A continuación se muestra un ejemplo:

create procedure showind3 @table varchar(30) = null

as

if @table is null

print "Please give a table name"

else

select table_name = sysobjects.name,

index_name = sysindexes.name, index_id = indid

from sysindexes, sysobjects

where sysobjects.name = @table

and sysobjects.id = sysindexes.id

Si el usuario no proporciona ningún parámetro, SQL Server imprime el mensaje del procedimiento en la pantalla.

Para otros ejemplos de definición del valor predeterminado como NULL, examine el texto de los procedimientos del sistema utilizando sp_helptext .

Caracteres comodín en el parámetro predeterminado

El valor predeterminado puede incluir los caracteres comodín (%, _, [] y [^]) si el procedimiento utiliza el parámetro con la palabra clave like .

Por ejemplo, showind puede modificarse para mostrar información sobre las tablas del sistema si el usuario no proporciona ningún parámetro, como se muestra a continuación:

create procedure showind4 @table varchar(30)="sys%"

as

select table_name = sysobjects.name,

index_name = sysindexes.name, index_id = indid

from sysindexes, sysobjects

where sysobjects.name like @table

and sysobjects.id = sysindexes.id

Uso de más de un parámetro

A continuación se muestra una variante del procedimiento almacenado au_info que tiene valores predeterminados con caracteres comodín para ambos parámetros:

Page 213: 80575032 Libro de SQL y Tl SQL Excelente

Page 213 of 280

create proc au_info2 @lastname varchar(30) = "D%",

@firstname varchar(18) = "%" as

select au_lname, au_fname, title, pub_name

from authors, titles, publishers, titleauthor

where au_fname like @firstname

and au_lname like @lastname

and authors.au_id = titleauthor.au_id

and titles.title_id = titleauthor.title_id

and titles.pub_id = publishers.pub_id

Si au_info2 se ejecuta sin parámetros, se muestran todos los autores cuyos apellidos comienzan por "D":

au_info2

au_lname au_fname title pub_name

-------- ------- ------------------------- -------------

Dull Ann Secrets of Silicon Valley Algodata Infosystems

DeFrance Michel The Gourmet Microwave Binnet & Hardley

(2 rows affected)

Si hay valores predeterminados disponibles para parámetros, éstos pueden omitirse en la ejecución, comenzando por el último parámetro. No puede saltarse un parámetro a menos que NULL sea su valor predeterminado suministrado.

Note: Si proporciona los parámetros en el formato " @parameter = value ", puede suministrarlos en cualquier orden. También puede omitir un parámetro para el que se ha suministrado un valor predeterminado. Si proporciona un valor en el formato " @parameter = value ", todos los parámetros subsiguientes también deberán suministrarse de este modo.

Como ejemplo de omisión del segundo parámetro cuando se han definido valores predeterminados para dos parámetros, puede buscar los libros y editores de todos los autores cuyo apellido es "Ringer", de la siguiente manera:

au_info2 Ringer

au_lname au_fname title Pub_name

-------- -------- --------------------- ------------

Ringer Anne The Gourmet Microwave Binnet & Hardley

Ringer Anne Is Anger the Enemy? New Age Books

Ringer Albert Is Anger the Enemy? New Age Books

Ringer Albert Life Without Fear New Age Books

(4 rows affected)

Grupos de procedimientos

El punto y coma (;) y el número entero opcionales después del nombre del procedimiento en las instrucciones create procedure y execute permiten agrupar los procedimientos que tienen el mismo nombre para que puedan omitirse juntos mediante un solo comando drop procedure .

Los procedimientos utilizados en la misma aplicación suelen agruparse de este modo. Por ejemplo, podría crear una serie de procedimientos llamados orders;1 , orders;2 , etc.. La siguiente instrucción omitiría el grupo completo:

drop proc orders

Una vez agrupados los procedimientos mediante el anexo de un punto y coma (;) y un número a sus nombres, no es posible omitirlos de forma individual. Por ejemplo, no se permite la siguiente instrucción:

drop proc orders;2

with recompile en create procedure

En la instrucción create procedure , la cláusula opcional with recompile aparece justo antes de las instrucciones SQL. Esto indica a SQL Server que no guarde ningún plan para este procedimiento. Cada vez que se ejecuta el procedimiento se crea un plan nuevo.

Si no se usa with recompile , SQL Server almacena el plan de ejecución que crea. Generalmente, este plan de ejecución es correcto.

Page 214: 80575032 Libro de SQL y Tl SQL Excelente

Page 214 of 280

Sin embargo, es posible que un cambio en los datos o un cambio en los valores de parámetro suministrados para las ejecuciones subsiguientes haga que SQL Server proponga un plan de ejecución distinto del que creó la primera vez que se ejecutó el procedimiento. En estas situaciones, SQL Server necesita un plan de ejecución nuevo.

Use with recompile en una instrucción create procedure cuando crea que necesita un plan nuevo. Consulte el Manual de Referencia de SQL Server para obtener más información.

with recompile en execute

En la instrucción execute , la cláusula opcional with recompile aparece después de cualquier parámetro. Esto indica a SQL Server que compile un plan nuevo. El plan nuevo se utiliza para ejecuciones subsiguientes.

Use with recompile cuando ejecute un procedimiento si los datos han sufrido un gran cambio o si el parámetro que proporciona es atípico, es decir, si tiene alguna razón para creer que el plan almacenado con el procedimiento podría no ser óptimo para la ejecución de éste.

Note: Si utiliza select * en la instrucción create procedure , el procedimiento, aunque use la opción with recompile de execute , no toma ninguna columna nueva añadida a la tabla. Es necesario omitir el procedimiento y volver a crearlo.

Anidación de procedimientos dentro de procedimientos

La anidación tiene lugar cuando un procedimiento almacenado o un disparador llama a otro. El nivel de anidación se incrementa cuando el procedimiento o disparador llamado inicia la ejecución y disminuye cuando el procedimiento o disparador llamado finaliza la ejecución. Si se supera el máximo de 16 niveles de anidación, el procedimiento no se ejecuta correctamente. El nivel de anidación actual se almacena en la variable global @@nestlevel .

Uso de tablas temporales en procedimientos almacenados

Es posible crear y utilizar tablas temporales en un procedimiento almacenado, pero la tabla temporal sólo existe mientras dura el procedimiento almacenado que la crea. Cuando el procedimiento finaliza, SQL Server omite la tabla temporal de forma automática. Un solo procedimiento puede:

Crear una tabla temporal

Insertar, actualizar o eliminar datos

Ejecutar consultas en la tabla temporal

Llamar a otros procedimientos que hacen referencia a la tabla temporal

Dado que la tabla temporal tiene que existir para poder crear procedimientos que hagan referencia a ella, a continuación se indican los pasos que debe seguir:

1. Cree la tabla temporal que precisa con una instrucción create table o una select into . Por ejemplo:

create table #tempstores

(stor_id char(4), amount money)

2. Cree los procedimientos que accedan a la tabla temporal (pero no el que la genera).

create procedure inv_amounts

as

select stor_id, "Total Due" =sum(amount)

from #tempstores

group by stor_id

3. Omita la tabla temporal:

drop table #tempstores

4. Cree el procedimiento que genera la tabla y llama a los procedimientos creados en el paso 2:

create procedure inv_proc

as

Page 215: 80575032 Libro de SQL y Tl SQL Excelente

Page 215 of 280

create table #tempstores

(stor_id char(4), amount money)

insert #tempstores

select stor_id, sum(qty*(100-discount)/100*price)

from salesdetail, titles

where salesdetail.title_id = titles.title_id

group by stor_id, salesdetail.title_id

exec inv_amounts

También puede crear tablas temporales sin el prefijo #, utilizando create table tempdb..tablename... desde dentro de un procedimiento almacenado. Estas tablas no desaparecen cuando finaliza el procedimiento, de modo que es posible hacer referencia a ellas mediante procedimientos independientes. Siga los pasos descritos anteriormente para crear estas tablas.

Ejecución de procedimientos de forma remota

Es posible ejecutar procedimientos en otro SQL Server desde el SQL Server local. Una vez configurados ambos servidores de forma adecuada, puede ejecutar cualquier procedimiento en el SQL Server remoto con sólo usar el nombre del servidor como parte del identificador. Por ejemplo, para ejecutar un procedimiento llamado remoteproc en un servidor denominado GATEWAY:

exec gateway.remotedb.dbo.remoteproc

Consulte la Guía de Administración del Sistema para obtener información sobre cómo configurar los SQL Server local y remoto para la ejecución remota de procedimientos. Es posible pasar uno o más valores como parámetros a un procedimiento remoto desde el lote o el procedimiento que contiene la instrucción execute para el procedimiento remoto. Los resultados del SQL Server remoto aparecen en el terminal local.

El estado de retorno de los procedimientos, descritos en las secciones siguientes, puede utilizarse para capturar y transmitir mensajes de información sobre el estado de ejecución de los procedimientos.

Warning! Las llamadas de procedimientos remotos no se consideran parte de una transacción. En consecuencia, si ejecuta una llamada de procedimientos remotos como parte de una transacción y luego revierte la transacción, los cambios realizados por la llamada en un SQL Server remoto no se revierten.

Obtención de información a partir de procedimientos almacenados

Los procedimientos almacenados muestran un "estado de retorno" que indica si se han ejecutado correctamente o, en caso contrario, las razones del fallo. Este valor puede almacenarse en una variable cuando se llama a un procedimiento y utilizarse en futuras instrucciones Transact-SQL. Los valores del estado de retorno definidos por SQL Server para fallos se encuentran en la escala de -1 a -99; los usuarios pueden definir sus propios valores de estado de retorno fuera de esta escala.

Otra forma en la que los procedimientos almacenados pueden devolver información al solicitante es mediante los parámetros de retorno. Los parámetros designados como parámetros de retorno en las instrucciones create procedure y execute informan sobre los valores de parámetro al solicitante. Después el solicitante puede utilizar instrucciones condicionales para verificar el valor devuelto.

El estado de retorno y los parámetros de retorno permiten modularizar los procedimientos almacenados. Un conjunto de instrucciones SQL usadas por varios procedimientos almacenados puede crearse como un solo procedimiento que devuelve su estado de ejecución o los valores de sus parámetros al procedimiento de llamada. Por ejemplo, muchos de los procedimientos del sistema suministrados por SQL Server ejecutan un procedimiento que verifica que determinados parámetros son identificadores válidos.

Las llamadas de procedimientos remotos, que son procedimientos almacenados ejecutados en un SQL Server remoto, también devuelven ambos tipos de información. Todos los ejemplos que se muestran más abajo se podrían ejecutar de forma remota si la sintaxis de la instrucción execute incluyese el servidor, la base de datos y los nombres de los propietarios, así como el nombre del procedimiento.

Estado de retorno

Los procedimientos almacenados pueden devolver un valor entero llamado estado de retorno . Este estado indica que el procedimiento se ha realizado correctamente, o indica la razón del fallo. SQL Server tiene un conjunto definido de valores de

Page 216: 80575032 Libro de SQL y Tl SQL Excelente

Page 216 of 280

retorno. Los usuarios también pueden definir sus propios valores de retorno. A continuación se muestra un ejemplo de un lote que utiliza el formato de la instrucción execute que devuelve el estado:

declare @status int

execute @status = pub_info

select @status

El estado de ejecución del procedimiento pub_info se almacena en la variable @ status . Este ejemplo solamente imprime el valor con una instrucción select ; ejemplos posteriores utilizan este valor de retorno en cláusulas condicionales.

Valores de estado de retorno reservados

SQL Server reserva el 0 para indicar un retorno correcto y los valores negativos entre -1 y -99 para indicar diferentes razones de fallo. Los números 0 y -1 a -14 están en uso:

Tabla 14-1: Valores de estado de retorno reservados

Valor Significado

0 Procedimiento ejecutado sin error

-1 Falta objeto

-2 Error de tipo de datos

-3 Se eligió un proceso como víctima de un bloqueo insoluble

-4 Error de permiso

-5 Error de sintaxis

-6 Errores de usuario diversos

-7 Error de recursos, como espacio insuficiente

-8 Problema interno no fatal

-9 Se ha alcanzado el límite del sistema

-10 Inconsistencia interna fatal

-11 Inconsistencia interna fatal

-12 La tabla o el índice están corrutpos

-13 La base de datos está corrupta

-14 Error de hardware

Los valores entre -15 y -99 están reservados para su uso futuro por parte de SQL Server.

Si se produce más de un error durante la ejecución, se devolverá el estado que tenga el valor absoluto más alto.

Valores de retorno generados por el usuario

El usuario puede generar sus propios valores de retorno en procedimientos almacenados añadiendo un parámetro a la instrucción return . Los números entre 0 y -99 están reservados para su uso por parte de SQL Server; pueden utilizarse todos los demás números enteros. El siguiente ejemplo devuelve 1 cuando un libro tiene un contrato válido y 2 en todos los demás casos:

create proc checkcontract @titleid tid

as

if (select contract from titles where

title_id = @titleid) = 1

return 1

else

return 2

El siguiente procedimiento almacenado llama a checkcontract y utiliza cláusulas condicionales para verificar el estado de retorno:

create proc get_au_stat @titleid tid

as

Page 217: 80575032 Libro de SQL y Tl SQL Excelente

Page 217 of 280

declare @retvalue int

execute @retvalue = checkcontract @titleid

if (@retvalue = 1)

print "Contract is valid"

else

print "There is not a valid contract"

A continuación se muestran los resultados de ejecutar get_au_stat con la title_id de un libro con un contrato válido:

get_au_stat "MC2222"

Contract is valid

Verificación de roles en procedimientos

Si un procedimiento almacenado realiza tareas relacionadas con la administración del sistema o la seguridad, es posible que desee asegurarse de que sólo los usuarios con un rol específico puedan ejecutarlo (consulte la Guía del Usuario de las Características de Seguridad para obtener información sobre roles). La función proc_role permite verificar los roles cuando se ejecuta el procedimiento. proc_role devuelve 1 si el usuario posee el rol especificado. Los nombres de rol son sa_role, sso_role y oper_role .

A continuación se muestra un ejemplo que utiliza proc_role en el procedimiento almacenado test_proc para que la persona solicitante sea el administrador del sistema:

create proc test_proc

as

if (proc_role("sa_role") = 0)

begin

print "You don't have the right role"

return -1

end

else

print "You have SA role"

return 0

Parámetros de retorno

Cuando las instrucciones create procedure y execute incluyen la opción output con un nombre de parámetro, el procedimiento devuelve un valor al solicitante, que puede ser un lote SQL u otro procedimiento almacenado. El valor devuelto puede utilizarse en instrucciones adicionales en el lote o el procedimiento de llamada. Cuando se usan parámetros de retorno en una instrucción execute que forma parte de un lote, los valores de retorno se imprimen con un encabezado antes de que se ejecuten las instrucciones subsiguientes del lote.

Este procedimiento almacenado realiza la multiplicación con dos valores enteros. El tercer valor entero, @ result , se define como un parámetro output :

create procedure mathtutor @mult1 int, @mult2 int,

@result int output

as

select @result = @mult1 * @mult2

Para utilizar mathtutor a fin de poner en cifras un problema de multiplicación, debe declarar la variable @result e incluirla en la instrucción execute . La adición de la palabra clave output a la instrucción execute muestra el valor de los parámetros de retorno.

declare @result int

exec mathtutor 5, 6, @result output

(return status = 0)

Return parameters:

-----------

30

Si quisiera adivinar la respuesta y ejecutar este procedimiento proporcionando tres valores enteros, no vería los resultados de la multiplicación. La instrucción select del procedimiento asigna valores, pero no imprime:

Page 218: 80575032 Libro de SQL y Tl SQL Excelente

Page 218 of 280

mathtutor 5, 6, 32

(return status = 0)

El valor del parámetro output debe pasarse como una variable, no como una constante. Este ejemplo declara la variable @ guess para almacenar el valor que debe pasarse a mathtutor para su uso en @ result . SQL Server imprime los parámetros de retorno:

declare @guess int

select @guess = 32

exec mathtutor 5, 6, @result = @guess output

(1 row affected)

(return status = 0)

Return parameters:

@result

-----------

30

El valor del parámetro de retorno siempre se indica, tanto si ha cambiado su valor como si no. Tenga en cuenta que:

En el ejemplo anterior, el parámetro output @ result debe pasarse como "@ parameter = @ variable ". Si no fuera el último parámetro pasado, los parámetros subsiguientes tendrían que pasarse como "@ parameter = value ".

@ result no tiene que declararse en el lote de llamada; es el nombre de un parámetro que ha de pasarse a mathtutor .

Aunque el valor cambiado de @ result se devuelve al solicitante en la variable asignada en la instrucción execute , en este caso @ guess , se muestra bajo su propio encabezado, es decir, @ result .

Si quiere utilizar el valor inicial de @ guess en cláusulas condicionales después de la instrucción execute , debe almacenarlo en otro nombre de variable durante la llamada al procedimiento. El siguiente ejemplo ilustra los últimos dos puntos utilizando @ store para mantener el valor de la variable durante la ejecución del procedimiento almacenado y empleando el "nuevo" valor devuelto de @ guess en cláusulas condicionales:

declare @guess int

declare @store int

select @guess = 32

select @store = @guess

execute mathtutor 5, 6, @result = @guess output

select Your_answer = @store, Right_answer = @guess

if @guess = @store

print "Right-o"

else

print "Wrong, wrong, wrong!"

(1 row affected)

(1 row affected)

(return status = 0)

Return parameters:

@result

-----------

30

Your_answer Right_answer

----------- ------------

32 30

(1 row affected)

Wrong, wrong, wrong!

A continuación se muestra un procedimiento almacenado que verifica si las nuevas ventas de libros harían que el porcentaje de derechos de autor de un autor cambiase. El parámetro @ pc está definido como un parámetro output :

create proc roy_check @title tid, @newsales int,

@pc int output

as

declare @newtotal int

select @newtotal = (select titles.total_sales + @newsales

Page 219: 80575032 Libro de SQL y Tl SQL Excelente

Page 219 of 280

from titles where title_id = @title)

select @pc = royalty from roysched

where @newtotal >= roysched.lorange and

@newtotal < roysched.hirange

and roysched.title_id = @title

El siguiente lote SQL llama al procedimiento roy_check , después de asignar un valor a la variable percent . Los parámetros de retorno se imprimen antes de que se ejecute la siguiente instrucción del lote:

declare @percent int

select @percent = 10

execute roy_check "BU1032", 1050, @pc = @percent output

select Percent = @percent

go

(1 row affected)

(return status = 0)

Return parameters:

@pc

-----------

12

Percent

-----------

12

(1 row affected)

El siguiente procedimiento almacenado llama al procedimiento roy_check y utiliza el valor de retorno para percent en una cláusula condicional:

create proc newsales @title tid, @newsales int

as

declare @percent int

declare @stor_pc int

select @percent = (select royalty from roysched, titles

where roysched.title_id = @title

and total_sales >= roysched.lorange

and total_sales < roysched.hirange

and roysched.title_id=titles.title_id)

select @stor_pc = @percent

execute roy_check @title, @newsales, @pc = @percent

output

if

@stor_pc != @percent

begin

print "Royalty is changed"

select Percent = @percent

end

else

print "Royalty is the same"

Si ejecuta este procedimiento almacenado con los mismos parámetros utilizados en el lote anterior, verá estos resultados:

execute newsales "BU1032", 1050

Royalty is changed

Percent

-----------

12

(1 row affected, return status = 0)

En los dos ejemplos anteriores que llaman a roy_check , @ pc es el nombre del parámetro que se pasa a roy_check y @percent es la variable que contiene la salida. Cuando el procedimiento almacenado newsales ejecuta roy_check , el valor devuelto en @percent puede cambiar dependiendo de los otros parámetros que se pasen. Si quiere comparar el valor devuelto de percent con el valor inicial de @ pc , debe almacenar el valor inicial en otra variable. El ejemplo anterior lo guardó en stor_pc .

Pase de valores en parámetros

Page 220: 80575032 Libro de SQL y Tl SQL Excelente

Page 220 of 280

Los valores pasados en los parámetros deben tener este formato:

@ parameter = @ variable

No pueden pasarse constantes; debe existir un nombre de variable que "reciba" el valor de retorno. Los parámetros pueden ser de cualquier tipo de datos de SQL Server, excepto text e image .

Note: Si el procedimiento almacenado requiere varios parámetros, pase el parámetro del valor de retorno en último lugar en la instrucción execute o pase todos los parámetros subsiguientes con el formato "@parameter = value".

La palabra clave output

La palabra clave output puede abreviarse como out , del mismo modo que execute puede acortarse como exec .

Un procedimiento almacenado puede devolver varios valores; cada uno debe definirse como una variable output en el procedimiento almacenado y en las instrucciones de llamada:

exec myproc @a = @myvara out, @b = @myvarb out

Si especifica output mientras ejecuta un procedimiento y el parámetro no se define utilizando output en el procedimiento almacenado, aparecerá un mensaje de error. No es un error llamar a un procedimiento que incluya especificaciones de valor de retorno sin solicitar los valores de retorno con output . Sin embargo, no se obtendrán los valores de retorno. El autor del procedimiento almacenado controla la información a la que pueden acceder los usuarios y éstos tienen control sobre sus variables.

Reglas asociadas a procedimientos almacenados

Algunas reglas adicionales para la creación de procedimientos almacenados son:

Las instrucciones create procedure no pueden combinarse con otras instrucciones en un solo lote.

La definición create procedure propiamente dicha puede incluir cualquier número y tipo de instrucción SQL, con la excepción de use y estas instrucciones create : create view create default create rule create trigger create procedure

Se pueden crear otros objetos de base de datos dentro de un procedimiento. Es posible hacer referencia a un objeto creado en el mismo procedimiento, siempre que se cree antes de hacer referencia a él. La instrucción create del objeto debe ocupar la primera posición en el orden real de las instrucciones del procedimiento.

En un procedimiento almacenado, no es posible crear un objeto, omitirlo y después crear otro con el mismo nombre.

SQL Server crea los objetos definidos en un procedimiento almacenado cuando el procedimiento se ejecuta, no cuando se compila.

Si ejecuta un procedimiento que llama a otro, el procedimiento llamado puede acceder a los objetos creados por el primer procedimiento.

Se puede hacer referencia a tablas temporales dentro de un procedimiento.

Si crea una tabla temporal dentro de un procedimiento, la tabla sólo existe para ese procedimiento y desaparece al salir de éste.

El número máximo de parámetros de un procedimiento almacenado es de 255.

El número máximo de variables locales y globales de un procedimiento sólo está limitado por la memoria disponible.

Calificación de nombres dentro de procedimientos

Dentro de un procedimiento almacenado, los nombres de objeto utilizados con determinados comandos deben calificarse con el nombre del propietario del objeto si otros usuarios van a hacer uso del procedimiento almacenado. Estos comandos son: alter table , create table , drop table , truncate table , create index , drop index , update statistic s , dbcc . Los nombres de objeto usados con otras instrucciones, como select o insert , dentro de un procedimiento almacenado no necesitan estar calificados porque los nombres se resuelven cuando se compila el procedimiento.

Por ejemplo, el usuario "mary" , que posee la tabla marytab , debería calificar el nombre de su tabla cuando se utilice con uno de estos comandos si quiere que otros usuarios puedan ejecutar el procedimiento donde se emplea la tabla:

Page 221: 80575032 Libro de SQL y Tl SQL Excelente

Page 221 of 280

create procedure p1

as

create index marytab_ind

on mary.marytab(col1)

El motivo de esta regla es que los nombres de objeto se resuelven cuando se ejecuta el procedimiento. Si marytab no está calificada y el usuario " john" intenta ejecutar el procedimiento, SQL Server busca una tabla llamada marytab propiedad de John. El ejemplo anterior muestra el uso correcto: indica a SQL Server que busque una tabla llamada marytab propiedad de Mary.

Omisión de procedimientos almacenados

Los procedimientos se quitan con el comando drop procedure , cuya sintaxis es:

drop procedure [ owner .] procedure_name

[, [ owner .] procedure_name ]...

Si un procedimiento almacenado llama a otro procedimiento almacenado que se ha omitido, SQL Server muestra un mensaje de error. Sin embargo, si se define un procedimiento con el mismo nombre para reemplazar al omitido, otros procedimientos que hagan referencia a él podrán llamarlo sin ningún problema.

Es posible omitir un grupo de procedimientos, es decir, varios procedimientos con el mismo nombre pero con sufijos number diferentes, mediante una sola instrucción drop procedure . Una vez agrupados los procedimientos, los procedimientos pertenecientes al grupo no podrán omitirse de forma individual.

Cambio de nombre de los procedimientos almacenados

Se puede cambiar el nombre de un procedimiento almacenado mediante el procedimiento del sistema sp_rename , cuya sintaxis es la siguiente:

sp_rename objname , newname

Por ejemplo, para cambiar el nombre de showall a countall :

sp_rename showall, countall

Lógicamente, el nombre nuevo debe ajustarse a las reglas para identificadores. El usuario sólo puede cambiar el nombre de los procedimientos almacenados que sean de su propiedad. El propietario de la base de datos puede cambiar el nombre del procedimiento almacenado de cualquier usuario. El procedimiento almacenado deberá estar en la base de datos actual.

Cambio de nombre de los objetos referenciados por procedimientos

Es necesario omitir y volver a crear un procedimiento si se cambia el nombre de cualquiera de los objetos a los que hace referencia. Un procedimiento que hace referencia a una tabla o una vista cuyos nombres se han cambiado puede parecer que funciona de forma correcta durante un tiempo. De hecho, sólo funciona hasta que SQL Server lo recompila. La recompilación tiene lugar por muchas razones y sin notificarse al usuario.

Utilice sp_depends para obtener un informe sobre los objetos a los que hace referencia un procedimiento.

Uso de procedimientos almacenados como mecanismos de seguridad

Es posible usar los procedimientos almacenados como mecanismos de seguridad a fin de controlar el acceso a la información de las tablas y la capacidad para efectuar modificaciones en los datos. Por ejemplo, puede denegar a otros usuarios el permiso para emplear el comando select en una tabla que es suya y crear un procedimiento almacenado que les permita visualizar sólo determinadas filas o columnas. También puede utilizar los procedimientos almacenados para limitar las instrucciones update , delete o insert .

La persona que posee el procedimiento almacenado debe ser propietario de la tabla o vista usada en el procedimiento. Ni siquiera el administrador del sistema puede generar un procedimiento almacenado para realizar operaciones en las tablas de otro usuario si no ha recibido permiso sobre ellas.

Page 222: 80575032 Libro de SQL y Tl SQL Excelente

Page 222 of 280

Para obtener información sobre cómo conceder y revocar permisos de procedimientos almacenados y otros objetos de base de datos, consulte la Guía del Usuario de las Características de Seguridad .

Procedimientos del sistema

Los procedimientos del sistema se suministran para comodidad del usuario como:

Métodos abreviados para la recuperación de información de las tablas del sistema.

Mecanismos para llevar a cabo la administración de la base de datos y otras tareas que implican la actualización de tablas del sistema.

La mayor parte del tiempo, las tablas del sistema sólo se actualizan mediante procedimientos del sistema. Un administrador del sistema puede permitir actualizaciones directas en las tablas del sistema cambiando una variable de configuración y emitiendo el comando reconfigure with override . Consulte la Guía de Administración del Sistema para obtener información detallada.

Los nombres de todos los procedimientos del sistema empiezan por "sp_". Se crean mediante el guión installmaster en la base de datos sybsystemprocs durante la instalación de SQL Server.

Los procedimientos del sistema pueden ejecutarse desde cualquier base de datos. Si ejecuta un procedimiento del sistema desde una base de datos distinta de sybsystemprocs , cualquier referencia a las tablas del sistema se correlacionan con la base de datos desde la que se ejecuta el procedimiento. Por ejemplo, si el propietario de la base de datos pubs2 ejecuta sp_adduser desde pubs2 , el usuario nuevo se añade a pubs2 .. sysusers .

Cuando el parámetro de un procedimiento del sistema es un nombre de objeto y este nombre de objeto está calificado por un nombre de base de datos o de propietario, el nombre completo debe incluirse entre comillas dobles o simples.

Dado que los procedimientos del sistema se encuentran en la base de datos sybsystemprocs , sus permisos también se definen aquí. Algunos procedimientos del sistema sólo pueden ser ejecutados por los propietarios de las bases de datos. Estos procedimientos garantizan que el usuario que ejecuta el procedimiento es el propietario de la base de datos en la que se ejecutan.

Otros procedimientos del sistema pueden ser ejecutados por cualquier usuario al que se ha concedido permiso execute sobre ellos, pero este permiso debe otorgarse en la base de datos sybsystemprocs . Esta situación tiene dos consecuencias:

Un usuario puede tener permiso para ejecutar un procedimiento del sistema en todas las bases de datos o en ninguna.

El propietario de una base de datos de usuario no puede controlar directamente los permisos para procedimientos del sistema dentro de su propia base de datos.

Consulte la Guía de Administración del Sistema para obtener información detallada.

Administración de seguridad

Esta categoría incluye procedimientos para:

Añadir, omitir e informar sobre los logins a SQL Server

Añadir, omitir e informar sobre los usuarios, grupos y alias de una base de datos

Cambiar contraseñas y bases de datos predeterminadas

Cambiar el propietario de una base de datos

Añadir, omitir e informar sobre los servidores remotos que pueden acceder a este SQL Server

Añadir los nombres de los usuarios de servidores remotos que pueden acceder a este SQL Server

Los procedimientos de esta categoría son: sp_addlogin , sp_addalias , sp_addgroup , sp_adduser , sp_changedbowner , sp_changegroup , sp_droplogin , sp_dropalias , sp_dropgroup , sp_dropuser , sp_helpgroup , sp_helprotect , sp_helpuser , sp_password .

Servidores remotos

Esta categoría incluye procedimientos para:

Añadir, omitir e informar sobre los servidores remotos que pueden acceder a este SQL Server

Page 223: 80575032 Libro de SQL y Tl SQL Excelente

Page 223 of 280

Añadir los nombres de los usuarios de servidores remotos que pueden acceder a este SQL Server

Los procedimientos de esta categoría son: sp_addremotelogin , sp_addserver , sp_dropremotelogin , sp_dropserver , sp_helpremotelogin , sp_helpserver , sp_remoteoption , sp_serveroption .

Definición de datos y objetos de base de datos

Esta categoría incluye procedimientos para:

Vincular y desvincular reglas y valores predeterminados

Añadir, omitir e informar sobre claves primarias, externas y comunes

Añadir, omitir e informar sobre los tipos de datos definidos por el usuario

Cambiar el nombre de objetos de base de datos y tipos de datos definidos por el usuario

Volver a optimizar procedimientos almacenados y disparadores

Informar sobre objetos de base de datos, tipos de datos definidos por el usuario, dependencias entre objetos de base de datos, bases de datos, índices y espacio utilizado por tablas e índices

Los procedimientos de esta categoría son: sp_bindefault , sp_bindrule , sp_unbindefault , sp_unbindrule , sp_foreignkey , sp_primarykey , sp_commonkey , sp_dropkey , sp_depends , sp_addtype , sp_droptype , sp_rename , sp_spaceused , sp_help , sp_helpdb , sp_helpindex , sp_helpjoins , sp_helpkey , sp_helptext , sp_indsuspect , sp_recompile .

Mensajes definidos por el usuario

Esta categoría incluye procedimientos para:

Añadir mensajes definidos por el usuario a la tabla sysusermessages de una base de datos del usuario

Omitir mensajes definidos por el usuario de sysusermessages

Recuperar mensajes de sysusermessages o sysmessages de la base de datos master para su uso en instrucciones print y raiserror

Los procedimientos de esta categoría son: sp_addmessage , sp_dropmessage y sp_getmessage .

Administración del sistema

Esta categoría incluye procedimientos para:

Añadir, omitir e informar sobre dispositivos de bases de datos y de volcado

Informar sobre bloqueos, las opciones de base de datos definidas y los usuarios que están ejecutando procesos

Cambiar e informar sobre variables de configuración

Controlar de la actividad del SQL Server

Los procedimientos de esta categoría son: sp_addumpdevice , sp_dropdevice , sp_helpdevice , sp_helpsort sp_logdevice , sp_dboption , sp_diskdefault , sp_configure , sp_monitor , sp_lock, sp_who .

Encontrará más información sobre los procedimientos del sistema que llevan a cabo estas tareas administrativas en la Guía de Administración del Sistema . Para obtener información completa sobre los procedimientos del sistema, consulte el Manual de Referencia de SQL Server .

Obtención de información sobre procedimientos almacenados

Varios procedimientos del sistema proporcionan información sobre procedimientos almacenados a partir de las tablas del sistema.

sp_help

Se puede obtener un informe sobre un procedimiento almacenado con el procedimiento del sistema sp_help . Por ejemplo, se puede obtener información sobre el procedimiento almacenado byroyalty , que forma parte de la base de datos pubs2 , de la siguiente forma:

Page 224: 80575032 Libro de SQL y Tl SQL Excelente

Page 224 of 280

sp_help byroyalty

Name Owner type Created_on

-------- ------ ---------------- -------------------

byroyalty dbo stored procedure Feb 9 1987 3:56PM

Data_located_on_segment When_created

--------------------------- --------------------

Parameter_name Type Length Param_order

-------------- ------ ------ -----------

@percentage int 4 1

(return status = 0)

Se puede obtener ayuda sobre un procedimiento del sistema ejecutando sp_help al utilizar la base de datos master .

sp_helptext

Para mostrar el texto de la instrucción create procedure , ejecute el procedimiento del sistema sp_helptext :

sp_helptext byroyalty

# Lines of Text

---------------

1

(1 row affected)

text

---------------------------------------------------

create procedure byroyalty @percentage int

as

select au_id from titleauthor

where titleauthor.royaltyper = @percentage

(1 row affected, return status = 0)

Es posible ver el texto de un procedimiento del sistema ejecutando sp_helptext al utilizar la base de datos sybsystemprocs .

sp_depends

El procedimiento del sistema sp_depends muestra todos los procedimientos almacenados que hacen referencia al objeto especificado por el usuario, o todos los procedimientos de los que depende. Este comando muestra todos los objetos a los que hace referencia el procedimiento almacenado byroyalty creado por el usuario:

sp_depends byroyalty

Cosas a las que hace referencia el objeto en la base de datos actual.

object type updated selected

---------------- ----------- --------- --------

dbo.titleauthor user table no no

(return status = 0)

La siguiente instrucción utiliza sp_depends para mostrar todos los objetos que hacen referencia a la tabla titleauthor :

sp_depends titleauthor

Cosas incluidas en la base de datos actual que hacen referencia al objeto. object type

-------------- ------------------

dbo.titleview view

dbo.reptq2 stored procedure

dbo.byroyalty stored procedure

(return status = 0)

Debe omitir y volver a crear el procedimiento si el nombre de algunos de los objetos a los que hace referencia ha cambiado.

Los procedimientos del sistema se explican brevemente en "Procedimientos del sistema". Para obtener información completa sobre los procedimientos del sistema, consulte el Manual de Referencia de SQL Server .

Page 225: 80575032 Libro de SQL y Tl SQL Excelente

Page 225 of 280

Chapter 15

Disparadores: imposición de la integridad de referencia

Los disparadores pueden usarse para imponer la integridad de referencia de los datos en toda la base de datos. Los disparadores también permiten realizar cambios "en cascada" en tablas relacionadas, imponer restricciones de columna más complejas que las permitidas por las reglas, comparar los resultados de las modificaciones de datos y llevar a cabo una acción resultante.

En este capítulo se trata lo siguiente:

Introducción general a los disparadores

Creación y omisión de disparadores

Forma en que los disparadores imponen la integridad de referencia de los datos en toda la base de datos

Reglas asociadas a los disparadores

Obtención de información sobre disparadores

Definición de disparador

Creación de disparadores

Omisión de disparadores

Uso de disparadores para mantener la integridad de referencia

Consideraciones sobre filas múltiples

Reversión de disparadores

Anidación de disparadores

Reglas asociadas a los disparadores

Obtención de información sobre disparadores

Definición de disparador

Un disparador es un tipo especial de procedimiento almacenado que se ejecuta cuando se insertan, eliminan o actualizan datos de una tabla especificada. Los disparadores pueden ayudar a mantener la integridad de referencia de los datos conservando la consistencia entre los datos relacionados lógicamente de distintas tablas. Integridad de referencia significa que los valores de las claves primarias y los valores correspondientes de las claves externas deben coincidir de forma exacta.

La principal ventaja de los disparadores es que son automáticos : funcionan cualquiera sea el origen de la modificación de los datos, una introducción de datos por parte de un empleado o una acción de una aplicación. Cada disparador es específico de una o más operaciones de modificación de datos, update , insert o delete . El disparador se ejecuta una vez por cada instrucción SQL.

Un disparador se "dispara" sólo cuando la instrucción de modificación de datos finaliza y SQL Server verifica la posible violación de tipos de datos, reglas o restricciones de integridad. El disparador y la instrucción que lo "dispara" se consideran una sola transacción que puede revertirse desde dentro del disparador. Si se detecta un error grave, se revierte toda la transacción.

Situaciones en las que los disparadores son de mayor utilidad:

Los disparadores pueden realizar cambios "en cascada" a lo largo de las tablas relacionadas de la base de datos. Por ejemplo, un disparador de eliminación de la columna title_id de la tabla titles puede originar una eliminación correspondiente de las filas coincidentes de otras tablas, usando title_id como clave única para localizar las filas de titleauthor , sales y roysched .

Los disparadores pueden no permitir, o "revertir", los cambios que violen la integridad de referencia, cancelando la transacción de modificación de datos intentada. Este tipo de disparador puede activarse si intenta insertar una clave externa que no coincide con su clave primaria correspondiente. Por ejemplo, podría crear un disparador de inserción en titleauthor que revirtiese cualquier inserción si el nuevo valor titleauthor.title_id no coincidiese con alguno de los valores de titles.title_id .

Los disparadores pueden imponer restricciones de mucha mayor complejidad que las definidas con las reglas. Al contrario de lo que ocurre con las reglas, los disparadores pueden hacer referencia a columnas u objetos de base de datos. Por ejemplo, un disparador puede revertir actualizaciones que intenten incrementar el precio de un libro en más de un 1% del anticipo.

Los disparadores pueden llevar a cabo análisis de hipótesis sencillos. Por ejemplo, un disparador puede comparar el estado de una tabla antes y después de una modificación de datos y llevar a cabo acciones basándose en esa comparación.

Page 226: 80575032 Libro de SQL y Tl SQL Excelente

Page 226 of 280

En este capítulo se resume la sintaxis de los disparadores, se explica cómo usarlos y se proporcionan ejemplos. Es posible que quiera utilizar estos ejemplos como plantillas para otros disparadores. En la sección final de este capítulo se describen las reglas relacionadas con el uso de disparadores y se explican los procedimientos del sistema que proporcionan ayuda con los disparadores.

Note: Salvo el disparador llamado deltitle , los disparadores tratados en este capítulo no están incluidos en la base de datos pubs2 entregada con la copia de SQL Server. Para trabajar con los ejemplos mostrados en este capítulo, cree cada ejemplo de disparador escribiendo la instrucción create trigger. Cada disparador nuevo para la misma operación ( insert , update o delete ) de una tabla o columna escribe sobre el disparador anterior sin avisar, y los disparadores antiguos se omiten de forma automática.

Comparación de disparadores y restricciones de integridad

Como alternativa a los disparadores, es posible usar la restricción de integridad de referencia de la instrucción create table para imponer la integridad de referencia en las tablas de la base de datos. Sin embargo, las restricciones de integridad de referencia se diferencian de los disparadores en que no pueden llevar a cabo las siguientes tareas (al igual que se ha descrito anteriormente):

Efectuar cambios "en cascada" en las tablas relacionadas de la base de datos

Imponer restricciones complejas haciendo referencia a otras columnas u objetos de base de datos

Realizar análisis de hipótesis

Además, las restricciones de integridad de referencia no revierten la transacción actual como resultado de la imposición de la integridad de datos. Con los disparadores, la transacción se puede revertir o continuar según la forma en que se manipule la integridad de referencia. Para obtener información sobre transacciones, consulte el Capítulo 17, "Transacciones: mantenimiento de la consistencia y recuperación de datos".

Si la aplicación requiere una de las tareas anteriores, deberá usar disparadores. De lo contrario, las restricciones de integridad de referencia ofrecen un método más sencillo para imponer la integridad de los datos. Tenga presente que SQL Server verifica las restricciones de integridad de referencia antes que los disparadores, por lo que una instrucción de modificación de datos que viole la restricción no dispara el disparador también. Para obtener más información sobre restricciones de integridad de referencia, consulte el Capítulo 7, "Creación de bases de datos y tablas".

Creación de disparadores

Un disparador es un objeto de base de datos. Cuando se crea un disparador, se especifica la tabla y los comandos de modificación de datos que deben "disparar", o activar, el disparador. Luego se indica la acción o acciones que debe llevar a cabo el disparador.

A continuación se muestra un ejemplo sencillo. Este disparador imprime un mensaje cada vez que alguien trata de insertar, eliminar o actualizar datos de la tabla titles :

create trigger t1

on titles

for insert, update, delete

as

print "Now modify the titleauthor table the same way."

Sintaxis de create trigger

A continuación se muestra la sintaxis completa de create trigger :

create trigger [ owner .] trigger_name

on [ owner .] table_name

{for {insert , update , delete}

as SQL_statements

O bien, usando la cláusula if update :

create trigger [ owner .] trigger_name

on [ owner .] table_name

for {insert , update}

as

[if update ( column_name )

Page 227: 80575032 Libro de SQL y Tl SQL Excelente

Page 227 of 280

[{and | or} update ( column_name )]...]

SQL_statements

[if update ( column_name )

[{and | or} update ( column_name )]...

SQL_statements ]...

La cláusula create crea el disparador y le asigna un nombre. El nombre del disparador debe cumplir con las reglas para identificadores.

La cláusula on indica el nombre de la tabla que activa el disparador. Esta tabla se denomina en ocasiones tabla de disparadores.

Los disparadores se crean en la base de datos actual, aunque pueden hacer referencia a objetos de otras bases de datos. El nombre de propietario que califica el nombre de disparador debe ser el mismo que el de la tabla. Nadie, excepto el propietario de la tabla, puede crear un disparador en una tabla. Si se indica el propietario de la tabla con el nombre de tabla en la cláusula create trigger o la cláusula on , también debe especificarse en la otra cláusula.

La cláusula for especifica los comandos de modificación de datos de la tabla de disparadores que activan el disparador. En el ejemplo anterior, la ejecución de insert , update o delete en titles hace que se imprima el mensaje.

Las instrucciones SQL indican las condiciones y acciones del disparador . Las condiciones del disparador especifican criterios adicionales que determinan si el comando insert , delete o update hará que se lleven a cabo las acciones del disparador. Las acciones de disparador múltiples de una cláusula if deben agruparse con begin y end .

Una cláusula if update verifica si existe una inserción o actualización para una columna en particular. En el caso de las actualizaciones, la cláusula if update da como resultado verdadero cuando el nombre de colmna se incluye en la cláusula set de una instrucción update , aunque la actualización no cambie el valor de la columna. if update no se utiliza con delete . Es posible especificar más de una columna, y usar más de una cláusula if update en una instrucción create trigger . Puesto que el nombre de tabla se especifica en la cláusula on , no debe usar el nombre de tabla delante del nombre de columna con if update .

Instrucciones SQL no permitidas en los disparadores

Dado que los disparadores se ejecutan como parte de la transacción, no se permiten las siguientes instrucciones en un disparador:

Todos los comandos create , incluidos create database , create table , create index , create procedure , create default , create rule , create trigger y create view

Todos los comandos drop

alter table y alter database

truncate table

grant y revoke

update statistics

reconfigure

load database y load transaction

disk init , disk mirror , disk refit , disk reinit , disk remirror , disk unmirror

select into

Omisión de disparadores

Se puede quitar un disparador omitiéndolo u omitiendo la tabla de disparadores a la que está asociado.

La sintaxis de drop trigger es:

drop trigger [ owner .] trigger_name

[, [owner.] trigger_name ]...

Cuando se omite una tabla, los disparadores asociados a ella se omiten automáticamente. El permiso drop trigger está asignado de forma predeterminada al propietario de la tabla de disparadores y no es transferible.

Uso de disparadores para mantener la integridad de referencia

Page 228: 80575032 Libro de SQL y Tl SQL Excelente

Page 228 of 280

Los disparadores se usan para mantener la integridad de referencia, que garantiza que los datos vitales de la base de datos, como el identificador único de unos datos determinados, sean precisos y puedan usarse conforme cambia la base de datos. La integridad referencial se coordina mediante el uso de claves primarias y externas.

La clave primaria es la columna o combinación de columnas que identifican de forma exclusiva una fila. Su valor no puede ser NULL, y debe tener un índice único. Una tabla con una clave primaria puede combinarse con las claves externas de otras tablas. La tabla de clave primaria puede considerarse como la maestra en una relación maestro-discípulo . En una base de datos puede haber numerosos grupos maestro-discípulo de este tipo.

Use el procedimiento del sistema sp_primarykey para marcar la clave primaria. Esto marca la clave para usarse con sp_helpjoins y la añade a la tabla syskeys .

En la base de datos pubs2 , por ejemplo, la columna title_id es la clave primaria de titles . Esta columna identifica de forma exclusiva los libros de titles y se combina con la columna title_id de titleauthor , salesdetail y roysched . La tabla titles es la tabla maestra en relación con titleauthor , salesdetail y roysched . El diagrama del Chapter 1, "The pubs2 Database," del Suplemento de Referencia de SQL Server muestra estas relaciones.

La clave externa es una columna o combinación de columnas cuyos valores coinciden con la clave primaria. No es necesario que la clave externa sea única. Con frecuencia esta clave tiene una relación de muchas-a-una con respecto a la clave primaria. Los valores de las claves externas deben ser copias de los valores de las claves primarias, es decir, los valores de las claves externas sólo pueden existir si también existen en las claves primarias. Una clave externa puede ser nula; si alguna parte de la clave externa compuesta es nula, la totalidad de la clave externa debe ser nula. Las tablas con claves externas se denominan con frecuencia tablas discípulas o dependientes de la tabla maestra.

Use el procedimiento sp_foreignkey para marcar las claves externas de la base de datos. Esto les asigna indicadores que permite utilizarlas con sp_helpjoins y otros procedimientos que hagan referencia a la tabla syskeys .

Las columnas title_id de titleauthor , salesdetail y roysched son claves externas; estas tablas son discípulas.

Funcionamiento de los disparadores

Los disparadores de integridad de referencia mantienen los valores de las claves externas en línea con los de las claves primarias. Cuando una modificación de datos afecta a una columna clave, los disparadores comparan los nuevos valores de columna con las claves relacionadas usando tablas de trabajo temporales llamadas tablas de verificación de disparadores. Cuando se escriben los disparadores, las comparaciones se basan en los datos almacenados temporalmente en las tablas de verificación de disparadores.

Contrastación de la modificación de datos respecto a las tablas de verificación de disparadores

En las instrucciones de los disparadores se usan dos tablas especiales: la tabla deleted (eliminada) y la tabla inserted (insertada). Se trata de tablas temporales usadas en la verificación de disparadores. Emplee estas tablas para comprobar los efectos de algunas modificaciones de datos y definir las condiciones de las acciones del disparador. No es posible alterar directamente los datos de las tablas de verificación de disparadores, pero se pueden usar las tablas en instrucciones select para detectar los efectos de una instrucción insert , update o delete .

La tabla deleted almacena copias de las filas afectadas por las instrucciones delete y update . Durante la ejecución de una instrucción delete o update , las filas se quitan de la tabla de disparadores y se transfieren a la tabla deleted . La tabla deleted y la tabla de disparadores no suelen tener filas en común.

La tabla inserted almacena copias de las filas afectadas por las instrucciones insert y update . Durante la ejecución de insert o update , se añaden filas nuevas a inserted y a la tabla de disparadores al mismo tiempo. Las filas de inserted son copias de las nuevas filas de la tabla de disparadores.

Una actualización con update es, en realidad, una eliminación seguida de una inserción; primero las filas antiguas se copian en la tabla deleted y luego las filas nuevas se copian en la tabla de disparadores y en la tabla inserted . La siguiente ilustración muestra el estado de las tablas de verificación de disparadores durante la ejecución de insert, delete y update.

Figure 15-4: Tablas de verificación de disparadores durante operaciones con insert, delete o update

Cuando defina las condiciones de los disparadores, use las tablas de verificación de disparadores que son adecuadas para la modificación de datos. Aunque no es un error hacer referencia a eliminated mientras se verifica una instrucción insert ni a inserted mientras se verifica una instrucción delete , estas tablas de verificación de disparadores no contendrán ninguna fila en estos casos.

Page 229: 80575032 Libro de SQL y Tl SQL Excelente

Page 229 of 280

Note: Cada disparador se activa una sola vez por consulta. Si las acciones de los disparadores dependen del número de filas afectadas por una modificación de datos, deberá usar pruebas, como examinar @@rowcount , para las modificaciones de datos de múltiples filas y llevar a cabo las acciones adecuadas.

Los siguientes ejemplos de disparadores albergarán las modificaciones de datos de múltiples filas cuando sea necesario. La variable global @@ rowcount , que almacena el "número de filas afectadas" por la última operación de modificación de datos, comprueba si se ha llevado a cabo una inserción, eliminación o actualización en múltiples filas. Si otra instrucción select precede a la verificación de @@ rowcount dentro del disparador, deberá usar variables locales para almacenar el valor a fin de examinarlo más adelante. Todas las instrucciones Transact-SQL que no devuelven valores vuelven a definir @@ rowcount en 0.

Ejemplo de disparador de inserción

Cuando se inserta una nueva fila de clave externa, es conveniente asegurarse de que la clave externa coincide con una clave primaria. El disparador debe verificar si existen combinaciones entre la fila o filas insertadas y las filas de la tabla de clave primaria, y luego revertir las inserciones de claves externas que no coincidan con una de las claves de la tabla de clave primaria. Este ejemplo revierte todos los cambios provocados por la instrucción insert ; en ejemplos posteriores se indica cómo rechazar de forma selectiva algunas modificaciones de datos.

Cuando tiene lugar la inserción, se añaden filas nuevas a la tabla de disparadores y a la tabla de verificación de disparadores inserted . Para verificar si las nuevas claves coinciden con alguna clave primaria, compruebe si existen combinaciones entre inserted y la tabla de clave primaria.

El siguiente disparador compara los valores title_id de la tabla inserted con los de la tabla titles . El disparador supone que va a realizar una entrada para la clave externa y que no va a introducir un valor nulo. Si la combinación falla, la transacción se revierte.

create trigger forinsertrig1

on salesdetail

for insert

as

if (select count(*)

from titles, inserted

where titles.title_id = inserted.title_id) !=

@@rowcount

/* cancelar la inserción e imprimir un mensaje.*/

begin

rollback transaction

print "No, a title_id does not exist in titles"

end

/* En caso contrario, permitirlo. */

else

print "Added! All title_id's exist in titles."

En este ejemplo, @@ rowcount hace referencia al número de filas añadidas a la tabla salesdetail . También es el número de filas añadidas a la tabla inserted . La verificación de si todos los valores title_id añadidos a salesdetail existen en la tabla titles se lleva a cabo combinando titles e inserted . Si el número de filas combinadas, que se determina mediante la consulta select count(*) , es diferente de @@ rowcount , una o varias inserciones son incorrectas y toda la transacción se cancela.

Este disparador imprime un mensaje si la inserción se revierte y otro si se acepta.

Ejemplo de disparador de eliminación

Cuando se elimina una fila de clave primaria, también deben eliminarse las filas de clave externa correspondientes de las tablas dependientes. Esto mantiene la integridad de referencia al garantizar la eliminación de las filas discípulas cuando se quita la fila maestra. Si esto no se hiciera, podría acabar con una base de datos que tuviera filas discípulas imposibles de recuperar o identificar. Se requiere un disparador que lleve a cabo una eliminación en cascada.

A continuación se muestra un ejemplo. Cuando se ejecuta una instrucción delete en titles , una o más filas salen de la tabla titles y se añaden a la eliminida. Un disparador puede comprobar las tablas dependientes ( titleauthor , salesdetail y roysched ) para ver si tienen filas con un valor title_id que coincida con los valores title_id quitados de titles y almacenados ahora en la tabla deleted. Si el disparador encuentra alguna fila de este tipo, la quita.

create trigger delcascadetrig

on titles

for delete

as

Page 230: 80575032 Libro de SQL y Tl SQL Excelente

Page 230 of 280

delete titleauthor

from titleauthor, deleted

where titleauthor.title_id = deleted.title_id

/* Quitar filas de titleauthor que

** coincidan con las filas eliminadas

** (títulos).*/

delete salesdetail

from salesdetail, deleted

where salesdetail.title_id = deleted.title_id

/* Quitar filas de salesdetail que

** coincidan con las filas eliminadas

** (títulos).*/

delete roysched

from roysched, deleted

where roysched.title_id = deleted.title_id

/* Quitar filas de roysched que

** coincidan con las filas eliminadas

** (títulos).*/

En la práctica, es posible que quiera conservar algunas de las filas discípulas. Esto puede ocurrir por razones de mantenimiento de historiales (para verificar cuántas ventas se han realizado en títulos que ya no se publican cuando estaban activos) o porque haya transacciones incompletas sobre las filas discípulas. Un disparador bien escrito debería tener en cuenta estos factores.

Por ejemplo, el disparador deltitle suministrado con la base de datos pubs2 evita la eliminación de una clave primaria si hay filas discípulas correspondientes a la misma en la tabla salesdetail . Este disparador conserva la capacidad de recuperar filas de salesdetail .

create trigger deltitle

on titles

for delete

as

if (select count(*)

from deleted, salesdetail

where salesdetail.title_id =

deleted.title_id) > 0

begin

rollback transaction

print "You can't delete a title with sales."

end

En este disparador, la fila o filas eliminadas de titles se verifican combinándolas con la tabla salesdetail . Si se encuentra una combinación, la transacción se cancela.

Ejemplos de disparador de actualización

Dado que una clave primaria es el identificador único de su fila y de las filas externas de otras tablas, un intento de actualizar una clave primaria debe realizarse con extremo cuidado. En este caso, desea proteger la integridad de referencia revirtiendo la actualización a no ser que se cumplan las condiciones especificadas.

Como norma general, es más adecuado prohibir cualquier cambio de edición de la clave primaria, por ejemplo, revocando todos los permisos para esa columna. Pero si desea prohibir las actualizaciones sólo en determinadas circunstancias, use un disparador.

Este disparador evita las actualizaciones de titles.title_id durante el fin de semana. La cláusula if update de stopupdatetrig permite centrarse en una columna concreta, titles.title_id . Las modificaciones de los datos de esa columna hacen que el disparador se active. Los cambios de los datos de otras columnas no. Cuando este disparador detecta una actualización que viola sus condiciones, cancela la actualización e imprime un mensaje. Si desea probar este disparador, sustituya el día actual de la semana por sábado ("Saturday") o domingo ("Sunday").

create trigger stopupdatetrig

on titles

for update

as

/* Si se intenta cambiar titles.title_id

** el sábado o domingo, se cancela la actualización.

*/

Page 231: 80575032 Libro de SQL y Tl SQL Excelente

Page 231 of 280

if update (title_id)

and datename(dw, getdate())

in ("Saturday", "Sunday")

begin

rollback transaction

print "We don't allow changes to"

print "primary keys on the weekend!"

end

También puede especificar acciones de disparador múltiples en más de una columna mediante if update . El siguiente ejemplo modifica stopupdatetrig a fin de incluir acciones de disparador adicionales para las actualizaciones realizadas en titles.price o titles.advance . Además de evitar las actualizaciones en la clave primaria durante los fines de semana, también las evita en el precio o anticipo de un título, a no ser que los ingresos totales de este título sobrepasen la cantidad del anticipo. Es posible usar el mismo nombre de disparador, ya que el disparador modificado sustituye al antiguo al volver a crearlo.

create trigger stopupdatetrig

on titles

for update

as

if update (title_id)

and datename(dw, getdate())

in ("Saturday", "Sunday")

begin

rollback transaction

print "We don't allow changes to"

print "primary keys on the weekend!"

end

if update (price) or update (advance)

if (select count(*) from inserted

where (inserted.price * inserted.total_sales)

< inserted.advance) > 0

begin

rollback transaction

print "We don't allow changes to price or"

print "advance for a title until its total"

print "revenue exceeds its latest advance."

end

Actualización de una clave externa

Un cambio o actualización únicamente en una clave externa constituye con toda probabilidad un error. Una clave externa no es más que una copia de la clave primaria; nunca deben ser independientes la una de la otra. Si por alguna razón desea permitir actualizaciones en una clave externa, es posible que quiera proteger la integridad creando un disparador que contraste las actualizaciones con la tabla master y las revierta si no coinciden con la clave primaria.

En el siguiente ejemplo, el disparador comprueba la existencia de dos fuentes posibles de error: puede ocurrir que title_id no esté siquiera en la tabla salesdetail , o que no esté en la tabla titles .

Este ejemplo usa instrucciones anidadas if...else . La primera instrucción if se cumple cuando el valor de la cláusula where de la instrucción update no coincide con ninguno de los valores existentes de salesdetail , es decir, la tabla inserted no contendrá ninguna fila y la selección devolverá un valor nulo. Si esta prueba se supera, la siguiente instrucción if comprueba si la fila o filas nuevas de la tabla inserted se combina con alguna title_id de la tabla titles . Si alguna de las filas no se combina, la transacción se revierte y se imprime un mensaje de error. Si la combinación se realiza con éxito, se imprime otro mensaje.

create trigger forupdatetrig

on salesdetail

for update

as

declare @row int

/* guardar valor de rowcount */

select @row = @@rowcount

if update (title_id)

begin

if (select distinct inserted.title_id

from inserted) is null

begin

rollback transaction

print "No! Old title_id must be in

salesdetail"

Page 232: 80575032 Libro de SQL y Tl SQL Excelente

Page 232 of 280

end

else

if (select count(*)

from titles, inserted

where titles.title_id =

inserted.title_id) != @row

begin

rollback transaction

print "No! New title_id not in titles"

end

else

print "salesdetail table updated"

end

Consideraciones sobre filas múltiples

Las consideraciones sobre filas múltiples son especialmente importantes en los casos en que la función del disparador es recalcular de forma automática los valores sumarios, es decir, llevar a cabo concordancias continuadas.

Los disparadores usados para mantener los valores sumarios deben contener cláusulas group by, o subconsultas que realicen agrupaciones implícitas, a fin de crear valores sumarios cuando se inserte, actualice o elimine más de una fila. Puesto que una cláusula group by impone una sobrecarga adicional, los siguientes ejemplos se han escrito para verificar si el valor de @@ rowcount es igual a uno, lo que significa que sólo se ha visto afectada una fila de la tabla de disparadores. Si @@ rowcount es igual a uno, las acciones del disparador se llevan a efecto sin la cláusula group by .

Este disparador de inserción actualiza la columna total_sales de la tabla titles cada vez que se añade una fila nueva a salesdetail . El disparador se activa cada vez que se registra una venta añadiendo una fila a la tabla salesdetail . Actualiza la columna total_sales de la tabla titles de modo que total_sales sea igual a su valor anterior más el valor añadido a salesdetail.qty . Esto mantiene actualizados los totales para las inserciones de salesdetail.qty .

create trigger intrig

on salesdetail

for insert as

/* verificar valor de @@rowcount */

if @@rowcount = 1

update titles

set total_sales = total_sales + qty

from inserted

where titles.title_id = inserted.title_id

else

/* cuando rowcount sea mayor que 1,

** usar una cláusula group by */

update titles

set total_sales =

total_sales + (select sum(qty)

from inserted

group by inserted.title_id

having titles.title_id = inserted.title_id)

El siguiente ejemplo es un disparador de eliminación que actualiza la columna total_sales de la tabla titles cada vez que se elimina una o más filas de salesdetail .

create trigger deltrig

on salesdetail

for delete

as

/* verificar valor de @@rowcount */

if @@rowcount = 1

update titles

set total_sales = total_sales - qty

from deleted

where titles.title_id = deleted.title_id

else

/* cuando rowcount sea mayor que 1,

** usar una cláusula group by */

update titles

set total_sales =

total_sales - (select sum(qty)

from deleted

Page 233: 80575032 Libro de SQL y Tl SQL Excelente

Page 233 of 280

group by deleted.title_id

having titles.title_id = deleted.title_id)

Este disparador se activa cada vez que se elimina una fila de la tabla salesdetail . Actualiza la columna total_sales de la tabla titles de modo que total_sales sea igual a su valor anterior menos el valor sustraído de salesdetail.qty .

El siguiente disparador de actualización actualiza la columna total_sales de la tabla titles cada vez que se actualiza el campo qty de una fila de salesdetail . No olvide que una actualización es una inserción seguida de una eliminación. Este disparador hace referencia a las tablas de verificación de disparadores inserted y deleted.

create trigger updtrig

on salesdetail

for update

as

if update (qty)

begin

/* verificar valor de @@rowcount */

if @@rowcount = 1

update titles

set total_sales = total_sales +

inserted.qty - deleted.qty

from inserted, deleted

where titles.title_id = inserted.title_id

and inserted.title_id = deleted.title_id

else

/* cuando rowcount sea mayor que 1,

** usar una cláusula group by */

begin

update titles

set total_sales = total_sales +

(select sum(qty)

from inserted

group by inserted.title_id

having titles.title_id =

inserted.title_id)

update titles

set total_sales = total_sales -

(select sum(qty)

from deleted

group by deleted.title_id

having titles.title_id =

deleted.title_id)

end

end

Disparador de inserción condicional

Los disparadores examinados hasta aquí han considerado cada instrucción de modificación de datos como un todo. Si una fila de una inserción de cuatro filas no era aceptable, la inserción en su conjunto se consideraba inaceptable y se revertía la transacción.

Sin embargo, no es necesario revertir todas las modificaciones de datos sólo porque algunas de ellas no son aceptables. El uso de una subconsulta correlacionada dentro de un disparador puede obligar al disparador a examinar las filas modificadas de una en una. Consulte el Capítulo 5, "Subconsultas: uso de consultas dentro de otras consultas", para obtener más información sobre las subconsultas correlacionadas. Entonces el disparador puede llevar a cabo acciones distintas en filas diferentes.

El ejemplo de disparador que se muestra a continuación supone la existencia de una tabla llamada newsales . Esta es su instrucción create :

create table newsales

(stor_id char(4) not null,

ord_num varchar(20) not null,

title_id tid not null,

qty smallint not null,

discount float not null)

Para verificar el disparador condicional, hay que insertar cuatro filas en la tabla newsales , . Dos de las filas de newsales tienen columnas title_id que no coinciden con ninguna de las ya existentes en la tabla titles . Estos son los datos:

Page 234: 80575032 Libro de SQL y Tl SQL Excelente

Page 234 of 280

newsales

stor_id ord_num title_id qty discount

------- ---------- --------- ---- ---------

7066 BA27619 PS1372 75 40.000000

7066 BA27619 BU7832 100 40.000000

7067 NB-1.242 PSxxxx 50 40.000000

7131 Asoap433 PSyyyy 50 40.000000

Cuando inserta datos de newsales en salesdetail , la instrucción es como sigue:

insert salesdetail

select * from newsales

En caso que se desee examinar cada uno de los registros que se intenta insertar, el disparador conditionalinsert analiza la inserción fila a fila y elimina las filas que no tienen una columna title_id en titles . A continuación se indica cómo hacerlo:

create trigger conditionalinsert

on salesdetail

for insert as

if

(select count(*) from titles, inserted

where titles.title_id = inserted.title_id)

!= @@rowcount

begin

delete salesdetail from salesdetail, inserted

where salesdetail.title_id = inserted.title_id

and inserted.title_id not in

(select title_id from titles)

print "Only records with matching title_ids

added."

end

La prueba de disparador es la misma que la del ejemplo intrig , pero la transacción no se revierte. En lugar de ello, el disparador elimina las filas no deseadas. Esta capacidad de borrar las filas que se acaban de insertar se basa en el orden en que se lleva a cabo el procesamiento cuando los disparadores se activan. Primero se insertan las filas en la tabla y en inserted , y luego se activa el disparador.

Reversión de disparadores

Es posible revertir los disparadores mediante las instrucciones rollback trigger o rollback transaction (si el disparador se activa como parte de una transacción). Sin embargo, rollback trigger sólo revierte el efecto del disparador y de la instrucción que lo activó. rollback transaction revierte la transacción en su totalidad. Por ejemplo:

begin tran

insert into publishers (pub_id) values ('9999')

insert into publishers (pub_id) values ('9998')

commit tran

Si la segunda instrucción insert hace que el disparador de publishers ejecute rollback trigger , sólo se verá afectada esa instrucción insert ; la primera instrucción insert no se revierte. Si, en cambio, ese disparador ejecuta rollback transaction , se revierten las dos instrucciones insert como parte de la transacción.

A continuación se indica la sintaxis de rollback trigger:

rollback trigger

[with raiserror_statement ]

La sintaxis de rollback transaction se describe en el Capítulo 17, "Transacciones: mantenimiento de la consistencia y recuperación de datos".

raiserror_statement especifica una instrucción raiserror que imprime un mensaje de error definido por el usuario y establece un indicador del sistema para registrar que se ha producido una situación de error. Esto ofrece la posibilidad de presentar un error al cliente cuando se ejecuta rollback trigger , de forma que el estado de transacción del error refleje la reversión. Por ejemplo:

Page 235: 80575032 Libro de SQL y Tl SQL Excelente

Page 235 of 280

rollback trigger with raiserror 25002

"title_id does not exist in titles table."

Para obtener más información sobre raiserror , consulte el Capítulo 13, "Uso de lotes y lenguaje de control de flujo".

Cuando se ejecuta rollback trigger , SQL Server aborta el comando en ejecución y detiene la ejecución del resto del disparador. Si el disparador que ejecuta rollback trigger está anidado dentro de otros disparadores, SQL Server revierte todo el trabajo realizado en estos disparadores hasta la actualización que activó el primer disparador, incluida ésta.

El siguiente ejemplo de disparador de inserción realiza una tarea similar a la del disparador forinsertrig1 descrito en la . Sin embargo, este disparador utiliza rollback trigger en lugar de rollback transaction para originar un error cuando revierte la inserción pero no la transacción.

create trigger forinsertrig2

on salesdetail

for insert

as

if (select count(*) from titles, inserted

where titles.title_id = inserted.title_id) !=

@@rowcount

rollback trigger with raiserror 25003

"Trigger rollback: salesdetail row not added

because a title_id does not exist in titles."

Cuando los disparadores que incluyen instrucciones rollback transaction se ejecutan desde un lote, dichos disparadores abortan el lote en su totalidad. En el siguiente ejemplo, si la instrucción insert activa un disparador que incluye una instrucción rollback transaction ( como forinsertrig1 ), la instrucción delete no se ejecutará, puesto que el lote se abortará:

insert salesdetail values ("7777", "JR123",

"PS9999", 75, 40)

delete salesdetail where stor_id = "7067"

Si los disparadores que incluyen instrucciones rollback transaction se activan desde dentro de una transacción definida por el usuario , rollback transaction revierte el lote en su totalidad. En el siguiente ejemplo, si la instrucción insert activa un disparador que incluye una instrucción rollback transaction , la instrucción update también se revertirá:

begin tran

update stores set payterms = "Net 30"

where stor_id = "8042"

insert salesdetail values ("7777", "JR123",

"PS9999", 75, 40)

Consulte el Capítulo 17, "Transacciones: mantenimiento de la consistencia y recuperación de datos", para obtener información sobre las transacciones definidas por el usuario.

SQL Server ignora una instrucción rollback trigger ejecutada fuera de un disparador y no emite la raiserror asociada con la instrucción. Sin embargo, una instrucción rollback trigger ejecutada fuera de un disparador, pero dentro de una transacción, genera un error que hace que SQL Server revierta la transacción y aborte el lote de instrucciones actual.

Anidación de disparadores

Los disparadores se pueden anidar a una profundidad de 16 niveles. La anidación se activa durante la instalación. El administrador del sistema puede activar y desactivar la anidación de disparadores con sp_configure . Para inhabilitar la anidación:

sp_configure "allow nested triggers", 0

Si la anidación de disparadores se habilita, un disparador que modifica una tabla en la que hay otro disparador activa el segundo disparador, que a su vez puede activar un tercer disparador, y así sucesivamente. Si cualquiera de los disparadores de la cadena desencadena un bucle infinito, el nivel de anidación se sobrepasa y el disparador se aborta. Los disparadores anidados pueden usarse para llevar a cabo funciones de mantenimiento como almacenar una copia de seguridad de las filas afectadas por un disparador anterior.

Por ejemplo, puede crear un disparador en titleauthor que guarde una copia de seguridad de las filas de titleauthor borradas por el disparador delcascadetrig . Con el disparador delcascadetrig en efecto, la eliminación de la title_id "PS2091" de titles

Page 236: 80575032 Libro de SQL y Tl SQL Excelente

Page 236 of 280

también elimina la fila o filas correspondientes de titleauthor . Para guardar los datos, puede crear un disparador delete en titleauthor que guarde los datos eliminados en otra tabla, del_save :

create trigger savedel

on titleauthor

for delete

as

insert del_save

select * from deleted

No conviene usar los disparadores en una secuencia dependiente de criterios de ordenación. Emplee disparadores independientes para efectuar las modificaciones de datos en cascada, como en el ejemplo anterior de delcascadetrig .

Note: Cuando se incluyen disparadores en una transacción, un fallo en cualquier nivel de un conjunto de disparadores anidados (incluido el mensaje de error de que se ha sobrepasado el nivel de anidación) cancela la totalidad de la transacción. Todas las modificaciones de datos se revierten. Proporcione sus disparadores con las instrucciones print o raiserror a fin de determinar dónde se ha producido el fallo.

La ejecución de rollback transaction en un disparador en cualquier nivel de anidación revierte los efectos de todos los disparadores y cancela la transacción completa. rollback trigger sólo afecta a los disparadores anidados y a la instrucción de modificación de datos que activó el primer disparador.

Recurrencia automática de disparadores

De forma predeterminada, un disparador no se llama a sí mismo de manera recurrente. Es decir, un disparador de actualización no se llama a sí mismo en respuesta a una segunda actualización de la misma tabla dentro del disparador. Si un disparador de actualización de una columna de una tabla tiene como resultado la actualización de otra columna, el disparador de actualización se activa una sola vez, no repetidamente. Sin embargo, es posible activar la opción allow self_recursion del comando set a fin de permitir que los disparadores se llamen a sí mismos de forma recurrente. La variable de configuración nested triggers también debe habilitarse para que se produzca la recurrencia automática.

El valor self_recursion permanece en efecto sólo mientras dura la sesión de cliente actual. Si la opción se define como parte de un disparador, su efecto queda limitado por el alcance del disparador que la define. Si el disparador que establece self_recursion on devuelve o hace que se active otro disparador, esta opción vuelve a definirse como off . Una vez que el disparador activa la opción self_recursion , puede repetirse varias veces si sus propias acciones hacen que se vuelva a activar a sí mismo, pero no puede sobrepasar el límite de 16 niveles de anidación.

Por ejemplo, suponga que la siguiente tabla new_budget existe en la base de datos pubs2 :

select * from new_budget

unit parent_unit budget

--------------- --------------- -------

one_department one_division 10

one_division company_wide 100

company_wide NULL 1000

(3 rows affected)

Cree un disparador que actualice new_budget de forma recurrente cada vez que se modifique la columna budget , como a continuación:

create trigger budget_change

on new_budget

for update as

if exists (select * from inserted

where parent_unit is not null)

begin

set self_recursion on

update new_budget

set new_budget.budget = new_budget.budget +

inserted.budget - deleted.budget

from inserted, deleted, new_budget

where new_budget.unit = inserted.parent_unit

and new_budget.unit = deleted.parent_unit

end

Page 237: 80575032 Libro de SQL y Tl SQL Excelente

Page 237 of 280

Si un usuario actualiza new_budget.budget incrementando el presupuesto de la unidad one_department en 3, SQL Server se comporta como sigue (suponiendo que esté habilitada la anidación de disparadores):

1. Al incrementar one_department de 10 a 13 se activa el disparador budget_change . 2. El disparador actualiza el presupuesto ("budget") del padre de one_department (en este caso, one_division ) de 100 a

103, lo que vuelve a activarlo. 3. El disparador actualiza el padre de one_division (en este caso, company_wide ) de 1000 a 1003, lo que hace que el

disparador se active por tercera vez. 4. El disparador intenta actualizar el padre de company_wide , pero, puesto que no existe (NULL), la última ejecución de

update nunca llega a producirse y el disparador no se activa, finalizando así la recurrencia automática. Se puede consultar new_budget para ver los resultados finales que se muestran a continuación:

select * from new_budget

unit parent_unit budget

--------------- --------------- -------

one_department one_division 13

one_division company_wide 103

company_wide NULL 1003

(3 rows affected)

También es posible ejecutar un disparador de forma recurrente de otras maneras. Un disparador llama a un procedimiento almacenado que realiza acciones que hace que se active de nuevo (sólo se reactiva si está habilitada la anidación de disparadores). A no ser que existan condiciones dentro del disparador que limiten el número de recurrencias, esto provocará un desbordamiento del nivel de anidación.

Por ejemplo, si un disparador de actualización llama a un procedimiento almacenado que lleva a cabo una actualización, el disparador y el procedimiento almacenado se ejecutan exactamente una vez si nested triggers está desactivada. Si esta opción está activada y el número de actualizaciones no está limitado a menos de 16 por alguna condición del disparador o el procedimiento, este bucle continuará hasta que sobrepase el valor máximo de 16 niveles de anidación.

Reglas asociadas a los disparadores

Aparte de prever los efectos de una modificación de datos en múltiples filas, las reversiones de los disparadores y la anidación de disparadores, existen otros factores que deben tenerse en cuenta cuando se escriben disparadores.

Disparadores y permisos

Un disparador se define en una tabla en particular. Sólo el propietario de la tabla tiene los permisos create trigger y drop trigger sobre dicha tabla. Estos permisos no se pueden transferir a otros usuarios.

SQL Server acepta definiciones de disparador que intentan llevar a cabo acciones para las que el usuario no tiene permiso. La existencia de un disparador de ese tipo aborta cualquier intento futuro de modificar la tabla de disparadores, puesto que el disparador se ejecuta y falla debido a que los permisos no son correctos. La transacción se cancelará. Será necesario rectificar la situación de los permisos u omitir el disparador.

Por ejemplo, Jose es el propietario de salesdetail y crea un disparador en ella. Se supone que el disparador debe actualizar titles.total_sales cuando se actualice salesdetail.qty . Sin embargo, Mary es la propietaria de titles y no ha concedido a Jose el permiso sobre titles . Cuando Jose intenta actualizar salesdetail , SQL Server detecta el disparador y que Jose no tiene permisos sobre titles , y revierte la transacción de actualización. Jose deberá obtener de Mary el permiso de actualización para titles.total_sales u omitir el disparador de salesdetail .

Restricciones de los disparadores

A continuación se describen algunas limitaciones o restricciones impuestas a los disparadores por SQL Server:

Una tabla puede tener un máximo de tres disparadores: uno de actualización, uno de inserción y uno de eliminación.

Cada disparador puede aplicarse a una sola tabla. Sin embargo, un mismo disparador se puede aplicar a las tres acciones del usuario: update , insert y delete .

No se puede crear un disparador en una vista ni en una tabla temporal, aunque los disparadores pueden hacer referencia a las vistas o tablas temporales.

Aunque la instrucción truncate table es, en realidad, como una instrucción delete sin la cláusula where porque quita todas las filas, no puede "activar" un disparador porque las eliminaciones individuales de fila no se registran.

Page 238: 80575032 Libro de SQL y Tl SQL Excelente

Page 238 of 280

Los disparadores no se permiten en las tablas del sistema. Aunque no aparece ningún mensaje de error si crea un disparador en una tabla del sistema, el disparador no se utilizará.

Valores nulos implícitos y explícitos

if update ( column_name ) es verdadero para una instrucción insert siempre que a la columna se le asigna un valor en la lista de selección o en la cláusula values . La introducción de un valor NULL explícito o un valor predeterminado asigna un valor a una columna y, por consiguiente, activa el disparador. Sin embargo, un valor NULL implícito no lo activa.

Estos ejemplos clarifican la situación:

create table junk

(a int null,

b int not null)

create trigger junktrig

on junk

for insert

as

if update(a) and update(b)

print "FIRING"

/*"if update" es verdadero para ambas columnas.

** Se activa el disparador.*/

insert junk (a, b) values (1, 2)

/*"if update" es verdadero para ambas columnas.

** Se activa el disparador.*/

insert junk values (1, 2)

/*NULL explícito:

**"if update" es verdadero para ambas columnas.

** Se activa el disparador.*/

insert junk values (NULL, 2)

/* Si hay un valor predeterminado para la

** columna a, "if update" es verdadero para

** ambas columnas. Se activa el disparador.*/

insert junk (b) values (2)

/* Si no hay ningún valor predeterminado en la

** columna a, "if update" no es verdadero para

** la columna a.

El disparador no se activa.*/

insert junk (b)values (2)

Los resultados serían los mismos si sólo se usara la cláusula:

if update(a)

Para crear un disparador que no permita la inserción de valores nulos implícitos, puede usar:

if update(a) or update(b)

De este modo, las instrucciones SQL del disparador pueden verificar si a o b es nulo.

Disparadores y rendimiento

En términos de rendimiento, la sobrecarga de disparador es generalmente muy baja. El tiempo invertido en ejecutar un disparador se emplea principalmente para hacer referencia a otras tablas, que pueden estar en memoria o en el dispositivo de base de datos.

Las tablas de verificación de disparadores deleted e inserted siempre están en la memoria activa. La ubicación de otras tablas a las que hace referencia el disparador determina la cantidad de tiempo necesaria para realizar la operación.

Comandos set en los disparadores

Page 239: 80575032 Libro de SQL y Tl SQL Excelente

Page 239 of 280

Es posible utilizar el comando set dentro de un disparador. La opción set que se ejecuta permanece en efecto durante la ejecución del disparador y después recupera su valor anterior.

Cambio de nombre y disparadores

Si cambia el nombre de un objeto al que hace referencia un disparador, debe omitir el disparador y volver a crearlo de forma que su texto refleje el nombre nuevo del objeto al que hace referencia. Emplee el procedimiento sp_depends para obtener un informe de los objetos a los que hace referencia un disparador. El curso de acción más seguro es no cambiar el nombre de ninguna tabla o vista a las que haga referencia un disparador.

Obtención de información sobre disparadores

Como objetos de base de datos que son, los disparadores se enumeran en sysobjects por nombre. La columna type de sysobjects identifica los disparadores con la abreviatura "TR". La siguiente consulta busca los disparadores que existen en una base de datos:

select *

from sysobjects

where type = "TR"

La instrucción create trigger correspondiente a cada disparador se almacena en syscomments . Se puede mostrar la definición de un disparador con el procedimiento del sistema sp_helptext .

Los planes de ejecución de los disparadores se almacenan en sysprocedures . Varios procedimientos del sistema proporcionan información de las tablas del sistema sobre los disparadores.

sp_help

Se puede obtener un informe sobre un disparador con el procedimiento del sistema sp_help . Por ejemplo, puede obtener información sobre deltitle como a continuación:

sp_help deltitle

Name Owner Type

----------- ------- -----------

deltitle dbo trigger

Data_located_on_segment When_created

----------------------- -----------------

no es aplicable Feb 9 1987 3:56PM

(return status = 0)

sp_helptext

Para mostrar el texto de la instrucción create trigger , ejecute el procedimiento del sistema sp_helptext :

sp_helptext deltitle

# Lines of Text

---------------

1

text

---------------------------------------------

create trigger deltitle

on titles

for delete

as

if (select count(*) from deleted, salesdetail

where salesdetail.title_id = deleted.title_id) >0

begin

rollback transaction

print "You can't delete a title with sales."

end

sp_depends

Page 240: 80575032 Libro de SQL y Tl SQL Excelente

Page 240 of 280

El procedimiento del sistema sp_depends muestra todos los disparadores que hacen referencia al objeto o todas las tablas y vistas afectadas por el disparador. Este ejemplo indica cómo utilizar sp_depends para obtener una lista de todos los objetos a los que hace referencia el disparador deltitle :

sp_depends deltitle Cosas a las que hace referencia el objeto en la base de datos actual. object type updated selected

---------------- ---------- ------- --------

dbo.salesdetail user table no no

dbo.titles user table no no

(return status = 0)

Esta instrucción muestra todos los objetos que hacen referencia a la tabla salesdetail :

sp_depends salesdetail Cosas incluidas en la base de datos actual que hacen referencia al objeto. object type

--------------------------- ----------------

dbo.deltitle disparador

dbo.history_proc procedimiento almacenado

dbo.insert_salesdetail_proc procedimiento almacenado

dbo.totalsales_trig disparador

(return status = 0)

Chapter 16

Cursores: acceso a los datos fila por fila

Una instrucción select devuelve cero o más filas. Si devuelve varias filas, puede manipular cada fila de forma individual mediante cursores.

En este capítulo se trata lo siguiente:

Introducción general a los cursores

Declaración y apertura de cursores

Obtención de datos utilizando cursores

Actualización o eliminación de datos utilizando cursores

Cierre y desasignación de cursores

Un ejemplo del uso de cursores

Efecto del bloqueo sobre los cursores

Obtención de información sobre cursores

Definición de cursores

Declaración de cursores

Apertura de cursores

Recuperación de filas de datos mediante cursores

Actualización y eliminación de filas utilizando cursores

Cierre y desasignación de cursores

Ejemplo del uso de cursores

Uso de cursores en procedimientos almacenados

Cursores y bloqueo

Obtención de información sobre cursores

Definición de cursores

Un cursor es el nombre simbólico asociado a una instrucción select Transact-SQL mediante una instrucción de declaración. Se compone de las siguientes partes:

Page 241: 80575032 Libro de SQL y Tl SQL Excelente

Page 241 of 280

Conjunto de resultados del cursor : el conjunto (tabla) de filas que resulta de ejecutar una consulta asociada al cursor.

Posición del cursor : un puntero en una fila dentro del conjunto de resultados del cursor

La posición del cursor indica la fila actual del cursor. Puede modificar o eliminar la fila de forma explícita utilizando las instrucciones delete o update con una cláusula que especifique el cursor. Puede cambiar la posición actual del cursor mediante una operación llamada recuperación . Una recuperación desplaza hacia abajo la posición actual del cursor una o más filas en el conjunto de resultados del cursor.

Un cursor se comporta en gran medida como un puntero de archivo hacia una serie de registros de archivos, donde el cursor actúa como un puntero hacia los resultados de la consulta. Sin embargo, los cursores sólo admiten el movimiento hacia delante (o secuencial) a través de los resultados de la consulta. Una vez que se han recobrado varias filas, no es posible volver hacia atrás en el conjunto de resultados del cursor para acceder a ellas de nuevo. Este proceso permite examinar los resultados de una consulta fila por fila.

Después de declarar el cursor, éste se encuentra en uno de estos dos estados:

Cerrado : el conjunto de resultados del cursor no existe, por lo que no es posible leer información en él. Los cursores se encuentran inicialmente en este estado. Es necesario abrir el cursor de forma explícita para poder utilizarlo. Una vez abierto, puede cerrarlo de forma explícita después de terminar. SQL Server puede cerrar un cursor de forma implícita por varias razones, explicadas posteriormente en este capítulo.

Abierto: las filas del conjunto de resultados del cursor se encuentran disponibles para su lectura o actualización.

Se puede cerrar un cursor y después volver a abrirse. La reapertura de un cursor vuelve a crear el conjunto de resultados del cursor y coloca el cursor delante de la primera fila. Esto permite progresar por un conjunto de resultados del cursor tantas veces como sea necesario. El cursor se puede cerrar en cualquier momento, sin necesidad de examinar todo su conjunto de resultados.

Todas las operaciones de cursor, como recobrar o actualizar una fila, se llevan a cabo en referencia a la posición actual del cursor. Actualizar una fila del cursor implica modificar los datos de la fila o eliminar ésta por completo. No es posible utilizar los cursores para insertar filas. Todas las actualizaciones realizadas mediante un cursor afectan a las tablas base correspondientes incluidas en el conjunto de resultados del cursor.

Modo en que SQL Server procesa los cursores

Al acceder a los datos mediante cursores, SQL Server divide el proceso en las siguientes operaciones:

Declaración del cursorSQL Server crea la estructura del cursor y compila la consulta definida para éste. Almacena el plan de consulta compilado, pero no lo ejecuta.

Apertura del cursorSQL Server ejecuta el plan de consulta. Realiza un barrido de las tablas base (en la medida en que sea necesario, como con un select normal) y crea el conjunto de resultados del cursor. Prepara cualquier tabla temporal generada por la consulta y asigna recursos (como memoria) para dar soporte a la estructura del cursor. También coloca el cursor delante de la primera fila de su conjunto de resultados.

Recuperación desde el cursor SQL Server desplaza la posición del cursor hacia abajo una o más filas en su conjunto de resultados. Recupera los datos de cada fila del conjunto de resultados y almacena la posición actual, permitiendo posteriores recuperaciones hasta alcanzar el final del conjunto de resultados.

Actualización o eliminación mediante el cursor SQL Server actualiza o elimina los datos del conjunto de resultados del cursor (y las tablas base correspondientes de las que se han derivado los datos) en la posición en que se encuentre el cursor después de una recuperación. Esta operación es opcional.

Cierre del cursorSQL Server cierra el conjunto de resultados del cursor, quita las tablas temporales que quedan y libera los recursos del servidor retenidos para la estructura del cursor. Sin embargo, conserva el plan de consulta del cursor para poder abrirlo de nuevo.

Desasignación del cursorSQL Server vuelca el plan de consultas de la memoria y elimina toda huella de la estructura del cursor. Es preciso volver a declarar el cursor antes de utilizarlo.

Declaración de cursores

Debe declarar un cursor para poder utilizarlo. La declaración especifica la consulta que, a su vez, define el conjunto de resultados del cursor. Puede definir un cursor como actualizable o de sólo lectura de forma explícita mediante las palabras clave for update o for read only . En caso de omitirlas, SQL Server determina si el cursor es actualizable basándose en el tipo de consulta que define su conjunto de resultados. No es posible utilizar las instrucciones update o delete con el conjunto de resultados de un cursor de sólo lectura.

Page 242: 80575032 Libro de SQL y Tl SQL Excelente

Page 242 of 280

Sintaxis de declare cursor

La sintaxis de la instrucción declare cursor es:

declare cursor_name cursor

for select_statement

[for {read only | update [of column_name_list ]}]

La instrucción declare cursor debe preceder a cualquier instrucción open del cursor. No es posible combinar declare cursor con otras instrucciones del mismo lote Transact-SQL, excepto al usar el cursor en un procedimiento almacenado.

select_statement es la consulta que define el conjunto de resultados del cursor para cursor_name . En general, select_statement puede utilizar la sintaxis y semántica completas de una instrucción select Transact-SQL, incluida la palabra clave holdlock . Sin embargo, no puede contener una cláusula compute , for browse o into .

Por ejemplo, la siguiente instrucción declare cursor define un conjunto de resultados para el cursor authors_crsr , que contiene todos los autores que no residen en California:

declare authors_crsr cursor

for select au_id, au_lname, au_fname

from authors

where state != 'CA'

select_statement puede contener referencias a nombres de parámetros de Transact-SQL o variables locales. Sin embargo, los nombres sólo pueden hacer referencia a parámetros y variables locales definidas en un procedimiento almacenado que contenga la instrucción declare cursor . Si se utiliza el cursor en un disparador, select_statement también puede hacer referencia a las tablas temporales inserted y deleted utilizadas en los disparadores. Para obtener información adicional sobre el uso de la instrucción select , consulte el Capítulo 2, "Consultas: selección de datos de una tabla".

Alcance del cursor

Un cursor viene definido por su alcance , que determina la región en que está presente el cursor. Una vez que el alcance del cursor deja de existir, también desaparece su nombre. El alcance de los cursores viene definido por las siguientes regiones:

Sesión: esta región comienza cuando un cliente se conecta a SQL Server y termina al desconectarse. Esta región es distinta de las regiones definidas por procedimientos almacenados o disparadores.

Procedimiento almacenado: esta región se inicia cuando un procedimiento almacenado comienza su ejecución y finaliza cuando la termina. Si un procedimiento almacenado llama a otro, SQL Server inicia una región nueva y la trata como subregión del primer procedimiento.

Disparador: esta región se inicia cuando un disparador comienza su ejecución y finaliza cuando la completa.

Un cursor debe tener un nombre único dentro de un alcance dado. Puesto que cada alcance es distinto, un nombre de cursor definido en una región también puede definirse en otra región o en su propia subregión. No es posible acceder a un cursor definido en una región desde otra región. Sin embargo, SQL Server permite el acceso de un cursor a una subregión si no existe ningún otro cursor con el mismo nombre en ella.

SQL Server detecta conflictos de nombre dentro de un alcance concreto sólo durante el tiempo de ejecución. Un procedimiento almacenado o un disparador pueden definir dos cursores con el mismo nombre si sólo se ejecuta uno. Por ejemplo:

create procedure proc1 (@flag int)

as

if (@flag)

declare names_crsr cursor

for select au_fname from authors

else

declare names_crsr cursor

for select au_lname from authors

return

Este procedimiento almacenado funciona porque sólo está definido un cursor names_crsr en su alcance.

Barridos del cursor y el conjunto de resultados del cursor

Page 243: 80575032 Libro de SQL y Tl SQL Excelente

Page 243 of 280

Es posible que las filas del conjunto de resultados del cursor no reflejen los valores de las filas de la tabla base real. Por ejemplo, un cursor declarado con una cláusula order by requiere generalmente la creación de una tabla interna para ordenar las filas del conjunto de resultados del cursor. SQL Server no bloquea las filas de la tabla base correspondientes a las filas de la tabla interna, permitiendo que otros clientes actualicen dichas filas de la tabla base. En este caso, las filas devueltas al cliente desde el conjunto de resultados del cursor no estarán sincronizadas con las filas de la tabla base.

Un conjunto de resultados del cursor se genera a medida que las filas son devueltas mediante un fetch de dicho cursor. Esto significa que una consulta select del cursor se procesa como una consulta select normal. Este proceso, conocido como barridos de cursor , proporciona un tiempo de retorno más rápido y elimina la necesidad de leer filas que la aplicación no precisa.

SQL Server requiere que los barridos de cursor utilicen un índice único de una tabla, sobre todo para lecturas con un nivel de aislamiento 0. Si la tabla tiene una columna IDENTITY y necesita crear un índice no único en ella, utilice la opción de base de datos identity in nonunique index para incluir automáticamente una columna IDENTITY en las claves de índice de la tabla y hacer que todos los índices creados en la tabla sean únicos. Esta opción de base de datos hace que los índices lógicamente no únicos sean internamente únicos y permite usarlos para procesar cursores actualizables en lecturas con un nivel de aislamiento 0.

Sin embargo, todavía puede emplear cursores que hagan referencia a tablas sin índices, si no se actualiza ninguna de estas tablas con otro proceso que haga cambiar la posición actual de la fila. Por ejemplo:

declare storinfo_crsr cursor

for select stor_id, stor_name, payterms

from stores

where state = 'CA'

La tabla stores especificada con el cursor anterior no tiene ningún índice. SQL Server permite la declaración de cursores en tablas sin índices únicos, pero cualquier actualización o eliminación que mueva la posición de las filas en estas tablas cierra todos los cursores de las mismas.

Conversión de los cursores en actualizables

Se puede actualizar o eliminar una fila devuelta por un cursor si éste es actualizable. Si el cursor es de sólo lectura, sólo podrá leer los datos, pero no actualizarlos ni eliminarlos. De forma predeterminada, SQL Server intenta determinar si un cursor es actualizable antes de designarlo como de sólo lectura.

Se puede especificar si un cursor es actualizable o no explícitamente utilizando las palabras clave read only o update en la instrucción declare . El siguiente ejemplo define un conjunto de resultados actualizable para el cursor pubs_crsr :

declare pubs_crsr cursor

for select pub_name, city, state

from publishers

for update of city, state

El ejemplo anterior incluye todas las filas de la tabla publishers , pero sólo define explícitamente las columnas city y state para su actualización.

A menos que planee actualizar o eliminar filas mediante un cursor, debe declarar éste como de sólo lectura. Si no especifica read only o update explícitamente, el cursor es actualizable implícitamente cuando la instrucción select no contiene ninguno de los siguientes elementos:

Opción distinct

Cláusula group by

Función agregada

Subconsulta

Operador union

Cláusula at isolation read uncommitted

No es posible especificar la cláusula for update si la select_statement del cursor contiene una de las estructuras anteriores. SQL Server también define un cursor como de sólo lectura si se declaran ciertos tipos de cursores que incluyen una cláusula order by como parte de su select_statement . Para obtener más información, consulte la sección sobre cursores en el Manual de Referencia de SQL Server .

Page 244: 80575032 Libro de SQL y Tl SQL Excelente

Page 244 of 280

Si no especifica una column_name_list con la cláusula for update , todas las columnas especificadas en la consulta son actualizables. Como se ha descrito anteriormente para los barridos de cursor, SQL Server intenta utilizar índices únicos con los cursores actualizables al barrer la tabla base. Para los cursores, SQL Server considera un índice que contenga una columna IDENTITY como índice único, aunque no esté declarado como tal.

SQL Server permite incluir columnas en la column_name_list que no estén especificadas en la lista de columnas de la select_statement del cursor, pero que formen parte de las tablas indicadas en select_statement .

En el siguiente ejemplo, SQL Server utiliza el índice único de la columna pub_id de publishers (aunque pub_id no está incluida en la definición de newpubs_crsr ):

declare newpubs_crsr cursor

for select pub_name, city, state

from publishers

for update

Si no especifica la cláusula for update , SQL Server elige cualquier índice único, aunque también puede utilizar otros índices o barridos de tabla si no existe ningún índice único para las columnas especificadas. Sin embargo, cuando se especifica for update , SQL Server debe utilizar un índice único definido en una o varias columnas para barrer la tabla base. Si no hay ningún índice único, devolverá un error.

Las columnas de la tabla base especificadas en la column_name_list de for update deben incluir sólo las que se van a actualizar, y ninguna columna incluida en al menos un índice único. Esto permite que SQL Server utilice dicho índice único para su barrido de cursor, lo que ayuda a evitar una actualización anómala llamada problema Halloween .

Este problema se produce cuando un cliente actualiza una columna de una fila del conjunto de resultados del cursor que define el orden en que se devuelven las filas de las tablas base. Por ejemplo, si SQL Server accede a una tabla base utilizando un índice y el cliente actualiza la clave del índice, la fila del índice actualizada puede moverse dentro de éste y ser leída nuevamente por el cursor. Esto es resultado de que un cursor actualizable sólo crea de forma lógica un conjunto de resultados del cursor. El conjunto de resultados del cursor se compone realmente de las tablas base de las que se deriva el cursor.

Apertura de cursores

Después de declarar el cursor, debe abrir éste para realizar una operación fetch , update o delete de las filas. La apertura de un cursor hace que SQL Server evalúe la instrucción select que define el cursor y deje disponible el conjunto de resultados del cursor para su procesamiento. La sintaxis de open es:

open cursor_name

Después de abrir un cursor, éste se coloca delante de la primera fila de su conjunto de resultados. Utilice fetch para acceder a la primera fila.

SQL Server no permite abrir un cursor si éste ya está abierto o no se ha definido con la instrucción declare cursor . Puede volver a abrir un cursor cerrado para restablecer su posición al principio del conjunto de resultados.

Recuperación de filas de datos mediante cursores

Después de declarar y abrir un cursor, puede recobrar filas de su conjunto de resultados con el comando fetch . Este comando devuelve una o más filas al cliente que está extrayendo los datos de columna de la fila. Si lo desea, puede incluir parámetros de Transact-SQL o variables locales con fetch para almacenar valores de columna.

Sintaxis de fetch

La sintaxis de la instrucción fetch es:

fetch cursor_name [into fetch_target_list ]

Por ejemplo, después de declarar y abrir el cursor authors_crsr , puede recobrar la primera fila de su conjunto de resultados de la siguiente manera:

fetch authors_crsr

Page 245: 80575032 Libro de SQL y Tl SQL Excelente

Page 245 of 280

au_id au_lname au_fname

----------- ------------------- ---------------

341-22-1782 Smith Meander

Cada fetch posterior recupera otra fila del conjunto de resultados del cursor. Por ejemplo:

fetch authors_crsr

au_id au_lname au_fname

----------- ------------------- ---------------

527-72-3246 Greene Morningstar

Después de recobrar todas las filas, el cursor apuntará a la última fila del conjunto de resultados. Si ejecuta fetch de nuevo, SQL Server devuelve una advertencia a través de la variable @@sqlstatus (descrita más abajo) indicándo que no hay más datos. La posición del cursor no se altera.

No es posible recobrar una fila que ya se ha recuperado, ni volver atrás en un conjunto de resultados del cursor. Se puede cerrar y reabrir el cursor para generar el conjunto de resultados del cursor nuevamente e iniciar la recuperación desde el principio.

La cláusula into especifica que SQL Server introduce datos de columna en las variables indicadas. La fetch_target_list debe componerse de parámetros de Transact-SQL o variables locales declarados anteriormente.

Por ejemplo, después de declarar las variables @name , @city y @state , puede recobrar filas del cursor pubs_crsr como se indica a continuación:

fetch pubs_crsr into @name, @city, @state

SQL Server espera una correspondencia recíproca entre las variables de la fetch_target_list y las expresiones de la lista de destino especificadas en la select_statement que define el cursor. Los tipos de datos de las variables o parámetros deben ser compatibles con los de las columnas del conjunto de resultados del cursor.

Verificación del estado del cursor

SQL Server devuelve un valor de estado después de cada recuperación. Puede acceder al valor mediante la variable global @@sqlstatus . La siguiente tabla enumera valores de @@sqlstatus posibles y su significado:

Tabla 16-1: Valores de @@sqlstatus

Valor Significado

0 Indica que la instrucción f etch se ha completado correctamente.

1 Indica que la instrucción f etch ha dado como resultado un error.

2 Indica que no hay más datos en el conjunto de resultados. Esta advertencia puede aparecer si la posición actual del cursor es la última fila del conjunto de resultados y el cliente envía una instrucción f etch a ese cursor.

El siguiente ejemplo determina la @@sqlstatus del cursor authors_crsr abierto:

select @@sqlstatus

---------

0

(1 row affected)

Sólo una instrucción fetch puede definir la @@sqlstatus . Ninguna otra instrucción tiene efecto sobre esta variable.

Verificación del número de filas recobradas

SQL Server también proporciona la variable global @@rowcount . . @@rowcount permite controlar el número de filas del conjunto de resultados del cursor devueltas al cliente hasta la última recuperación. En otras palabras, representa el número total de filas vistas por el cursor en un momento dado.

Una vez leídas todas las filas de un conjunto de resultados del cursor, @@rowcount representa el número total de filas de dicho conjunto de resultados. Cada cursor abierto está asociado a una variable @@rowcount específica. Esta se omite al cerrar el

Page 246: 80575032 Libro de SQL y Tl SQL Excelente

Page 246 of 280

cursor. Verificando @@rowcount después de una operación de fetch , obtendrá el número de filas leídas con el cursor especificado en dicha operación fetch .

El siguiente ejemplo determina la @@rowcount del cursor authors_crsr abierto:

select @@rowcount

---------

1

(1 row affected)

Obtención de múltiples filas con cada fetch

De forma predeterminada, el comando fetch sólo devuelve una fila cada vez. Se puede utilizar la opción cursor rows del comando set para cambiar el número de filas devueltas por fetch . Sin embargo, esta opción no afecta a una recuperación que contenga una cláusula into .

La sintaxis de set es:

set cursor rows number for cursor_name

donde number especifica el número de filas del cursor. El valor predeterminado es 1 para cada cursor declarado. Se puede definir la opción cursor rows para un cursor con independencia de que esté abierto o cerrado.

Por ejemplo, se puede cambiar el número de filas recobradas por el cursor authors_crsr de la siguiente manera:

set cursor rows 3 for authors_crsr

Después, cada recuperación de authors_crsr devuelve 3 filas del conjunto de resultados del cursor:

fetch authors_crsr

au_id au_lname au_fname

----------- ------------------- ---------------

648-92-1872 Blotchet-Halls Reginald

712-45-1867 del Castillo Innes

722-51-5424 DeFrance Michel

El cursor se coloca en la última fila recobrada (el autor Michel DeFrance, en el ejemplo anterior).

La recuperación de varias filas al mismo tiempo es especialmente adecuada para aplicaciones cliente. Si recobra más de una fila, Open Client o Embedded SQL(TM) coloca las filas enviadas a la aplicación cliente en la memoria intermedia automáticamente. El cliente todavía ve un acceso fila por fila, pero cada fetch genera menos llamadas a SQL Server, lo que mejora el rendimiento.

Actualización y eliminación de filas utilizando cursores

Si el cursor es actualizable, puede utilizar las instrucciones update y delete para actualizar o eliminar filas. SQL Server determina si el cursor es actualizable verificando la select_statement que define el cursor. También puede definir un cursor como actualizable de forma explícita con la cláusula for update de la instrucción declare cursor . Consulte "Conversión de los cursores en actualizables" para obtener más información.

Eliminación de filas del conjunto de resultados del cursor

Mediante la cláusula where current of de la instrucción delete , puede eliminar la fila de la posición actual del cursor. Al eliminar una fila del conjunto de resultados del cursor, también se elimina de la tabla de base de datos subyacente. Sólo es posible eliminar una fila cada vez con el cursor.

La sintaxis de delete...where current of es:

delete [from] [[ database .] owner .]{ table_name | view_name }

where current of cursor_name

Page 247: 80575032 Libro de SQL y Tl SQL Excelente

Page 247 of 280

El table_name o view_name especificado con delete ... where current of debe ser la tabla o vista especificada en la primera cláusula from de la instrucción select que define el cursor.

Por ejemplo, se puede eliminar la fila a la que apunta actualmente el cursor authors_crsr de la siguiente manera:

delete from authors

where current of authors_crsr

La palabra clave from del ejemplo anterior es opcional.

Note: No es posible eliminar una fila de un cursor definido por una instrucción select que contenga una combinación, aunque el cursor sea actualizable.

Después de eliminar una fila de un cursor, SQL Server coloca el cursor delante de la siguiente fila de su conjunto de resultados. Todavía debe utilizar fetch para tener acceso a la fila siguiente. Si elimina la última fila del conjunto de resultados del cursor, SQL Server coloca el cursor después de la última fila del conjunto de resultados.

Por ejemplo, después de eliminar la fila actual en el ejemplo anterior (el autor Michel DeFrance), se pueden recobrar los siguientes 3 autores en el conjunto de resultados del cursor (suponiendo que cursor rows todavía esté definido como 3):

fetch authors_crsr

au_id au_lname au_fname

----------- ------------------- ---------------

807-91-6654 Panteley Sylvia

899-46-2035 Ringer Anne

998-72-3567 Ringer Albert

Evidentemente, puede eliminar una fila de la tabla base sin hacer referencia a un cursor. El conjunto de resultados del cursor cambia a medida que se realizan cambios en la tabla base.

Actualización de filas del conjunto de resultados del cursor

Mediante la cláusula where current of de la instrucción update , puede actualizar la fila de la posición actual del cursor. Cualquier actualización del conjunto de resultados del cursor también afecta a la fila de la tabla base de la que se deriva la fila del cursor.

La sintaxis de update...where current of es:

update [[ database .] owner .]{ table_name | view_name }

set [[[ database .] owner .]{ table_name .| view_name .}]

column_name 1 =

{ expression 1 |NULL|( select_statement )}

[, column_name 2 =

{ expressio n2 |NULL|( select_statement )}]...

where current of cursor_name

La cláusula set especifica el nombre de columna del conjunto de resultados del cursor y asigna el valor nuevo. Cuando se enumeran varios pares del tipo nombre de columna/valor, deben ir separados por comas.

table_name o view_name debe ser la tabla o vista especificada en la primera cláusula from de la instrucción select que define el cursor. Si dicha cláusula from hace referencia a más de una tabla o vista (mediante una combinación), sólo podrá especificar la tabla o vista que esté actualizando en ese momento.

Por ejemplo, puede actualizar la fila a la que apunta el cursor pubs_crsr del siguiente modo:

update publishers

set city = "Pasadena",

state = "CA"

where current of pubs_crsr

Después de la actualización, la posición del cursor permanece igual. Se puede continuar actualizando la fila de esa posición del cursor siempre que otra instrucción Transact-SQL no lo desplace.

Page 248: 80575032 Libro de SQL y Tl SQL Excelente

Page 248 of 280

SQL Server permite actualizar columnas que no están especificadas en la lista de columnas de la select_statement , pero forman parte de las tablas indicadas en esta instrucción. Sin embargo, cuando especifica una column_name_list con update , sólo es posible actualizar las columnas indicadas en ella.

Cierre y desasignación de cursores

Cuando termine con el conjunto de resultados del cursor, puede cerrarlo mediante close . La sintaxis de close es:

close cursor_name

El cierre del cursor no cambia su definición. Se puede volver a abrir con open y SQL Server creará un conjunto de resultados del cursor nuevo utilizando la misma consulta que antes. Por ejemplo:

close authors_crsr

open authors_crsr

Después, puede recobrar desde authors_crsr , empezando por el principio de su conjunto de resultados. Cualquier condición asociada a dicho cursor (como el número de filas recobradas, definido por set cursor rows ) permanece en vigor.

Por ejemplo:

fetch authors_crsr

au_id au_lname au_fname

----------- ------------------- ---------------

341-22-1782 Smith Meander

527-72-3246 Greene Morningstar

648-92-1872 Blotchet-Halls Reginald

Si quiere desechar el cursor, debe desasignarlo mediante deallocate . La sintaxis de deallocate es:

deallocate cursor cursor_name

La desasignación de un cursor libera cualquier recurso asociado con él, incluido el nombre del cursor. No puede volver a utilizar un nombre de cursor hasta que lo desasigne. Si desasigna un cursor abierto, SQL Server lo cierra automáticamente. La finalización de una conexión cliente a un servidor también cierra y desasigna cualquier cursor abierto.

Ejemplo del uso de cursores

El siguiente ejemplo de cursor utiliza esta consulta:

select author = au_fname + " " + au_lname, au_id

from authors

order by au_lname

Los resultados de la consulta son:

author au_id

------------------------- -----------

Abraham Bennet 409-56-7008

Reginald Blotchet-Halls 648-92-1872

Cheryl Carson 238-95-7766

Michel DeFrance 722-51-5454

Ann Dull 427-17-2319

Marjorie Green 213-46-8915

Morningstar Greene 527-72-3246

Burt Gringlesby 472-27-2349

Sheryl Hunter 846-92-7186

Livia Karsen 756-30-7391

Chastity Locksley 486-29-1786

Stearns MacFeather 724-80-9391

Heather McBadden 893-72-1158

Michael O'Leary 267-41-2394

Sylvia Panteley 807-91-6654

Anne Ringer 899-46-2035

Albert Ringer 998-72-3567

Page 249: 80575032 Libro de SQL y Tl SQL Excelente

Page 249 of 280

Meander Smith 341-22-1782

Dick Straight 274-80-9391

Dirk Stringer 724-08-9931

Johnson White 172-32-1176

Akiko Yokomoto 672-71-3249

Innes del Castillo 712-45-1867

Los siguientes pasos muestran el modo de utilizar un cursor con la consulta anterior:

1. Declare el cursor. Esta instrucción declare cursor define un cursor utilizando la instrucción select mostrada anteriormente:

declare newauthors_crsr cursor for

select author = au_fname + " " + au_lname, au_id

from authors

order by au_lname

2. Una vez declarado el cursor, puede abrirlo:

open newauthors_crsr

3. Ahora puede recobrar filas utilizando el cursor:

fetch newauthors_crsr

author au_id

------------------------- -----------

Abraham Bennet 409-56-7008

4. Se pueden recobrar varias filas al mismo tiempo especificando el número de filas con el comando set :

set cursor rows 5 for newauthors_crsr

fetch newauthors_crsr

author au_id

------------------------- -----------

Reginald Blotchet-Halls 648-92-1872

Cheryl Carson 238-95-7766

Michel DeFrance 722-51-5454

Ann Dull 427-17-2319

Marjorie Green 213-46-8915

Cada fetch posterior devuelve cinco filas más:

fetch newauthors_crsr

author au_id

------------------------- -----------

Morningstar Greene 527-72-3246

Burt Gringlesby 472-27-2349

Sheryl Hunter 846-92-7186

Livia Karsen 756-30-7391

Chastity Locksley 486-29-1786

5. Una vez que haya terminado con el cursor, puede cerrarlo:

close newauthors_crsr

El cierre del cursor libera el conjunto de resultados, pero el cursor se mantiene definido. Si lo abre de nuevo, SQL Server vuelve a ejecutar la consulta y coloca el cursor delante de la primera fila de su conjunto de resultados. El cursor todavía está definido para devolver cinco filas con cada fetch .

6. El comando deallocate se utiliza para convertir al cursor en no definido:

deallocate cursor newauthors_crsr

No puede volver a utilizar el nombre del cursor hasta que se desasigne el mismo.

Page 250: 80575032 Libro de SQL y Tl SQL Excelente

Page 250 of 280

Uso de cursores en procedimientos almacenados

Los cursores son especialmente útiles en procedimientos almacenados. Permiten llevar a cabo la misma tarea utilizando sólo una consulta que, de otro modo, requeriría varias. Sin embargo, todas las operaciones del cursor deben ejecutarse dentro de un solo procedimiento. Un procedimiento almacenado no puede abrir, recobrar o cerrar un cursor que no esté declarado en el procedimiento. El cursor no está definido fuera del alcance del procedimiento almacenado.

Por ejemplo, el siguiente procedimiento almacenado au_sales verifica la tabla sales para ver si algún libro de un autor concreto se ha vendido bien:

create procedure au_sales (@author_id id)

as

/*declarar variables locales usadas para recobrar */

declare @title_id tid

declare @title varchar(80)

declare @ytd_sales int

declare @msg varchar(120)

/* declarar el cursor para recobrar los libros

** escritos por un autor concreto */

declare author_sales cursor for

select ta.title_id, t.title, t.total_sales

from titleauthor ta, titles t

where ta.title_id = t.title_id

and ta.au_id = @author_id

open author_sales

fetch author_sales

into @title_id, @title, @ytd_sales

if (@@sqlstatus = 2)

begin

print "We do not sell books by this author."

close author_sales

return

end

/* si el conjunto de resultados del cursor no está

** vacío, procesar cada fila de información */

while (@@sqlstatus = 0)

begin

if (@ytd_sales = NULL)

begin

select @msg = @title +

" had no sales this year."

print @msg

end

else if (@ytd_sales < 500)

begin

select @msg = @title +

" had poor sales this year."

print @msg

end

else if (@ytd_sales < 1000)

begin

select @msg = @title +

" had mediocre sales this year."

print @msg

end

else

begin

select @msg = @title +

" had good sales this year."

print @msg

end

fetch author_sales into @title_id, @title,

@ytd_sales

end

Page 251: 80575032 Libro de SQL y Tl SQL Excelente

Page 251 of 280

/* si se genera un error, llamar al manipulador

** designado */

if (@@sqlstatus = 1) exec error_handle

close author_sales

deallocate cursor author_sales

return

Para obtener más información sobre los procedimientos almacenados, consulte el Capítulo 14, "Uso de procedimientos almacenados".

Cursores y bloqueo

Los métodos de bloqueo de cursores son similares a los métodos de bloqueo actuales de SQL Server. En general, las instrucciones que leen datos (tales como select o readtext ) utilizan bloqueos compartidos en cada página de datos para evitar la lectura de datos modificados por una transacción no consignada. Las instrucciones de actualización utilizan bloqueos exclusivos en cada página que modifican. Para reducir los bloqueos insolubles y mejorar la simultaneidad, SQL Server sitúa con frecuencia un bloqueo exclusivo delante de un bloqueo de actualización, el cual indica que el cliente piensa cambiar datos de la página.

Con los cursores actualizables, SQL Server utiliza bloqueos de actualización de forma predeterminada al barrer tablas o vistas referenciadas con la cláusula for update de declare cursor . Si se incluye for update , pero la lista está vacía, todas las referencias a tablas y vistas de la cláusula from de la select_statement reciben bloqueos de actualización predeterminadamente. Si no incluye la cláusula for update , las tablas y vistas referenciadas reciben bloqueos compartidos. Puede indicar a SQL Server que utilice bloqueos compartidos en lugar de bloqueos de actualización añadiendo la palabra clave shared a la cláusula from . De forma específica, añada shared después de cada nombre de tabla para la que prefiera un bloqueo compartido .

Para obtener información sobre el bloqueo de SQL Server, consulte la Guía de Administración del Sistema . Para obtener más información sobre cursores y bloqueos, consulte el Manual de Referencia de SQL Server .

Obtención de información sobre cursores

SQL Server proporciona el procedimiento del sistema sp_cursorinfo , que muestra información sobre el nombre del cursor, su estado actual (como abierto o cerrado) y sus columnas de resultados. El siguiente ejemplo muestra información sobre el cursor authors_crsr :

sp_cursorinfo 0, authors_crsr

El nombre de cursor 'authors_crsr' está declarado

en el nivel anidado '0'.

El id del cursor es 327681

El cursor se abrió con éxito 1 veces

El cursor se compiló con un nivel de aislamiento 1.

El cursor no está abierto.

El cursor permanecerá abierto cuando una

transacción se confirme o se elimine.

El número de filas devuelto para cada FETCH es 1.

El cursor es actualizable.

Este cursor devolvió 3 columnas.

Las columnas de resultado son:

Nombre = 'au_id', Tabla = 'authors', Tipo = ID,

Longitud = 11 (actualizable)

Nombre = 'au_lname', Tabla = 'authors', Tipo =

VARCHAR, Longitud = 40 (acutalizable)

Nombre = 'au_fname', Tabla = 'authors', Tipo =

VARCHAR, Longitud = 20 (actualizable)

Para obtener más información sobre sp_cursorinfo , consulte el Manual de Referencia de SQL Server .

Chapter 17

Page 252: 80575032 Libro de SQL y Tl SQL Excelente

Page 252 of 280

Transacciones: mantenimiento de la consistencia y recuperación de datos

Las transacciones proporcionan un modo de agrupar instrucciones Transact-SQL a fin de que sean tratadas como una unidad. Se ejecutan todas las instrucciones del grupo, o ninguna.

En este capítulo se trata lo siguiente:

Introducción general a las transacciones

Uso de instrucciones agrupadas en una transacción

Definición de modos y niveles de aislamiento de transacciones

Funcionamiento de procedimientos almacenados y disparadores con transacciones

Funcionamiento de cursores con transacciones

Copia de seguridad y recuperación de transacciones

Definición de transacción

Uso de transacciones

Selección del modo y nivel de aislamiento de las transacciones

Uso de transacciones en procedimientos almacenados y disparadores

Uso de cursores en transacciones

Copia de seguridad y recuperación de transacciones

Definición de transacción

Una transacción es un mecanismo para garantizar que un conjunto de una o más instrucciones SQL se trate como una sola unidad de trabajo. SQL Server maneja automáticamente todos los comandos de modificación de datos, incluidas las solicitudes de cambio de un solo paso, como transacciones. De forma predeterminada, cada instrucción insert , update y delete se considera una sola transacción.

Puede agrupar un conjunto de instrucciones SQL en una transacción definida por el usuario con los comandos begin transaction , commit transaction y rollback transaction . begin transaction marca el comienzo de un bloque de transacciones. Todas las instrucciones posteriores, hasta una rollback transaction o una commit transaction coincidente, se incluyen como parte de la transacción.

Las transacciones permiten a SQL Server garantizar:

La consistencia de los datos: las consultas y solicitudes de cambio simultáneas no pueden colisionar entre sí y los usuarios nunca ven ni emplean los datos que están en proceso de cambio.

La capacidad de recuperación de los datos: en caso de un fallo del sistema, la recuperación de la base de datos es completa y automática.

Para poder utilizar las transacciones compatibles con las normas SQL, SQL Server proporciona opciones que permiten seleccionar el modo y el nivel de aislamiento de las transacciones. Las aplicaciones que requieren transacciones compatibles con las normas SQL deberían definir dichas opciones al comienzo de cada sesión. Los modos y niveles de aislamiento de las transacciones se describen más adelante en este capítulo.

Transacciones y consistencia

En un entorno multiusuario, SQL Server debe evitar que las consultas y solicitudes de modificación de datos simultáneas interfieran entre sí. Esto es importante porque si los datos procesados por una consulta pudieran ser cambiados por la actualización de otro usuario mientras la consulta está en ejecución, los resultados de la consulta serían ambiguos.

SQL Server define automáticamente el nivel adecuado de bloqueo para cada transacción. Puede hacer que los bloqueos compartidos sean más restrictivos consulta a consulta incluyendo la palabra clave holdlock en una instrucción select .

Las transacciones definidas por el usuario permiten a los usuarios indicar a SQL Server que procese cualquier número de instrucciones SQL como una sola unidad. Dichas transacciones se explican más adelante en otra sección.

Transacciones y recuperación

Page 253: 80575032 Libro de SQL y Tl SQL Excelente

Page 253 of 280

Una transacción es una unidad de trabajo y una unidad de recuperación. El hecho de que SQL Server manipule las solicitudes de cambio de un solo paso como transacciones significa que la base de datos puede recuperarse completamente en caso de fallos.

El tiempo de recuperación de SQL Server se mide en minutos y segundos. Se puede especificar el tiempo de recuperación máximo aceptable.

Los comandos SQL relacionados con la recuperación y copia de seguridad se explican en "Copia de seguridad y recuperación de transacciones".

Uso de transacciones

begin transaction y commit transaction indican a SQL Server que procese cualquier número de comandos individuales como una sola unidad. rollback transaction deshace la transacción, bien hasta su comienzo, bien hasta un punto de resguardo. Puede definir un punto de resguardo dentro de una transacción con el comando save transaction .

Las transacciones definidas por el usuario proporcionan control sobre el manejo de la transacción. También mejoran el rendimiento, dado que la sobrecarga del sistema se alcanza una vez por transacción en lugar de una vez para cada comando individual.

Note: La agrupación de un gran número de comandos Transact-SQL en una transacción de larga duración puede afectar al tiempo de recuperación. Si SQL Server falla antes de que la transacción se consigne, la recuperación llevará más tiempo, porque SQL Server debe deshacer la transacción.

Cualquier usuario puede definir una transacción. No se requiere ningún permiso para ninguno de los comandos de la transacción.

Las siguientes secciones contienen temas generales sobre transacciones y comandos de transacción, con ejemplos. Para obtener más información sobre las transacciones, consulte el Manual de Referencia de SQL Server .

Uso de comandos de definición de datos en transacciones

Pueden utilizar determinados comandos del lenguaje de definición de datos en transacciones definiendo la opción ddl in tran de sp_dboption como verdadera. Si ddl in tran es verdadera en una base de datos concreta, es posible emitir comandos como create table , grant y alter table dentro de transacciones en esa base de datos. Si ddl in tran es verdadera en la base de datos model , es posible emitir los comandos dentro de transacciones en todas las bases de datos creadas después de que ddl in tran se definiese como verdadera en model .

Warning! La única situación en la que está justificado el uso de comandos del lenguaje de definición de datos dentro de transacciones es en create schema . Los comandos del lenguaje de definición de datos establecen bloqueos sobre las tablas del sistema, como sysobjects . Si usa comandos del lenguaje de definición de datos dentro de transacciones, éstas deberán ser de longitud reducida. En particular, evite utilizar comandos del lenguaje de definición de datos en tempdb dentro de transacciones, porque, de lo contrario, el sistema puede llegar a detenerse. Siempre debe dejar ddl in tran establecido como falso en tempdb .

Para definir ddl in tran como verdadera, escriba:

sp_dboption mydb,"ddl in tran", true

El primer parámetro especifica el nombre de la base de datos donde debe definir la opción. Es necesario estar usando la base de datos master para ejecutar sp_dboption . Cualquier usuario puede ejecutar sp_dboption sin parámetros para mostrar los valores de opción actuales. Sin embargo, para definir opciones, es preciso ser un administrador del sistema o el propietario de la base de datos.

Los siguientes comandos se permiten en una transacción definida por el usuario sólo si la opción ddl in tran de sp_dboption está definida como verdadera:

Tabla 17-1: Comandos DDL no permitidos en transacciones

alter table (se permiten cláusulas distintas de partition y unpartition ) create default create index create procedure

drop default drop index drop procedure

grant revoke

Page 254: 80575032 Libro de SQL y Tl SQL Excelente

Page 254 of 280

create rule create schema create table create trigger create view

drop rule drop table drop trigger drop view

Los procedimientos del sistema que cambian la base de datos master o que crean tablas temporales no pueden utilizarse dentro de transacciones definidas por el usuario.

Nunca debe utilizar los siguientes comandos dentro de una transacción definida por el usuario:

Tabla 17-2: Comandos DDL no permitidos en transacciones

alter database alter table...partition alter table...unpartition create database

disk init dump database dump transaction drop database

load transaction load database reconfigure

select into update statistics truncate table

Es posible verificar el valor actual de ddl in tran con sp_helpdb .

Inicio y consignación de transacciones

Los comandos begin transaction y commit transaction pueden incluir cualquier número de instrucciones SQL y procedimientos almacenados. Las sintaxis de ambas instrucciones es:

begin {transaction | tran} [ transaction_name ]

commit {transaction | tran | work} [ transaction_name ]

transaction_name es el nombre asignado a la transacción y debe cumplir con las reglas para identificadores.

Las palabras clave transaction , tran y work (en commit transaction ) son sinónimas: puede utilizar una en lugar de las otras. Sin embargo, transaction y tran son extensiones Transact-SQL; sólo work es compatible con las normas SQL.

A continuación se muestra un ejemplo básico:

begin tran

statement

procedure

statement

commit tran

commit transaction no afecta a SQL Server si no hay ninguna transacción activa.

Reversión y guardado de transacciones

Si una transacción debe cancelarse antes de que se consigne, ya sea por un fallo o por un cambio por parte del usuario, todas las instrucciones o procedimientos finalizados deberán deshacerse.

Puede cancelar o revertir una transacción con el comando rollback transaction en cualquier momento antes de que se introduzca el comando commit transaction . Si utiliza puntos de resguardo, puede cancelar una transacción completa o parte de la misma. Sin embargo, no es posible cancelar una transacción una vez consignada.

La sintaxis del comando rollback transaction es:

rollback {transaction | tran | work} [ transaction_name | savepoint_name ]

Un punto de resguardo es un marcador que el usuario coloca dentro de una transacción para indicar el punto hasta donde es posible realizar la reversión.

Los puntos de resguardo se insertan incluyendo un comando save transaction dentro de la transacción. La sintaxis es:

Page 255: 80575032 Libro de SQL y Tl SQL Excelente

Page 255 of 280

save {transaction | tran} savepoint_name

El nombre del punto de resguardo debe cumplir con las reglas para identificadores.

Si no se proporciona ningún nombre de punto de resguardo ( savepoint_name ) ni ningún nombre de transacción ( transaction_name ) con el comando rollback transaction , la transacción se revierte al primer comando begin transaction de un lote.

A continuación se indica cómo utilizar los comandos save transaction y rollback transaction :

begin tran transaction_name

statement

statement

procedure

save tran savepoint_name

statement

rollback tran savepoint_name

statement

statement

rollback tran

El primer comando rollback transaction revierte la transacción hasta el punto de resguardo situado dentro de la transacción. El segundo comando rollback transaction revierte la transacción hasta su comienzo. Si una transacción se revierte a un punto de resguardo, debe continuar hasta su finalización o cancelarse por completo.

Hasta que se emite commit transaction , SQL Server considera todas las instrucciones subsiguientes como parte de la transacción, a menos que se encuentre con otra instrucción begin transaction . En este punto, SQL Server considera todas las instrucciones subsiguientes como parte de esta nueva transacción anidada. Las transacciones anidadas se describen en la próxima sección.

rollback transaction o save transaction no afectan a SQL Server y no devuelven ningún mensaje de error si no hay ninguna transacción activa.

Verificación del estado de las transacciones

La variable global @@transtate realiza un seguimiento del estado actual de una transacción. SQL Server determina qué estado debe devolver realizando un seguimiento de los cambios de transacción que puedan tener lugar después de la ejecución de la instrucción. @@transtate puede contener los siguientes valores:

Tabla 17-3: Valores de @@transtate

Valor Significado

0 Transacción en proceso. Hay una transacción implícita o explícita en efecto; la instrucción anterior se ha ejecutado de forma correcta.

1 Transacción ejecutada de forma correcta. La transacción ha finalizado y ha consignado sus cambios.

2 Instrucción abortada. La instrucción anterior se ha abortado; no ha tenido ningún efecto sobre la transacción.

3 Transacción abortada. La transacción se ha abortado y ha revertido los cambios efectuados.

En una transacción, es posible utilizar @@transtate después de una instrucción (como insert ) para determinar si se ha ejecutado de forma correcta o se ha abortado y su efecto sobre la transacción. El siguiente ejemplo verifica @@transtate durante una transacción (tras una operación insert correcta) y después de que la transacción se consigne:

begin transaction

insert into publishers (pub_id) values ('9999')

(1 row affected)

select @@transtate

----------

0

(1 row affected)

commit transaction

select @@transtate

Page 256: 80575032 Libro de SQL y Tl SQL Excelente

Page 256 of 280

----------

1

(1 row affected)

El siguiente ejemplo verifica @@transtate después de una operación insert no correcta (debido a una violación de regla) y después de que la transacción se revierta:

begin transaction

insert into publishers (pub_id) values ('7777')

Msg 552, Level 16, State 1:

Una columna insertada o actualizada entra en conflicto con una regla vinculada a la columna.

El comando ha sido abortado. El conflicto se produjo en la base de 'pubs2', tabla

'publishers', regla 'pub_idrule', columna 'pub_id'.

select @@transtate

----------

2

(1 row affected)

rollback transaction

select @@transtate

----------

3

(1 row affected)

Sin embargo, a diferencia de @@error , SQL Server no borra @@transtate después de cada instrucción. Cambia @@transtate sólo como respuesta a una acción llevada a cabo por una transacción.

Transacciones anidadas

Es posible anidar transacciones dentro de otras transacciones. Cuando se anidan las instrucciones begin transaction y commit transaction , el par más exterior es el que inicia y consigna la transacción. Los pares interiores sólo mantienen un seguimiento del nivel de anidación. SQL Server no consigna la transacción hasta que se emite la instrucción commit transaction que coincide con la instrucción begin transaction más exterior.

SQL Server proporciona una variable global, @@trancount , que mantiene un seguimiento del nivel de anidación actual de las transacciones. Una instrucción begin transaction incial implícita o explícita define @@ trancount en 1. Cada begin transaction subsiguiente aumenta @@trancount y commit transaction la reduce. La activación de un disparador también incrementa @@ trancount y la transacción se inicia con la instrucción que activa el disparador. Las transacciones anidadas no se consignan hasta que @@trancount es igual a 0.

Por ejemplo, SQL Server no consigna los siguientes grupos de instrucciones anidados hasta la instrucción commit transaction final:

begin tran

select @@trancount

/* @@trancount = 1 */

begin tran

select @@trancount

/* @@trancount = 2 */

begin tran

select @@trancount

/* @@trancount = 3 */

commit tran

commit tran

commit tran

select @@trancount

/* @@ trancount = 0 */

Cuando se anida una instrucción rollback transaction sin incluir un nombre de transacción o punto de resguardo, siempre revierte a la instrucción begin transaction más exterior y cancela la transacción.

Page 257: 80575032 Libro de SQL y Tl SQL Excelente

Page 257 of 280

Ejemplo de una transacción definida por el usuario

Este ejemplo muestra el modo en que se podría especificar una transacción definida por el usuario:

begin transaction royalty_change

/* Un usuario trata de cambiar la división de

** derechos de autor de los dos autores de The

** Gourmet Microwave. */

/* Dado que la base de datos sería inconsistente

** entre las dos actualizaciones, deben agruparse

** en una transacción. */

update titleauthor

set royaltyper = 65

from titleauthor, titles

where royaltyper = 75

and titleauthor.title_id = titles.title_id

and title = "The Gourmet Microwave"

update titleauthor

set royaltyper = 35

from titleauthor, titles

where royaltyper = 25

and titleauthor.title_id = titles.title_id

and title = "The Gourmet Microwave"

save transaction percent_changed

/* Una vez actualizadas las entradas royaltyper

** de los dos autores, el usuario inserta el

** punto de resguardo "percent_changed" y luego

** verifica cómo afectaría un aumento del 10% en

** el precio a las ganancias por derechos de autor

** de los autores. */

update titles

set price = price * 1.1

where title = "The Gourmet Microwave"

select (price * royalty * total_sales) * royaltyper

from titles, titleauthor, roysched

where title = "The Gourmet Microwave"

and titles.title_id = titleauthor.title_id

and titles.title_id =roysched.title_id

rollback transaction percent_changed

/* La transacción se revierte al punto de

** resguardo con el comando rollback transaction.

** Sin un punto de resguardo, se revertería al

** principio de la transacción. */

commit transaction

Selección del modo y nivel de aislamiento de las transacciones

SQL Server proporciona dos opciones que pueden definirse para dar soporte a las transacciones compatibles con las normas SQL. Estas opciones definen el modo y el nivel de aislamiento de las transacciones, y deberían definirse al comienzo de cada sesión que requiera transacciones compatibles con normas SQL.

SQL Server admite los siguientes modos de transacción:

El modo predeterminado, llamado no encadenado o modo Transact-SQL, requiere instrucciones begin transaction explícitas emparejadas con instrucciones commit transaction o rollback transaction para completar la transacción.

Page 258: 80575032 Libro de SQL y Tl SQL Excelente

Page 258 of 280

El modo compatible con las normas SQL, llamado modo encadenado , inicia una transacción de forma implícita antes de cualquier instrucción de recuperación o modificación de datos. Estas instrucciones incluyen: delete , insert , open , fetch , select y update . Sin embargo, es necesario finalizar la transacción explícitamente con commit transaction o rollback transaction .

Puede definir los dos modos mediante la opción chained del comando set . Sin embargo, no debería mezclar estos modos de transacción en las aplicaciones. El comportamiento de los procedimientos almacenados y los disparadores puede variar según el modo y es posible que precise una acción especial para ejecutar un procedimiento en un modo que se creó en el otro.

SQL Server admite los siguientes niveles de aislamiento para las transacciones:

Nivel 0 - SQL Server garantiza que los datos escritos por una transacción representen los datos reales. Este nivel evita que otras transacciones escriban sobre los mismos datos antes de que la transacción se consigne. Los otras transacciones pueden leer los datos no consignados.

Nivel 1 - SQL Server garantiza que los datos leídos por una transacción representen los datos reales, no los datos del proceso de otra transacción no consignada. Este es el nivel de aislamiento predeterminado soportado por SQL Server.

Nivel 3 - SQL Server garantiza que los datos leídos por una transacción sean válidos hasta el final de dicha transacción. SQL Server da soporte a este nivel mediante la palabra clave holdlock de la instrucción select que aplica un bloqueo de lectura en los datos especificados.

Es posible definir el nivel de aislamiento de la sesión mediante la opción transaction isolation level del comando set . Puede imponer el nivel de aislamiento sólo para una consulta en lugar de usar la cláusula at isolation de la instrucción select .

En las siguientes secciones se describen estas opciones de forma más detallada.

Selección de un modo de transacción

Las normas SQL requieren que todas las instrucciones SQL de recuperación y modificación de datos tengan lugar dentro de una transacción. Una transacción se inicia de forma automática con la primera instrucción de recuperación o modificación de datos después del inicio de una sesión o después de que la transacción anterior se consigne o aborte. Este es el modo de transacción encadenado.

Puede definir este modo para la sesión actual mediante la activación de la opción chained de la instrucción set . Por ejemplo:

set chained on

Sin embargo, no puede ejecutar el comando set chained dentro de una transacción. Para volver al modo no encadenado de las transacciones, defina la opción chained como off . El modo predeterminado es no encadenado.

En el modo encadenado de las transacciones, SQL Server ejecuta de forma implícita una instrucción begin transaction justo antes de las siguientes instrucciones de recuperación o modificación de datos: delete , insert , open , fetch , select y update . Por ejemplo, el siguiente grupo de instrucciones genera diferentes resultados dependiendo del modo que se utilice:

insert into publishers

values ('9999', null, null, null)

begin transaction

delete from publishers where pub_id = '9999'

rollback transaction

En el modo no encadenado, rollback sólo afecta a la instrucción delete , por lo que publishers todavía contiene la fila insertada. En el modo encadenado, la instrucción insert inicia de forma implícita una transacción y la reversión afecta a todas las instrucciones hasta el comienzo de dicha transacción, incluida la instrucción insert .

Aunque el modo encadenado inicia de forma implícita las transacciones con instrucciones de recuperación o modificación de datos, sólo puede anidar transacciones mediante el uso explícito de instrucciones begin transaction . Una vez que comienza la primera transacción implícitamente, las instrucciones de recuperación o modificación de datos posteriores dejan de iniciar transacciones hasta después de que la primera transacción se consigne o aborte. Por ejemplo, en la siguiente consulta, la primera instrucción commit transaction consigna todos los cambios en modo encadenado; la segunda instrucción commit no es necesaria:

insert into publishers

values ('9999', null, null, null)

insert into publishers

Page 259: 80575032 Libro de SQL y Tl SQL Excelente

Page 259 of 280

values ('9997', null, null, null)

commit transaction

commit transaction

Note: En el modo encadenado, una instrucción de recuperación o modificación de datos inicia una transacción independientemente de que se ejecute de forma correcta. Incluso una instrucción select que no acceda a una tabla comienza una transacción.

Puede verificar la variable global @@tranchained para determinar el modo de transacción actual de SQL Server. select @@tranchained devuelve 0 para el modo no encadenado o 1 para el encadenado.

Selección de un nivel de aislamiento

La norma SQL92 define cuatro niveles de aislamiento para las transacciones. Cada nivel de aislamiento especifica los tipos de acciones que no están permitidos cuando se ejecutan transacciones concurrentes. Los niveles más altos incluyen las restricciones impuestas por los niveles más bajos:

El nivel 0 evita que otras transacciones cambien los datos que ya han sido modificados (mediante insert , delete , update , etc.) por una transacción no consignada. Las otras transacciones se bloquean para que no modifiquen los datos hasta que la transacción se haya consignado. No obstante, las otras transacciones todavía pueden leer los datos no consignados, lo que da lugar a lecturas sucias .

El nivel 1 evita las lecturas sucias. Estas lecturas tienen lugar cuando una transacción modifica una fila y luego una segunda transacción lee esa misma fila antes de que la primera transacción haya podido consignar el cambio. Si la primera transacción revierte el cambio, la información leída por la segunda transacción se convierte en inválida.

El nivel 2 evita las lecturas no repetidas . Estas lecturas tienen lugar cuando una transacción lee una fila y luego una segunda transacción modifica dicha fila. Si la segunda transacción consigna el cambio, las lecturas subsiguientes realizadas por la primera transacción producen resultados diferentes a los de la primera lectura.

El nivel 3 evita las lecturas fantasma . Estas lecturas tienen lugar cuando una transacción lee un conjunto de filas que cumplen una condición de búsqueda y luego una segunda transacción modifica los datos (mediante una instrucción insert , delete , update , etc.). Si la primera transacción repite la lectura con las mismas condiciones de búsqueda, el conjunto de filas resultante es distinto.

De forma predeterminada, el nivel de aislamiento de transacción de SQL Server es 1. La norma SQL92 establece que el nivel predeterminado de todas las transacciones sea 3 para evitar las lecturas sucias, no repetidas y fantasma. Para imponer este nivel de aislamiento, Transact-SQL proporciona la opción transaction isolation level de set . Esta opción indica a SQL Server que aplique de forma automática una acción holdlock a todas las opciones select de una transacción. Por ejemplo:

set transaction isolation level 3

Las aplicaciones que emplean transaction isolation level 3 deberían definir este nivel de aislamiento al principio de cada sesión. Sin embargo, el uso de transaction isolation level 3 hace que SQL Server retenga los bloqueos de lectura durante la ejecución de la transacción. Si también utiliza el modo de transacción encadenado, ese nivel de aislamiento permanece en efecto para cualquier instrucción de recuperación o modificación de datos que inicie una transacción de forma implícita. En ambos casos, esto puede originar problemas de concurrencia para algunas aplicaciones, ya que es posible que se retengan más bloqueos durante periodos de tiempo más largos.

Para volver a asignar el nivel de aislamiento predeterminado de SQL Server a la sesión actual:

set transaction isolation level 1

Si se define transaction isolation level 0 al principio de cada sesión, las aplicaciones no afectadas por las lecturas sucias pueden presenciar una concurrencia menos problemática y un nivel de bloqueo insoluble reducido cuando acceden a los mismos datos. Un ejemplo es una aplicación que halla el saldo promedio momentáneo de todas las cuentas de ahorro almacenadas en un tabla. Dado que sólo necesita una captación instantánea del saldo promedio actual, que probablemente cambia con frecuencia en una tabla activa, la aplicación debería consultar la tabla con un nivel de aislamiento 0. Las aplicaciones que precisen una consistencia de datos, como los ingresos y extracciones de cuentas específicas de la tabla, deberían evitar el nivel 0.

Las consultas ejecutadas con el nivel de aislamiento 0 no adquieren ningún bloqueo de lectura durante sus operaciones de barrido, por lo que no impiden a otras transacciones que escriban en los mismos datos, ni viceversa. Sin embargo, aunque defina su nivel de aislamiento en 0, las utilidades (como dbcc ) e instrucciones de modificación de datos (como update ) todavía adquieren bloqueos de lectura para sus tareas de barrido, ya que deben mantener la integridad de la base de datos cerciorándose de que se han leído los datos correctos antes de modificarlos.

Page 260: 80575032 Libro de SQL y Tl SQL Excelente

Page 260 of 280

La variable global @@isolation contiene el nivel de aislamiento actual de la sesión de Transact-SQL. Al consultar @@isolation se obtiene el valor del nivel activo (0, 1 o 3). Por ejemplo:

select @@isolation

--------

1

(1 row affected)

Para obtener más información sobre los niveles de aislamiento y el bloqueo, consulte la Guía de Mejora de Rendimiento y Afinación .

Cambio del nivel de aislamiento de una consulta

Puede cambiar el nivel de aislamiento de una consulta usando la cláusula at isolation con las instrucciones select o readtext . Las opciones read uncommitted , read committed y serializable de at isolation representan cada nivel de aislamiento al igual que se indica a continuación:

Opción de at isolation Nivel de aislamiento

read uncommited 0

read committed 1

serializable 3

Por ejemplo, las dos instrucciones siguientes consultan la misma tabla con los niveles de aislamiento 0 y 3, respectivamente:

select *

from titles

at isolation read uncommitted

select *

from titles

at isolation serializable

La cláusula at isolation sólo es válida para consultas select y readtext individuales o en la instrucción declare cursor . SQL Server devuelve un error de sintaxis si at isolation se utiliza:

Con una consulta que usa la cláusula into

Dentro de una subconsulta

Con una consulta en la instrucción create view

Con una consulta en la instrucción insert

Con una consulta que usa la cláusula for browse

Si hay un operador union en la consulta, debe especificar la cláusula at isolation después de la última instrucción select .

La norma SQL92 define read uncommitted , read committed y serializable como opciones para at isolation (y set transaction isolation level ). Una extensión Transact-SQL también permite especificar 0, 1 o 3 para at isolation . Para simplificar la explicación sobre los niveles de aislamiento, los ejemplos de at isolation de este manual no usan esta extensión.

También puede imponer el nivel de aislamiento 3 usando la palabra clave holdlock de la instrucción select . Sin embargo, no es posible especificar holdlock , noholdlock ni shared en una consulta que también indica at isolation read uncommitted . Si emplea distintas formas de definir un nivel de aislamiento, la palabra clave holdlock tiene prioridad sobre la cláusula at isolation (salvo el nivel de aislamiento 0) y esta cláusula tiene prioridad sobre el nivel de sesión definido por set transaction isolation level .

Cursores y niveles de aislamiento

Puede utilizar la cláusula at isolation de la instrucción select para cambiar el nivel de aislamiento de un cursor. Por ejemplo:

declare commit_crsr cursor

for select *

from titles

at isolation read committed

Page 261: 80575032 Libro de SQL y Tl SQL Excelente

Page 261 of 280

Esta instrucción hace que el cursor funcione con el nivel de aislamiento 1, sea cual sea el nivel de la transacción o sesión. Si declara un cursor con el nivel de aislamiento 0 ( read uncommitted ), SQL Server también define el cursor como de sólo lectura. No es posible especificar la cláusula for update con at isolation read uncommitted en una instrucción declare cursor .

SQL Server establece el nivel de aislamiento de un cursor al abrirlo, no al declararlo. Una vez abierto el cursor, SQL Server determina su nivel de aislamiento conforme a lo siguiente:

Si el cursor se declara con la cláusula at isolation , este nivel de aislamiento reemplaza al nivel de aislamiento de transacción con el que se abre.

Si el cursor no se declara con at isolation , dicho cursor utiliza el nivel de aislamiento con el que se abre. Si cierra el cursor y luego lo vuelve a abrir, el cursor adquiere el nivel de aislamiento actual de la transaccción.

Con respecto al último punto, es necesario resaltar que algunos tipos de cursores (idioma y cliente) declarados en una transacción con el nivel de aislamiento 1 o 3 no pueden abrirse en una transacción con el nivel 0. Para obtener más información sobre esta restricción y los distintos tipos de cursores, consulte el Manual de Referencia de SQL Server.

Procedimientos almacenados y niveles de aislamiento

Los procedimientos almacenados del sistema de Sybase siempre funcionan con el nivel de aislamiento 1, sea cual sea el nivel de la transacción o sesión. Los procedimientos almacenados del usuario utilizan el nivel de aislamiento de la transacción donde se ejecutan. Si el nivel de aislamiento cambia dentro de un procedimiento almacenado, el nivel nuevo sólo permanece en efecto durante la ejecución del procedimiento almacenado.

Disparadores y niveles de aislamiento

Como los disparadores se activan mediante instrucciones de modificación de datos (como insert ), todos los disparadores se ejecutan con el nivel de aislamiento de la transacción o con el 1, el que sea mayor. En consecuencia, si un disparador se activa en una transacción con el nivel 0, SQL Server define el nivel de aislamiento del disparador en 1 antes de ejecutar su primera instrucción.

Uso de transacciones en procedimientos almacenados y disparadores

Es posible utilizar transacciones en procedimientos almacenados y disparadores del mismo modo que con los lotes de instrucciones. Si una transacción de un lote o procedimiento almacenado llama a otro procedimiento almacenado o disparador que contiene una transacción, la segunda transacción se anida en la primera.

La primera instrucción begin transaction explícita o implícita (que usa el modo encadenado) inicia la transacción del lote, procedimiento almacenado o disparador. Cada begin transaction subsiguiente aumenta el nivel de anidación. Cada commit transaction subsiguiente reduce el nivel de anidación hasta que alcanza el 0. A continuación, SQL Server consigna la transacción completa. rollback transaction aborta la transacción completa hasta la primera instrucción begin transaction , independientemente del nivel de anidación o el número de procedimientos almacenados y disparadores que abarque.

En los procedimientos almacenados y disparadores, el número de instrucciones begin transaction debe coincidir con el número de instrucciones commit transaction . Esto también se aplica a los procedimientos almacenados que utilizan el modo encadenado. La primera instrucción que inicia implícitamente una transacción también debe tener una commit transaction coincidente.

El siguiente diagrama muestra lo que puede ocurrir cuando se anidan instrucciones de transacción dentro de procedimiento almacenados:

Figure 17-5: Anidación de instrucciones de transacción

Las instrucciones rollback transaction incluidas en procedimientos almacenados no afectan a las instrucciones subsiguientes del procedimiento o lote que llamó originalmente al procedimiento. SQL Server ejecuta las instrucciones subsiguientes del procedimiento almacenado o lote. Sin embargo, las instrucciones rollback transaction en disparadores abortan el lote a fin de que las instrucciones subsiguientes no se ejecuten.

Por ejemplo, el siguiente lote llama al procedimiento almacenado myproc que incluye una instrucción rollback transaction :

begin tran

update titles set ...

insert into titles ...

Page 262: 80575032 Libro de SQL y Tl SQL Excelente

Page 262 of 280

execute myproc

delete titles where ...

Las instrucciones update e insert se revierten y la transacción se aborta. SQL Server continúa el lote y ejecuta la instrucción delete . Sin embargo, si hay un disparador insert en una tabla que incluye rollback transaction , se aborta todo el lote y delete no se ejecuta. Por ejemplo:

begin tran

update authors set ...

insert into authors ...

delete authors where ...

El uso de diferentes modos o niveles de aislamiento de transacción para procedimientos almacenados tiene determinados requisitos, que se describen en la siguiente sección. Los disparadores no se ven afectados por el modo de transacción actual, puesto que siempre son llamados como parte de una instrucción de modificación de datos.

Modos y niveles de aislamiento de transacción en procedimientos almacenados

Los procedimientos almacenados escritos para utilizar el modo no encadenado de las transacciones puede ser incompatible con otras transacciones que usan el modo encadenado, y viceversa. Por ejemplo, a continuación se muestra un procedimiento almacenado válido que utiliza el modo encadenado:

create proc myproc

as

insert into publishers

values ('9999', null, null, null)

commit work

Un programa que utilice el modo no encadenado de transacciones fallaría si llamase a este procedimiento porque commit no tiene el comando correspondiente begin . Es posible encontrar otros problemas:

Las aplicaciones que inician una transacción que utiliza el modo encadenado pueden crear transacciones increiblemente largas o retener bloqueos de datos durante toda su sesión. Este comportamiento reduce el rendimiento de SQL Server.

Las aplicaciones pueden anidar transacciones en momentos imprevistos. Esto puede generar resultados diferentes dependiendo del modo de transacción.

Como norma general, las aplicaciones que utilizan un modo de transacción deberían llamar a procedimientos almacenados escritos para usar el mismo modo. Las excepciones a dicha regla son los procedimientos almacenados del sistema SYBASE (que no incluyen a sp_procxmode descrito más adelante), que pueden ser llamados por sesiones que utilizan cualquier modo de transacción. Si no hay ninguna transacción activa al ejecutar un procedimiento almacenado del sistema, SQL Server desactiva el modo encadenado durante la ejecución del procedimiento. Antes de volver, el programa restablece el parámetro original del modo.

SQL Server etiqueta todos los procedimientos con el modo de transacción ("encadenado" o "no encadenado") de la sesión en la que se crean. Esto ayuda a evitar problemas asociados con transacciones que utilizan un modo que invocan otras transacciones que usan otro modo. Un procedimiento almacenado etiquetado como "encadenado" no es ejecutable en sesiones que utilizan el modo de transacción no encadenado, y viceversa.

Warning! Cuando emplee los modos de transacción, tenga presente los efectos que cada parámetro puede tener en sus aplicaciones.

Definición de modos de transacción para procedimientos almacenados

Puede utilizar el procedimiento almacenado del sistema sp_procxmode para cambiar el valor de etiqueta asociado a un procedimiento almacenado. SQL Server también proporciona una tercera etiqueta, "anymode" ("cualquier etiqueta"), que puede utilizar con sp_procxmode para señalar los procedimientos del sistema que pueden ejecutarse en cualquier modo de transacción. Por ejemplo:

sp_procxmode byroyalty, "anymode"

Use sp_procxmode sin valores de parámetro para obtener los modos de transacción de todos los procedimientos almacenados de la base de datos actual:

Page 263: 80575032 Libro de SQL y Tl SQL Excelente

Page 263 of 280

sp_procxmode

procedure name transaction mode

------------------------- --------------------

byroyalty Unchained

discount_proc Unchained

insert_sales_proc Unchained

insert_salesdetail_proc Unchained

storeid_proc Unchained

storename_proc Unchained

title_proc Unchained

titleid_proc Unchained

(8 rows affected, return status = 0)

Sólo se puede utilizar sp_procxmode en el modo de transacción no encadenado.

Para cambiar el modo de transacción de un procedimiento, es necesario ser un administrador del sistema, el propietario de la base de datos o el propietario del procedimiento.

Uso de cursores en transacciones

De forma predeterminada, SQL Server no cambia el estado de un cursor (abierto o cerrado) cuando una transacción finaliza por una consignación o reversión. Sin embargo, las normas SQL asocian un cursor abierto con su transacción activa. La consignación o reversión de esa transacción cierra automáticamente todos los cursores abiertos asociados a ella.

Para imponer este comportamiento compatible con las normas SQL, SQL Server proporciona la opción close on endtran del comando set . Además, si se activa el modo encadenado, SQL Server inicia una transacción cuando se abre un cursor y cierra el cursor cuando la transacción se consigna o revierte.

Por ejemplo, la siguiente secuencia de instrucciones genera de forma predeterminada un error:

open cursor test

commit tran

open cursor test

Si define las opciones close on endtran o chained , el estado del cursor pasa de abierto a cerrado después de la consignación. Esto permite que el cursor se vuelva a abrir.

Los bloqueos exclusivos adquiridos por un cursor en una transacción se retienen hasta el final de dicha transacción. Esto también se aplica a los bloqueos compartidos cuando se usa la palabra clave holdlock , la cláusula at isol a tion serializable o la opción set isol a tion level 3 . Sin embargo, si no define la opción close on endtran , el cursor permanece abierto después del final de la transacción y su bloqueo de página actual permanece en efecto. Asimismo, el cursor podría continuar adquiriendo bloqueos conforme recobrara filas adicionales.

Copia de seguridad y recuperación de transacciones

Todos los cambios efectuados en la base de datos, independientemente de que sean el resultado de una sola instrucción update o de un conjunto agrupado de instrucciones SQL, se registran de forma automática en la tabla del sistema syslogs . A esta tabla se le llama diario de transacciones .

Algunos comandos que cambian la base de datos no se registran, como truncate table , la copia masiva en una tabla que no tiene índices, select into , writetext y dump transaction with no_log .

El diario de transacciones registra las instrucciones update , insert o delete cada pocos segundos. Cuando comienza una transacción, se registra un evento begin transaction en el diario. Las instrucciones de modificación de datos se registran en el diario conforme se reciben.

El cambio siempre se registra en el diario antes de que se realice ningún cambio en la base de datos en sí. Este tipo de diario, llamado registro de escritura anticipada, garantiza que la base de datos pueda recuperarse completamente en caso de que se produzca un fallo.

Los fallos se pueden producir por problemas del hardware o de los medios, problemas del software de sistema, problemas del software de aplicación, cancelaciones de transacciones dirigidas por el programa o decisiones de usuario de cancelar una transacción.

Page 264: 80575032 Libro de SQL y Tl SQL Excelente

Page 264 of 280

En caso de generarse alguno de estos fallos, el diario de transacciones puede reproducirse frente a una copia de la base de datos restaurada a partir de una copia de seguridad realizada con los comandos dump .

Para recuperarse de un fallo, las transacciones que estaban en proceso, pero aún sin consignar, en el momento del fallo deben deshacerse, puesto que una transacción parcial no es un cambio exacto. Las transacciones finalizadas deben rehacerse si no hay garantía de que se hayan escrito en el dispositivo de bases de datos.

Si hay transacciones activas de larga duración todavía sin consignar en el momento en que SQL Server falla, el proceso para deshacer los cambios puede necesitar tanto tiempo como el invertido en ejecutar la transacción. Estos casos incluyen transacciones que no contienen commit transaction ni rollback transaction para que coincidan con begin transaction . Esto evita que SQL Server escriba ningún cambio y aumenta el tiempo de recuperación.

El volcado dinámico de SQL Server permite realizar copias de seguridad de la base de datos y del diario de transacciones mientras la base de datos continúa en uso. Realice copias de seguridad frecuentes del diario de transacciones de la base de datos. Cuanto más a menudo realice copias de seguridad de los datos, menor será la cantidad de trabajo que pierda en caso de un fallo del sistema.

El propietario de cada base de datos o los usuarios con una autorización OPER son responsables de la copia de seguridad de la base de datos y de su diario de transacciones con los comandos dump , aunque el permiso para ejecutarlos puede transferirse a otros usuarios. Sin embargo, el permiso para utilizar los comandos load corresponde predeterminadamente al propietario de la base de datos y no puede transferirse.

Una vez emitidos los comandos load adecuados, SQL Server administra todos los aspectos del proceso de recuperación. SQL Server también controla de forma automática el intervalo del punto de verificación, que es el punto en el que todas las páginas de datos que se han cambiado tienen garantía de haberse escrito en el dispositivo de bases de datos. Los usuarios pueden forzar un punto de verificación si es necesario con el comando checkpoint .

Para obtener más información, consulte el Manual de Referencia de SQL Server y la Guía de Administración del Sistema.

Glosario

acciones de disparador

Acción para la que se especifica un disparador.

actualización

Adición, eliminación o modificación de datos utilizando las instrucciones insert , delete , truncate table o update .

administrador del sistema

Usuario autorizado para manejar la administración del sistema SQL Server, incluida la creación de cuentas de usuario, asignación de permisos y creación de bases de datos.

alcance del cursor

Región en la que se reconoce el cursor. El nombre de cursor existe sólo mientras exista su alcance. El alcance es de uno de los tres tipos siguientes:

Sesión - la región se inicia cuando el cliente se conecta a SQL Server y finaliza cuando se desconecta. Esta región no incluye cualquier región definida por procedimientos almacenados o disparadores.

Procedimiento almacenado - la región se inicia cuando un procedimiento almacenado comienza la ejecución y finaliza cuando la completa.

Disparador- la región se inicia cuando un disparador comienza la ejecución y finaliza cuando la completa.

Los nombres de cursor deben ser únicos dentro de su alcance. Por ejemplo, un procedimiento almacenado no puede declarar dos cursores con el mismo nombre.

alias

Page 265: 80575032 Libro de SQL y Tl SQL Excelente

Page 265 of 280

Permite que un usuario de SQL Server sea reconocido como otro usuario en una base de datos. Utilice sp_addalias para crear un alias.

argumento

Valor suministrado para una función o procedimiento, necesario para evaluar la función.

autocombinación

Combinación utilizada para comparar valores dentro de una columna de una tabla. Puesto que esta operación relaciona una combinación de una tabla consigo misma, es preciso asignar dos nombres temporales a la tabla, o nombres de correlación , que se utilizan para calificar los nombres de columna en el resto de la consulta.

barridos del cursor

Proceso de generación de un conjunto de resultados del cursor.

base de datos

Conjunto de tablas de datos relacionados y otros objetos de base de datos organizados y presentados para un fin específico.

base de datos master

Controla las bases de datos de usuarios y el funcionamiento general de SQL Server. Conocida como master , realiza el seguimiento de las cuentas de usuario, procesos permanentes y mensajes de error del sistema.

base de datos predeterminada

Base de datos a la que un usuario se conecta al hacer el login.

bases de datos del sistema

Bases de datos de un SQL Server instalado recientemente: master , que controla las bases de datos de usuarios y las operaciones de SQL Server; tempdb , utilizada para tablas temporales; model , utilizada como un modelo para crear nuevas bases de datos de usuario; y sybsystemprocs , que almacena los procedimientos del sistema.

bloque de instrucciones

Consiste de una serie de instrucciones Transact-SQL incluidas entre las palabras clave begin y end , de forma que se interpretan como una unidad.

bloqueo

Proceso de restricción de acceso a recursos en un entorno multiusuario para mantener la seguridad e impedir que se produzcan problemas de acceso. SQL Server aplica bloqueos a tablas o páginas de forma automática.

bloqueo activo

Solicitud de un bloqueo exclusivo que se deniega repetidamente debido a la interferencia de una serie de bloqueos compartidos simultáneos. SQL Server detecta la situación después de cuatro rechazos y no admite más bloqueos compartidos.

bloqueo compartido

bloqueo creado por operaciones de no actualización ("lectura"). Otros usuarios pueden leer los datos simultáneamente, pero ninguna transacción puede adquirir un bloqueo exclusivo sobre los datos hasta que se hayan liberado todos los bloqueos compartidos.

bloqueo de demanda

Page 266: 80575032 Libro de SQL y Tl SQL Excelente

Page 266 of 280

Impide que se definan más bloqueos compartidos en un recurso de datos (tabla o página de datos). Cualquier nueva solicitud de bloqueo compartido tiene que esperar a que termine la solicitud de bloqueo de demanda.

bloqueo insoluble

Situación que se produce cuando dos usuarios, cada uno de los cuales mantiene un bloqueo sobre una parte de los datos, intenta adquirir un bloqueo sobre la otra parte de los datos. SQL Server detecta los bloqueos insolubles y destruye el proceso de uno de los usuarios.

bloqueo intent

Indica la intención de adquirir un bloqueo compartido o exclusivo sobre una página de datos.

bloqueos de actualización

Bloqueos que garantizan que sólo una operación pueda modificar datos en una página. Otras transacciones pueden leer los datos mediante bloqueos compartidos. SQL Server aplica bloqueos de actualización cuando se inicia una operación update o delete .

bloqueos exclusivos

Bloqueos que impiden que cualquier otra transacción adquiera un bloqueo hasta que se libere el bloqueo original al final de una transacción. Siempre se aplican a operaciones de actualización ( insert , update , delete ).

cadena hexadecimal

Cadena binaria con codificación hexadecimal que comienza con el prefijo 0x y que puede incluir los dígitos de 0 a 9 y las letras mayúsculas y minúsculas de la A a la F. La interpretación de cadenas de caracteres hexadecimales es específica de la plataforma. Para algunos sistemas, el primer byte después del prefijo es el más significativo; para otros, es el último byte. Por ejemplo, la cadena de caracteres 0x0100 se interpreta como 1 en algunos sistemas, y como 256, en otros.

calificado

El nombre de un objeto de base de datos puede ser calificado, o ir precedido del nombre de base de datos y del propietario del objeto.

campo

Valor de datos que describe una característica de una entidad. También denominado columna .

carácter comodín

Carácter especial utilizado con la palabra clave de Transact-SQL like que puede representar un carácter (el carácter de subrayado, _) o un número cualquiera de caracteres (signo de porcentaje, %) que coincidan con un modelo de referencia.

cláusula predeterminada

Especifica el valor predeterminado para una columna en la instrucción create table .

cláusulas

Conjunto de palabras claves y parámetros que adaptan un comando Transact-SQL para satisfacer una necesidad determinada. Este término también se denomina frase de palabras clave .

clave

Campo utilizado para identificar un registro, a menudo empleado como el campo de índice para una tabla.

clave externa

Page 267: 80575032 Libro de SQL y Tl SQL Excelente

Page 267 of 280

Columna clave de una tabla que depende lógicamente de una columna de clave primaria de otra tabla. También es una columna (o combinación de columnas) cuyos valores deben coincidir con una clave primaria en alguna otra tabla.

clave primaria

Columna o columnas cuyos valores identifican de forma exclusiva una fila de una tabla.

columna

Equivalente lógico de un campo. Una columna contiene un elemento de datos individual dentro de una fila o registro.

columna IDENTITY

Columna con valores generados por el sistema que identifican cada columna de una tabla de forma exclusiva. Las columnas IDENTITY almacenan números únicos, como números de facturas o números de empleados, que SQL Server genera automáticamente. El valor de la columna IDENTITY identifica cada fila de una tabla de forma exclusiva.

comando

Instrucción que especifica una operación para que la computadora la realice. Cada comando o instrucción SQL comienza con una palabra clave, como insert , que asigna nombre a la operación básica realizada. Muchos comandos SQL tienen una o más frases de palabras clave o cláusulas , que adaptan el comando para satisfacer una necesidad determinada.

combinación

Operación básica de un sistema relacional que enlaza las filas de dos o más tablas comparando los valores de columnas especificadas.

combinación desigual

Combinación realizada en términos de desigualdad.

combinación externa

Combinación que devuelve filas coincidentes y no coincidentes. Los operadores *= y =* se emplean para solicitar la devolución de todas las filas de la primera y segunda tabla, independientemente de si existe o no alguna coincidencia en la columna de combinación.

combinación natural

Combinación en la que los valores de las columnas combinadas se comparan en términos de igualdad, y todas las columnas de las tablas se incluyen en los resultados, a menos que sólo se incluya una columna de cada par de columnas combinadas.

combinación theta

Combinaciones que utilizan los operadores de comparación como condición de combinación. Los operadores de comparación incluyen: igual (=), no igual (!=), mayor que (>), menor que (<), mayor o igual a (>=) y menor o igual a (<=).

concatenación

Combinación de expresiones para crear expresiones mayores. Las expresiones pueden incluir cualquier combinación de cadenas de caracteres o binarias, o de nombres de columna.

condiciones de disparador

Condiciones que provocan la activación de un disparador.

conjunto de resultados del cursor

Conjunto de filas resultantes de la ejecución de la instrucción select asociada con el cursor.

Page 268: 80575032 Libro de SQL y Tl SQL Excelente

Page 268 of 280

consulta

1. Solicitud para la recuperación de datos con una instrucción select .

2. Cualquier instrucción SQL que manipula datos.

consulta externa

Nombre alternativo de la consulta principal de una instrucción que contiene una subconsulta.

consulta interna

También denominada subconsulta.

consultas anidadas

Instrucciones select que contienen una o más subconsultas.

conversiones implícitas

Conversiones de tipos de datos realizadas automáticamente por SQL Server para comparar tipos de datos.

creador de indicadores FIPS

Para definir el creador de indicadores FIPS (Federal Information Processing Standards), es preciso que se indiquen todas las mejoras realizadas al lenguaje SQL sin normalizar. FIPS reconoce SQL89 como norma base.

cursor

Nombre simbólico asociado con una instrucción select Transact-SQL mediante una instrucción de declaración. Los cursores se componen de dos partes: el conjunto de resultados del cursor y la posición del cursor .

cursor cliente

Cursor declarado mediante llamadas Open Client o Embedded SQL. Open Client hace un seguimiento de las filas devueltas por SQL Server y las pone en memoria intermedia para la aplicación. Las actualizaciones y eliminaciones del conjunto de resultados de los cursores cliente sólo pueden realizarse mediante llamadas Open Client.

cursor de ejecución

Subconjunto de cursores de Open Client, cuyo conjunto de resultados se define mediante un procedimiento almacenado que tiene una sola instrucción select . El procedimiento almacenado puede utilizar parámetros. Los valores de los parámetros se envían mediante llamadas Open Client.

cursor de idioma

Cursor declarado en SQL sin utilizar Open Client. Al igual que con los cursores de SQL Server, Open Client ignora completamente los cursores, y los resultados se devuelven al cliente con el mismo formato que una operación select normal.

cursor del servidor

Cursor declarado dentro de un procedimiento almacenado. El cliente que ejecuta el procedimiento almacenado no percibe la presencia de estos cursores. Los resultados de un fetch recibidos por el cliente aparecen exactamente del mismo modo que los resultados de una operación select normal.

datos discípulos

Datos que dependen de otra tabla lógicamente. Por ejemplo, en la base de datos pubs2 , la tabla salesdetail es una tabla discípula. Cada pedido de la tabla sales puede tener un gran número de entradas correspondientes en salesdetail . Cada elemento de salesdetail carece de significado sin una entrada correspondiente en la tabla sales .

Page 269: 80575032 Libro de SQL y Tl SQL Excelente

Page 269 of 280

definición de datos

Proceso de definición de bases de datos y de creación de objetos de base de datos, como tablas, índices, reglas, valores predeterminados, procedimientos, disparadores y vistas.

dependiente

Los datos dependen lógicamente de otros datos cuando los datos maestros de una tabla deben mantenerse sincronizados con los datos discípulos de otra tabla, a fin de proteger la consistencia lógica de la base de datos.

diario de transacciones

Tabla del sistema ( syslogs ) en la que se registran todos los cambios realizados en la base de datos.

diccionario de datos

Tablas del sistema que contienen descripciones de los objetos de base de datos y de su estructura.

disparador

Forma especial de un procedimiento almacenado que se activa cuando un usuario ejecuta un comando de modificación como insert , delete o update en una tabla o columna especificada. Los disparadores se utilizan frecuentemente para imponer la integridad de referencia.

eliminación en cascada

Operación de eliminación que afecta a los datos relacionados en otras tablas.

equicombinación

Combinación basada en la igualdad.

errores fatales

Errores cuyo nivel de gravedad es 19 y superior. Un error fatal termina la sesión de trabajo del usuario y exige volver a hacer a el login.

escala

Número máximo de dígitos que un tipo de datos numeric o decimal puede almacenar a la derecha de la coma decimal. La escala debe ser inferior o igual a la precisión.

espacio del nombre de cursor

Región en la que se reconoce el cursor. Es una de los tres tipos siguientes:

sesión - La región se inicia cuando el cliente se conecta a SQL Server y finaliza cuando se desconecta. Esta región no incluye cualquier región definida por procedimientos almacenados o disparadores.

procedimiento almacenado - La región se inicia cuando un procedimiento almacenado comienza la ejecución y finaliza cuando la completa.

disparador- La región se inicia cuando un disparador comienza la ejecución y finaliza cuando la completa.

Los nombres de cursor deben ser únicos dentro de una región de alcance determinado. Por ejemplo, un procedimiento almacenado no puede declarar dos cursores con el mismo nombre.

esquema

Page 270: 80575032 Libro de SQL y Tl SQL Excelente

Page 270 of 280

Consiste de una serie de objetos asociados con un nombre de esquema particular y con un identificador de autorización de esquema. Los objetos son tablas, vistas, dominios, restricciones, axiomas, privilegios, etc.. Un esquema se crea con la instrucción create schema .

estabilidad del cursor

Nivel de bloqueo o aislamiento en el que SQL Server tiene un bloqueo compartido sobre páginas de la tabla base que contienen una fila del cursor actual. La página permanece bloqueada hasta que el cursor deja de posicionarse en la página (como resultado de operaciones de recobro). Si la tabla base tiene un índice, las páginas de índice correspondientes también tienen bloqueos compartidos.

estado de retorno

Valor que indica que el procedimiento se completó correctamente, o la razón del fallo.

expresión

Combinación de una o más constantes, literales, funciones, identificadores de columna o variables separadas por operadores que devuelven un valor único. Una expresión puede ser aritmética, relacional, lógica (booleana) o una cadena de caracteres.

expresión aritmética

Expresión que sólo contiene operandos numéricos y devuelve un valor numérico único. En Transact-SQL, los operandos pueden ser de cualquier tipo de datos numérico de SQL Server. Pueden ser funciones, variables, parámetros u otras expresiones aritméticas. Es sinónimo de expresión numérica .

expresión booleana

Expresión que realiza una evaluación TRUE (1) o FALSE (0). Las expresiones booleanas se emplean con frecuencia en instrucciones de control de flujo, como las condiciones if o while .

expresión constante

Expresión que devuelve el mismo valor cada vez que ésta se utiliza. En las instrucciones de sintaxis Transact-SQL, constant_expression no incluye variables ni identificadores de columna.

expresión de caracteres

Expresión que devuelve un valor de tipo de caracteres único. Puede incluir literales, operadores de concatenación, funciones e identificadores de columna.

expresión lógica

Expresión que realiza una evaluación TRUE (1), FALSE (0) o UNKNOWN (NULL). Las expresiones lógicas se utilizan con frecuencia en instrucciones de control de flujo, como las condiciones if o while .

expresión numérica

Expresión que sólo contiene valores numéricos y que devuelve un valor numérico único. En Transact-SQL, los operandos pueden ser de cualquier tipo de datos numérico de SQL Server. Pueden ser funciones, variables, parámetros u otras expresiones aritméticas. Este término es sinónimo de expresión aritmética .

expresión relacional

Tipo de expresión booleana o lógica con el formato:

arith_expression relational_operator arith_expression

En Transact-SQL, una expresión relacional puede devolver TRUE, FALSE o UNKNOWN. Los resultados pueden evaluarse como UNKNOWN si una o ambas expresiones se evalúan como NULL.

Page 271: 80575032 Libro de SQL y Tl SQL Excelente

Page 271 of 280

fecha base

1 de enero de 1900; la fecha suministrada por SQL Server cuando un usuario no especifica un valor para una columna de fecha.

fila

Conjunto de columnas relacionadas que describe una entidad específica. También llamada registro .

fragmento

Cuando se asigna sólo parte del espacio de un dispositivo con create o alter database , dicha parte se denomina fragmento.

frases de palabras clave

Conjunto de palabras clave y de parámetros que adaptan un comando Transact-SQL para satisfacer una necesidad determinada. También denominadas cláusulas .

función agregada

Función que actúa sobre un conjunto de celdas para generar una respuesta única o conjunto de respuestas, una para cada subconjunto de celdas. Las funciones agregadas disponibles en Transact-SQL son: promedio ( avg ), máximo ( max ), mínimo ( min ), total ( sum ) y conteo del número de elementos ( count ).

función agregada de fila

Funciones ( sum , avg , min , max y count ) que generan una nueva fila de datos resumidos cuando se utilizan con compute en una instrucción select .

función agregada escalar

Función agregada que genera un valor único de una instrucción select sin una cláusula group by . Esto es verdadero tanto si la función agregada está operando en todas las filas de una tabla, como si lo hace en un subconjunto de filas definido por una cláusula where . Véase también función agregada vectorial.

función agregada vectorial

Valor resultante del uso de una función agregada con una cláusula group by . Véase también función agregada escalar .

función de cadena de caracteres

Función que opera sobre cadenas de caracteres o de datos binarios. substring y charindex son funciones de cadena de caracteres de Transact-SQL.

función de conversión de tipos de datos

Función que se utiliza para convertir expresiones de un tipo de datos en otro tipo de datos, siempre que estas conversiones no se realicen automáticamente por SQL Server.

función de fecha

Función que muestra información de fechas y horas, o manipula los valores de fecha y hora. Las funciones de fecha incluyen getdate , datename , datepart , datediff y dateadd .

función del sistema

Función que devuelve información especial de la base de datos, en particular, de las tablas del sistema.

funciones

Véase funciones incorporadas .

Page 272: 80575032 Libro de SQL y Tl SQL Excelente

Page 272 of 280

funciones incorporadas

Amplia variedad de funciones que toman uno o más parámetros y devuelven resultados. Las funciones incorporadas incluyen funciones matemáticas, del sistema, de cadena de caracteres, de texto, de fecha y de conversión de tipos.

ID de usuario del servidor

Número de ID por el que SQL Server conoce al usuario.

identificador

Cadena de caracteres utilizada para identificar un objeto de base de datos, como un nombre de tabla o de columna.

identificadores delimitados

Nombres de objeto incluidos entre comillas dobles que evitan determinadas restricciones sobre los nombres de objeto.

índice agrupado

Indice en el que el orden físico es igual que el orden lógico (indexado). El nivel de hoja de un índice agrupado representa las propias páginas de datos.

índice no agrupado

Indice que almacena valores clave y punteros a datos. El nivel de hoja apunta a páginas de datos, en lugar de contener los propios datos.

índices compuestos

Indices que utilizan más de una columna. Emplee índices compuestos cuando sea conveniente realizar búsquedas en dos o más columnas como unidad, debido a su relación lógica.

índices únicos

Indices que no permiten que dos filas de las columnas especificadas tengan el mismo valor. SQL Server busca valores duplicados cuando se crea el índice (si ya existen datos) y cada vez que se añaden datos.

informe de cortes de control

Informe o visualización de datos que corta los datos en grupos y genera información resumida para cada corte. Los cortes controlan la generación de datos resumidos.

instrucción

Comienza con una palabra clave que nombra la operación o comando básico que va a realizarse.

instrucciones select anidadas

Véase consultas anidadas .

int

Valor entero de 32 bits con signo.

integridad de datos

Corrección e integridad de los datos dentro de una base de datos.

integridad de referencia

Page 273: 80575032 Libro de SQL y Tl SQL Excelente

Page 273 of 280

Reglas que gobiernan la consistencia de datos, específicamente las relaciones entre las claves primarias y las claves externas de distintas tablas. SQL Server resuelve la integridad de referencia con disparadores definidos por el usuario.

invitado

Si existe un usuario llamado "guest" (invitado) en la tabla sysusers de una base de datos, cualquier usuario con un login de SQL Server válido puede utilizar dicha base de datos, con privilegios limitados.

jerarquía de tipos de datos

Jerarquía que determina el resultado de los cálculos utilizando valores de distintos tipos de datos.

lectura no repetida

Se produce cuando una transacción lee una fila y, a continuación, una segunda transacción modifica dicha fila. Si la segunda transacción consigna el cambio, las lecturas posteriores realizadas por la primera transacción devuelven resultados diferentes al de la lectura original.

lectura sucia

Se produce cuando una transacción modifica una fila y, a continuación, una segunda transacción lee la fila antes de que la primera transacción consigne el cambio. Si la primera transacción revierte el cambio, la información leída por la segunda transacción deja de ser válida.

lecturas fantasma

Se producen cuando una transacción lee un conjunto de filas que cumplen una condición de búsqueda y, a continuación, una segunda transacción modifica los datos (mediante insert , delete , update , etc.). Si la primera transacción repite la lectura con las mismas condiciones de búsqueda, obtiene un conjunto de filas distinto.

lenguaje de control de flujo

Estructuras de programación de Transact-SQL (como if , else , while, o el rótulo goto ) que controlan el flujo de ejecución de las instrucciones Transact-SQL.

lista de selección

Columnas especificadas en la cláusula principal de una instrucción select . Para que una vista dependiente continúe siendo válida, la lista seleccionada debe mantenerse en todas las vistas subyacentes.

login

Nombre que emplea el usuario para conectarse a SQL Server. Un login es válido si SQL Server tiene una entrada para dicho usuario en la tabla del sistema syslogins .

lote

Una o más instrucciones Transact-SQL terminadas con una marca de final de lote, que envía los lotes a SQL Server para su procesamiento.

mensaje de error

Mensaje que SQL Server emite, generalmente al terminal del usuario, cuando detecta una situación de error.

modificación de datos

Adición, eliminación o modificación de la información de la base de datos con los comandos insert , delete y update .

modo de transacción encadenado

Page 274: 80575032 Libro de SQL y Tl SQL Excelente

Page 274 of 280

Determina si SQL Server inicia o no automáticamente una nueva transacción en la siguiente instrucción de recuperación o de modificación de datos. Si set chained se define como on fuera de una transacción, la siguiente instrucción de recuperación o de modificación de datos inicia una nueva transacción. Este modo cumple con las normas SQL: garantiza que cada instrucción de recuperación y de modificación de datos se realiza dentro de una transacción. El modo de transacción encadenado puede ser incompatible con programas Transact-SQL existentes. El valor predeterminado es off . Las aplicaciones que requieren el cumplimiento de las normas SQL (como el precompilador Embedded SQL) deben definir automáticamente la opción chained como on al principio de cada sesión.

módulo

Operador aritmético representado por un signo de porcentaje (%), que proporciona el resto entero después de una operación de división entre dos enteros. Por ejemplo, 21 % 9 = 3 porque 21 dividido entre 9 es igual a 2 con un resto de 3.

nivel de aislamiento

Especifica las clases de acciones no permitidas durante la ejecución de las transacciones actuales; también denominado "nivel de bloqueo." La norma SQL define cuatro niveles de aislamiento para transacciones SQL. El nivel 0 impide que otras transacciones modifiquen datos ya modificados por una transacción no consignada. El nivel 1 impide las lecturas sucias . El nivel 2 (no admitido por SQL Server) también impide las lecturas no repetidas . El nivel 3 impide ambos tipos de lecturas, así como las lecturas fantasma ; es equivalente a realizar todas las consultas con holdlock . El usuario controla el nivel de aislamiento con la opción transaction isolation level de set o con la cláusula at isolation de select o readtext . El nivel predeterminado es 1.

nivel de bloqueo

Véase nivel de aislamiento .

nivel de hoja

Nivel de un índice en el que todos los valores clave aparecen en orden. Para índices agrupados de SQL Server, el nivel de hoja y el nivel de datos es el mismo. Para índices no agrupados, el último nivel de índice por encima del nivel de datos es el nivel de hoja, ya que los valores clave para todas las filas de datos aparecen en el orden clasificado.

nombres de correlación

Distinguen los diferentes roles que una tabla determinada realiza en una consulta, en especial una consulta correlacionada o autocombinación . Asigne nombres de correlación en la cláusula from y especifique el nombre de correlación después del nombre de tabla:

select au1.au_fname, au2.au_fname from authors au1, authors au2 where au1.zip = au2.zip

número de estado de error

Número adjunto a un mensaje de error de SQL Server que permite identificar de forma exclusiva la línea del código de SQL Server donde se produjo el error.

número de mensaje

Número que identifica de forma exclusiva un mensaje de error.

número de nivel de gravedad

Gravedad de una condición de error: los errores con un nivel de gravedad 19 y superior son errores fatales.

objeto de base de datos

Uno de los componentes de una base de datos: tabla, vista, índice, procedimiento, disparador, columna, valor predeterminado o regla.

Page 275: 80575032 Libro de SQL y Tl SQL Excelente

Page 275 of 280

objetos

Véase objetos de base de datos .

operador relacional

Operador que compara dos operandos y devuelve un valor verdadero, como "5 <7" (TRUE), "ABC" = "ABCD" (FALSE) o "@value > NULL" (UNKNOWN).

operadores

Símbolos que actúan sobre dos valores para producir un tercero. Véanse los operadores de comparación, lógicos o aritméticos.

operadores aritméticos

La adición (+), sustracción (-), división (/) y multiplicación (*) pueden utilizarse con columnas numéricas. El módulo (%) sólo puede utilizarse con las columnas int , smallint y tinyint .

operadores de comparación

Se utilizan para comparar un valor con otro en una consulta. Los operadores de comparación son: igual a (=), mayor que (>), menor que (<), mayor o igual a (>=), menor o igual a (<=), no igual a (!=), no mayor que (!>) y no menor que (!<).

operadores lógicos

Son los operadores and , or y not . Los tres pueden utilizarse en cláusulas where . El operador and combina dos o más condiciones y devuelve resultados cuando todas las condiciones son verdaderas; or conecta dos o más condiciones y devuelve resultados cuando alguna de las condiciones es verdadera.

palabra clave

Palabra o expresión reservada para uso exclusivo de Transact-SQL. También conocida como palabra reservada .

parámetros

Argumento para un procedimiento almacenado.

parte de fecha

Parte de una fecha, como día, mes o año, reconocidas por las funciones de fecha de Transact-SQL.

partes de asignación de disco

Grupos de unidades de asignación a partir de los cuales SQL Server crea un nuevo archivo de base de datos. El tamaño mínimo de un parte de asignación de disco es una unidad de asignación , o 256 páginas de 2KB.

permiso

Autorización para realizar determinadas acciones en objetos de base de datos específicos o para ejecutar ciertos comandos.

permisos de comando

Permisos que afectan a los comandos. Véase también permisos de objeto .

permisos de objeto

Permisos que regulan el uso de determinados comandos (comandos de modificación de datos, además de select , truncate table y exec ute) para especificar tablas, vistas o columnas. Véase también permisos de comando .

Page 276: 80575032 Libro de SQL y Tl SQL Excelente

Page 276 of 280

posición del cursor

Indica la fila actual del cursor. Es posible hacer referencia a dicha fila explícitamente utilizando instrucciones diseñadas para admitir cursores, como delete o update . Cambie la posición actual del cursor mediante fetch , que desplaza la posición actual del cursor una o más filas hacia abajo en el conjunto de resultados del cursor.

precisión

Número máximo de dígitos decimales que los tipos de datos numeric y decimal pueden almacenar. La precisión incluye todos los dígitos, tanto los que se encuentran a la derecha, como a la izquierda de la coma decimal.

precisión de visualización

Número de dígitos binarios significativos que ofrece el formato de visualización predeterminado para los valores real y float . Internamente, los valores real y float se almacenan con una precisión inferior o igual a la de los tipos de datos específicos de la plataforma a partir de los cuales son creados. Por razones de visualización, la precisión de los valores real de Sybase es de 9 dígitos, y la de los valores float de Sybase, de 17.

privilegio

Autorización para realizar determinadas acciones en objetos de base de datos específicos o para ejecutar comandos concretos. Es sinónimo de permiso .

problema Halloween

Anomalía asociada con actualizaciones del cursor por la que una fila aparece dos veces en el conjunto de resultados. Esto ocurre cuando el cliente actualiza la clave del índice y la fila de índice actualizada se desplaza hacia abajo en el conjunto de resultados.

procedimiento almacenado

Consiste de una serie de instrucciones SQL y de instrucciones de control de flujo opcionales almacenadas bajo un nombre. Los procedimiento almacenados suministrados por SQL Server se denominan procedimientos del sistema .

procedimientos del sistema

Procedimientos almacenados suministrados por SQL Server para la administración del sistema. Estos procedimientos se desempeñan como atajos para recuperar información de tablas del sistema, o como mecanismos para efectuar la administración de bases de datos y otras tareas que involucran la actualización de tablas del sistema.

producto cartesiano

Todas las combinaciones de filas posibles de cada una de las tablas especificadas en una combinación. El número de filas del producto cartesiano es igual al número de filas de la primera tabla por el número de filas de la segunda tabla. Después de calcular el producto cartesiano, se eliminarán las filas que no satisfagan las condiciones de combinación.

Propietario de la base de datos

Usuario que crea una base de datos. Un propietario de la base de datos tiene control sobre todos los objetos de base de datos de dicha base de datos. El nombre de login del propietario de la base de datos es ''dbo''.

protección dependiente de contexto

Protección que proporciona determinados permisos o privilegios dependiendo de la identidad del usuario. Este tipo de protección se proporciona utilizando vistas y la función incorporada user_id .

proyección

Una de las operaciones de consulta básicas de un sistema relacional. Una proyección es un subconjunto de las columnas de una tabla.

Page 277: 80575032 Libro de SQL y Tl SQL Excelente

Page 277 of 280

punto de resguardo

Marcador que el usuario coloca dentro de una transacción definida por el usuario . El usuario puede utilizar posteriormente el comando rollback transaction con el nombre del punto de resguardo para cancelar cualquier comando anterior al punto de resguardo, o commit transaction para completar realmente los comandos.

punto de verificación

Punto en el cual se garantiza que todas las páginas de datos modificadas se han escrito en el dispositivo de bases de datos.

recobro

Desplaza la posición actual del cursor hacia abajo en el conjunto de resultados del cursor. También denominado recobro del cursor.

recuperación de datos

Solicitud de datos de la base de datos y recepción de los resultados. También denominada consulta .

regla

Especificación que controla los datos que pueden introducirse en una columna determinada, o en una columna de un tipo particular de datos definido por el usuario.

reglas de normalización

Reglas estándar de diseño de base de datos en un sistema de administración de bases de datos relacionales.

relación maestro-discípulo

Relación entre conjuntos de datos en la que un conjunto de datos depende lógicamente del otro. Por ejemplo, en la base de datos pubs2 , la tabla sales y la tabla salesdetail tienen una relación maestro-discípulo. Véase datos discípulos y tabla maestra .

resolución de vista

En consultas que utilizan una vista, es el proceso de verificación de la validez de objetos de base de datos en la consulta y de combinación de la consulta y de la definición almacenada de la vista.

restricción

Subconjunto de las filas de una tabla. También denominada selección , es una de las operaciones de consulta básicas de un sistema relacional.

restricción a nivel de columna

Limita los valores de una columna especificada. Sitúe restricciones a nivel de columna después del nombre de columna y del tipo de datos en la instrucción create table , antes de la coma de separación.

restricción a nivel de tabla

Limita los valores de más de una columna de una tabla. Introduzca restricciones a nivel de tabla como cláusulas independientes separadas por comas en la instrucción create . Declare las restricciones que operan en más de una columna como restricciones a nivel de tabla.

restricción de clave primaria

Restricción exclusiva que no admite valores nulos para las columnas que componen la clave. Sólo puede haber una restricción de clave primaria por tabla. La restricción de clave primaria crea un índice único en las columnas especificadas para imponer la integridad de estos datos.

Page 278: 80575032 Libro de SQL y Tl SQL Excelente

Page 278 of 280

restricción de integridad de referencia

Las restricciones de integridad de referencia requieren que los datos insertados en la tabla "de referencia" que define la restricción tengan valores coincidentes en la tabla "a la que se hace referencia". No es posible eliminar filas ni actualizar valores de columna de una tabla a la que se hace referencia que sean coincidentes con los valores de una tabla de referencia. Asimismo, no es posible omitir la tabla a la que se hace referencia hasta que se omita la tabla de referencia o se quite la restricción de integridad de referencia.

restricción de verificación

Una restricción de verificación ( check ) limita los valores que el usuario puede insertar en una columna de una tabla. Una restricción check especifica una condición de búsqueda search_condition que cualquier valor debe superar antes de insertarse en la tabla.

restricción exclusiva (unique)

Restricción que precisa que todos los valores no nulos de las columnas especificadas sean únicos. No está permitido que dos filas de una tabla tengan el mismo valor en la columna especificada. La restricción exclusiva crea un índice único en las columnas especificadas para imponer la integridad de estos datos.

restricciones de integridad

Constituyen un modelo para describir la integridad de base de datos en la instrucción create table . La integridad de base de datos está formada por dos componentes complementarios: validez , que garantiza que toda la información falsa queda excluida de la base de datos, e integridad , que garantiza que toda la información verdadera se incluye en la base de datos.

roles

Proporcionan responsabilidades individuales para los usuarios que realizan tareas de administración y de seguridad del sistema en SQL Server. Los roles de administrador del sistema, oficial de seguridad del sistema y operador pueden concederse a cuentas de login individuales del servidor

selección

Subconjunto de filas de una tabla. También denominada restricción, es una de las operaciones de consulta básicas de un sistema relacional.

sistema operativo

Grupo de programas que traduce comandos del usuario a la computadora y permite realizar tareas, como crear archivos, ejecutar programas e imprimir documentos.

subconsulta

Instrucción select anidada dentro de otra instrucción select , insert , update o delete , o dentro de otra subconsulta.

subconsulta correlacionada

Es una subconsulta que no puede evaluarse independientemente, sino que sus resultados dependen de la consulta externa. También se denomina subconsulta de repetición, ya que se ejecuta una vez para cada fila seleccionada por la consulta externa. Véase también consultas anidadas .

tabla

Consiste en una serie de filas (registros) que tienen columnas asociadas (campos). Es el equivalente lógico de un archivo de base de datos.

tabla de disparador

Tabla a la que se adjunta un disparador.

Page 279: 80575032 Libro de SQL y Tl SQL Excelente

Page 279 of 280

tabla del sistema

Una de las tablas del diccionario de datos. Las tablas del sistema realizan un seguimiento de la información general de SQL Server y de cada base de datos de usuario. La base de datos Master contiene algunas tablas del sistema que no están en las bases de datos de usuarios.

tabla maestra

Tabla que contiene datos de los que dependen los datos de otra tabla de forma lógica. Por ejemplo, en la base de datos pubs2 , la tabla sales es una tabla maestra. La tabla salesdetail contiene información discípula que depende de los datos maestros de sales . Normalmente, la tabla discípula dispone de una clave externa que se combina con la clave primaria de la tabla maestra.

tablas base

Tablas permanentes en las que se basa una vista. También llamadas tablas "subyacentes".

tablas de verificación de disparadores

Cuando una modificación de datos afecta a una columna clave, los disparadores comparan los nuevos valores de columna con las claves relacionadas utilizando tablas de trabajo temporales llamadas tablas de verificación de disparadores.

terminador de comandos

Marca de final de lote que envía el lote a SQL Server para su procesamiento.

tipo de datos

Especifica el tipo de información que contendrá cada columna y cómo se almacenarán los datos. Los tipos de datos incluyen char , int , money , etc.. Los usuarios pueden crear sus propios tipos de datos en base a los tipos de datos del sistema SQL Server.

tipo de datos definido por el usuario

Definición del tipo de datos que puede contener una columna, creada por el usuario. Estos tipos de datos se definen en función de los tipos existentes de datos del sistema. Es posible vincular reglas y valores predeterminados a los tipos de datos definidos por el usuario (pero no a los tipos de datos del sistema).

tipos de datos compatibles

Tipos que SQL Server convierte automáticamente para realizar una comparación implícita o explícita.

transacción

Mecanismo para garantizar que un conjunto de acciones se interprete como una sola unidad de trabajo. Véase también transacción definida por el usuario .

transacción definida por el usuario

Véase transacción .

transacción revertida

Instrucción Transact-SQL que se emplea con una transacción definida por el usuario (antes de que se haya recibido un transacción commit ) que cancela la transacción y deshace cualquier cambio realizado en la base de datos.

unidad de asignación

Unidad lógica de 1/2 megabyte. El comando disk init inicializa un nuevo dispositivo de base de datos para SQL Server y lo divide en partes de 1/2 megabyte llamadas unidades de asignación.

Page 280: 80575032 Libro de SQL y Tl SQL Excelente

Page 280 of 280

valor clave

Cualquier valor indexado.

valor nulo

Se utiliza cuando no se asigna explícitamente ningún valor. NULL no es equivalente a cero, ni a espacio en blanco. Un valor de NULL no se considera superior, inferior ni equivalente a ningún otro valor, incluso otro valor de NULL.

valor predeterminado

Opción elegida por el sistema cuando no se especifica ninguna otra opción.

variable

Entidad asignada a un valor. SQL Server tiene dos tipos de variables, llamadas variables locales y variables globales .

variable global

Variables definidas por el sistema que SQL Server actualiza de forma permanente. Por ejemplo, @@error contiene el número del último error generado por el sistema.

variables locales

Variables definidas por el usuario con una instrucción declare .

vista

Forma alternativa de consultar los datos de una o más tablas. Normalmente, se crea como un subconjunto de columnas de una o más tablas.

volcado dinámico

Volcado que se realiza cuando la base de datos está activa.

http://manuals.sybase.com/onlinebooks/group-

asarc/svs11001/tsqlsp/@Generic__BookTocView/45905;hf=0;pt=45905;lang=es