Está en la página 1de 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 1 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
Los nombres de comando, de opción de comando, de utilidad, de indicador de utilidad y otras palabras clave se
coman do o
imprimen en C ourier negrita en las instrucciones de sintaxis, y en Helvetica negrita en el texto de los
comand o
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 2 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 3 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
Expresión que siempre devuelve el mismo valor, como "5+3" o "ABCDE"
expression
Cualquier expresión de coma flotante o expresión que se convierte de forma implícita en un valor de coma
float_expr
flotante
Cualquier expresión de número entero o expresión que se convierte de forma implícita en un valor de
integer_expr
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 4 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 5 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 6 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 7 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 8 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
byroyalty pertenece al propietario de la base de datos.
GATEWAY.pubs2..byroyalty
GATEWAY...byroyalty Debe usarse si pubs2 es la base de datos predeterminada.
declare @var int
Debe usarse cuando la instrucción no es la primera instrucción de un lote.
exec GATEWAY...byroyalty

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 9 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 10 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 11 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 12 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
work
transaction
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 13 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 14 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 15 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 16 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 17 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 18 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 19 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 20 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 21 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 22 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 23 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 24 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 25 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 26 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 27 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 28 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 29 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.
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.

[ specifier ] - 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 30 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 31 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 32 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 33 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 34 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 35 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 36 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 37 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 38 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 39 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 40 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 41 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 42 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 43 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 44 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 45 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 46 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 47 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 48 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 49 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 50 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 51 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 52 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 53 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 54 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 55 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 56 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 57 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 58 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 59 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 60 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 61 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 62 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 63 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 64 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 65 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 66 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 67 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 68 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 69 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 70 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 71 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 72 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 73 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 74 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 75 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 76 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 77 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 78 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 79 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 80 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 81 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 82 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 83 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 84 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 85 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 86 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 87 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 88 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 89 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 90 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 2 31, 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 91 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
Sinónimos Margen Bytes de almacenamiento
categoría
Numéricos exactos: enteros
0 a 255
tinyint 1

215 -1 (32.767) a -215 (-32.768)


smallint integer 2

231 -1 (2.147.483.647) a
int 4
-231 (-2.147.483.648)
Numéricos exactos: decimales
numeric (p, s) 1038 -1 a -1038 2 a 17
dec
decimal (p, s) 1038 -1 a -1038 2 a 17
Numéricos aproximados
float (precision) dependiente de la máquina 4u8

double precision dependiente de la máquina 8

real dependiente de la máquina 4


Monetarios
214.748,3647 a -214.748,3648
smallmoney 4

922.337.203.685.477,5807 a
money 8
-922.337.203.685.477,5808
Fecha/hora
Del 1 de enero de 1900 al 6 de junio
smalldatetime de 2079 4

datetime Del 1 de enero de 1753 al 31 de 8


diciembre de 9999
Caracteres

Page 92 of 280
n
char(n) 255 caracteres o menos
character
longitud de entrada real
varchar(n) 255 caracteres o menos
character varying, char varying
n * @@ncharsize
nchar(n) 255 caracteres o menos
national character, national char
@@ncharsize * número de
nvarchar(n) 255 caracteres o menos caracteres
nchar varying, national char
varying, national character varying
text 231 -1 (2.147.483.647) bytes o menos
0 o múltiplo de 2K
Binarios
binary(n) 255 bytes o menos n

varbinary(n) 255 bytes o menos longitud de entrada real

image 231 -1 (2.147.483.647) bytes o menos 0 o múltiplo de 2K


Bit
1 (un byte contiene hasta 8
bit 0o1
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 Bytes de
Almacena
datos almacenamiento
Números enteros entre 0 y 255, ambos incluidos. (No se admiten
tinyint 1
números negativos.)
Números enteros entre 215 -1 y -215 (32.767 y
smallint 2
-32.768), ambos incluidos.
Números enteros entre 231 - 1 y -231 (2.147.483.647 y -2.147.483.648), ambos
int 4
incluidos.

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 93 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
4 para d efault precision < 16,
float [( default precision )]
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
Almacena Bytes de almacenamiento
datos
Datos de longitud fija, como números de seguridad social o
char(n) n
códigos postales
Datos, como nombres, cuya longitud puede variar
varchar(n) Número real de caracteres introducidos
considerablemente
nchar(n) Datos de longitud fija en juegos de caracteres multibyte n * @@ncharsize

Page 94 of 280
nvarchar(n) Datos de longitud variable en juegos de caracteres multibyte Número real de caracteres * @@ncharsize
Hasta 2.147.483.647 bytes de caracteres imprimibles en listas 0 sin inicializar; un múltiplo de 2K después de
text
enlazadas de páginas de datos 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 95 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
Valores monetarios entre +922.337.203.685.477,5807 y
money 8
-922.337.203.685.477,5808
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 96 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 97 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 98 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 99 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 100 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 101 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 102 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 103 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 104 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 2 23 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 105 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 106 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 107 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 108 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 109 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 110 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 111 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 112 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 113 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 114 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 115 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 116 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 117 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 118 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 119 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 120 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 121 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 122 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 123 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 124 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 125 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 126 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 127 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 128 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 129 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 130 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 131 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 132 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 133 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 134 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 135 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 136 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 137 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 138 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 139 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 140 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 141 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 142 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 143 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 144 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 145 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 146 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


ac
----- -----
1 10 Combina y califica en c
2 NULL Combina, pero no cumple las calificaciones

Page 147 of 280


3 NULL
No combina
(3 rows affected)

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 148 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 149 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 150 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 151 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 152 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 153 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 154 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 155 of 280


Función Argumento Resultado
( object_id , column_id
col_name Devuelve el nombre de la columna.
[, database_id ])
( object_name , column_name Devuelve la longitud definida de la columna. Use datalength para ver el
col_length
) tamaño de datos real.
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
curunreservedpgs (dbid, lstart, unreservedpgs )
datos no está en uso, el valor se toma de la columna u nreservedpgs de
sysusages .
Devuelve el número de páginas usadas por la tabla ( doampg ) o el
( object_id , { doampg |
data_pgs índice ( ioampg ). El resultado no incluye las páginas utilizadas para las
ioampg })
estructuras internas.
Devuelve la longitud de la expresión en bytes. e xpression suele ser un
datalength ( expression ) nombre de columna. Si e xpression es una constante de caracteres, debe
incluirse entre comillas.
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
db_id ( [ database_name ] ) 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.
Devuelve el nombre de la base de datos. d atabase_id debe ser una
db_name ([ database_id ]) expresión numérica. Si no se proporciona ninguna d atabase_id ,
db_name devuelve el nombre de la base de datos actual.
Devuelve la ID de proceso principal del proceso cliente (no el proceso
host_id ()
SQL Server).
Devuelve el nombre de computadora principal actual del proceso cliente
host_name ()
(no el proceso SQL Server).
( object_name , index_id , key_ Devuelve el nombre de la columna indexada; devuelve NULL si o
index_col
# [, user_id ]) bject_name no es un nombre de tabla ni de vista.
Sustituye el valor indicado en e xpression2 cuando e xpression1 da como
isnull ( expression1 , expression2 ) resultado NULL. Los tipos de datos de las expresiones deben convertirse
de forma implícita, o es necesario usar la función c onvert .
Maneja el umbral de última oportunidad del segmento de diario.

lastchance crea un umbral de última oportunidad en la base de datos


especificada.

({{ "lastchance" | "logfull" | logfull devuelve 1 si se ha cruzado el umbral de última oportunidad de


lct_admin "unsuspend" } , database_id la base de datos especificada y 0 en caso contrario.
} | "reserve" , log_pages })
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.
Comprueba si el usuario solicitante tiene el rol correcto para ejecutar el
( "sa_role" | "sso_role" |
proc_role procedimiento. Si el rol es correcto, el resultado es 1. En caso contrario,
"oper_role" )
el resultado es 0.
( object_id , { doampg | Devuelve el número de páginas asignadas a la tabla o índice. Esta
reserved_pgs
ioampg }) 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).
Devuelve los roles activos actuales del usuario, si hay (sa_role, sso_role
show_role ()
u oper_role). Si el usuario carece de roles, el resultado es NULL.
Devuelve el número de ID del usuario de servidor de s yslogins. Si no se
suser_id ([ server_user_name ]) proporciona ningún s erver_user_name , el resultado es la ID de servidor
del usuario actual.

Page 156 of 280


Devuelve el nombre del usuario de servidor. Las ID del usuario de
suser_name ([ server_user_id ]) servidor están almacenadas en s yslogins . Si no se proporciona ninguna
s erver_user_id , el resultado es el nombre del usuario actual.
Devuelve el número total de páginas usadas por una tabla y su índice
used_pgs ( object_id , doampg , ioampg )
agrupado.
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.
tsequal ( timestamp , timestamp2 )
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.
Devuelve el número de ID del usuario. Indica el número de s ysusers en
user_id ([ user_name ]) la base de datos actual. Si no se proporciona ningún u ser_name , el
resultado es la ID del usuario actual.
Devuelve el nombre del usuario, basado en la ID del usuario de la base
user_name ([ user_id ]) de datos actual. Si no se proporciona ninguna u ser_id , el resultado es
el nombre del usuario actual.
Devuelve 0 si c haracter expression no es un identificador válido
valid_name ( character_expression ) (caracteres ilegales o más de 30 bytes de longitud) y un número distinto
de cero en caso contrario.
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
valid_user ( server_user_id )
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 157 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
Puede sustituirse por
argumento

Page 158 of 280


Un nombre de columna de tipo de caracteres, variable, o expresión constante de tipo char , varchar , nchar
char_expr o nvarchar . Las funciones que aceptan nombres de columna text se indican en la explicación. Las
expresiones constantes deben aparecer entre comillas.
Un nombre de columna binario o de caracteres, variable o expresión constante. Pueden ser datos char ,
expression
varchar, ncha r o nvarchar , en cuanto a char_expr , más binary o varbinary .
Una expresión de caracteres de tipo de datos char, nchar, varchar o nvarchar que puede incluir cualquiera
pattern
de los caracteres comodín de coincidencia con el patrón admitidos por SQL Server.
Cualquier numérico aproximado ( float , real o double precision ), nombre de columna, variable o expresión
approx_numeric
constante.
Cualquier número entero (como tinyint, smallint o int ), nombre de columna, variable o expresión constante.
integer_expr
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.
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.
char ( integer_expr )
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.
Examina expression2 para buscar la primera aparición de expression1 y devuelve un
( expression1, valor entero que representa su posición inicial. Si no se encuentra expression1 ,
charindex
expression2 ) devuelve 0. Si expression1 contiene caracteres comodín, charindex los trata como
literales.
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
char_length ( char_expr )
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.
( char_expr1, Devuelve un valor entero que representa la diferencia entre dos valores soundex .
difference
char_expr2 ) Consulte soundex más adelante.
lower ( char_expr ) Convierte mayúsculas en minúsculas. Devuelve un valor de caracteres.
Quita los espacios en blanco iniciales de la expresión de caracteres. Sólo se quitan los
ltrim ( char_expr ) valores equivalentes al carácter de espacio en la especificación de caracteres especiales
de SQL.
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
("% pattern %",
devolver el desplazamiento en bytes, es decir, cadenas de caracteres multibyte, hay que
char_expr [ using {
patindex especificar using bytes . El carácter comodín '%' debe preceder y seguir a pattern ,
bytes | chars |
excepto cuando se buscan caracteres iniciales o finales. Consulte la sección sobre
characters }] )
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 .
Devuelve una cadena con el mismo tipo de datos que char_expr , que contiene la misma
( char_expr,
replicate expresión repetida el número especificado de veces o tantas veces como quepa en un
integer_expr )
espacio de 255 bytes, cualquiera que sea inferior.
reverse ( char_expr ) Devuelve el inverso de char_expr ; si char_expr es "abcd", devuelve "dcba".
Devuelve la parte de la expresión de caracteres que empieza por el número de
( char_expr,
right caracteres desde la derecha. El valor de retorno tiene el mismo tipo de datos que la
integer_expr )
expresión de caracteres.
rtrim ( char_expr ) Quita los espacios en blanco finales. Sólo se quitan los valores equivalentes al carácter

Page 159 of 280


de espacio en la definición de caracteres especiales de SQL.
Devuelve un código soundex de cuatro caracteres para cadenas de caracteres que se
soundex ( char_expr ) 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.
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
( approx_numeric define el número de dígitos decimales que se devolverán.
str [, length [, decimal ]
])
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.
Elimina los caracteres length de char_expr1 en start , después inserta char_expr2 en
( char_expr1 , start ,
stuff char_expr1 en start . Para eliminar caracteres sin insertar otros caracteres, char_expr2
length , char_expr2 )
debería ser NULL, no " ", que indica un solo espacio.
Devuelve parte de una cadena de caracteres o binaria. start especifica la posición de
( expression , start ,
substring carácter donde empieza la subcadena. length especifica el número de caracteres de la
length )
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 160 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 161 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 162 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 163 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
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
("% pattern %", forma predeterminada, patindex devuelve el desplazamiento en caracteres; para
char_expr [ using { devolver el desplazamiento en bytes para cadenas de caracteres multibyte, hay que
patindex
bytes | chars | especificar using bytes . El carácter comodín % debe preceder y seguir a pattern ,
characters } ] ) 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 .
Devuelve el valor del puntero de texto, un valor binario de 16 bytes. El puntero de texto
textptr ( text_columname )
se verifica para garantizar que apunte a la primera página de texto.
Verifica si es válido un puntero de texto dado. Tenga en cuenta que el identificador para
(" table_name ..
textvalid una columna text o image debe incluir el nombre de la tabla. Devuelve 1 si el puntero
col_name ", textpointer )
es válido, 0 si el puntero no es válido.
Especifica el límite, en bytes, de los datos t ext o image que van a ser devueltos con
set una instrucción select . El valor actual se almacena en la variable global @@textsize . n
{n|0}
textsize 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 164 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
Puede sustituirse por
argumento
Cualquier numérico aproximado ( float , real o double precision ), nombre de columna, variable, expresión
approx_numeric
constante, o una combinación de los mismos.
Cualquier número entero ( tinyint , smallint o int), nombre de columna, variable, expresión constante, o una
integer
combinación de los mismos.
Cualquier numérico exacto ( numeric , dec , decimal , tinyint , smallint o int ), numérico aproximado ( float ,
numeric real o double precision ), o columna money , variable, expresión constante, o una combinación de los
mismos
Cualquier numérico exacto, numérico aproximado o columna money , variable, expresión constante, o una
power
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 165 of 280
Tabla 10-7: Funciones matemáticas
Func
Argumento Resultado
ión
Devuelve el valor absoluto de una expresión dada. Los resultados son del mismo tipo y tienen
abs ( numeric )
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.
( approx_numeric1 ,
atn2 Devuelve el ángulo (en radianes) cuya tangente es ( approx_numeric1 / approx_numeric2 ).
approx_numeric2 )
Devuelve el número entero más pequeño mayor o igual que el valor especificado. Los
ceiling ( numeric ) 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).
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
degrees ( numeric )
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.
Devuelve el número entero más grande menor o igual que el valor especificado. Los resultados
floor ( numeric ) 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.
Devuelve el valor de numeric elevado a la potencia de power. Los resultados son del mismo
power ( numeric , power ) 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.
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
radians ( numeric_expr )
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.
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
round ( numeric , integer ) 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.
Devuelve el signo de numeric : positivo (+1), cero (0) o negativo (-1). Los resultados son del
sign ( numeric )
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 166 of 280
Tabla 10-8: Ejemplos de funciones matemáticas
Instrucción Resultado
select floor(123) 123
select floor(123.45) 123.000000
select floor(1.2345E2) 123.000000
select floor(-123.45) -124.000000
select floor(-1.2345E2) -124.000000
select floor($123.45) 123.00
select ceiling(123.45) 124.000000
select ceiling(-123.45) -123.000000
select ceiling(1.2345E2) 124.000000
select ceiling(-1.2345E2) -123.000000
select ceiling($123.45) 124.00
select round(123.4545, 2) 123.4500
select round(123.45, -2) 100.00
select round(1.2345E2, 2) 123.450000
select round(1.2345E2, -2) 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 167 of 280


datepart ( datepart , date ) Parte de un valor datetime o smalldatetime , por ejemplo, el mes, como un valor entero.
(datepart, date, La cantidad de tiempo entre la segunda y la primera de las dos fechas, convertida al
datediff
date) componente de fecha especificado, por ejemplo, meses, días, horas.
(datepart, number,
dateadd Una fecha generada al añadir componentes de fecha a otra fecha.
date)

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 168 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 169 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 170 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 171 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 172 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 173 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 174 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 175 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 176 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 177 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 178 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 179 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 180 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
El comando create index no se El comando de introducción de filas duplicadas no
Ninguna opción definida
ejecuta de forma correcta. se ejecuta de forma correcta.
El comando se ejecuta de forma
allow_dup_row definida El comando se ejecuta de forma correcta.
correcta.
Se crea el índice, pero las filas Se aceptan todas las filas, excepto las duplicadas;
ignore_dup_row<Default Para
duplicadas se eliminan; mensaje de mensaje de error. Consulte la advertencia
Font> definida
error. 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 181 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 182 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 183 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 184 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 185 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
Valor predeterminado antiguo vinculado a:
vinculado a:
Tipo de datos de usuario Column a
Sustituye al valor predeterminado Ningún cambio; valor predeterminado
Tipo de datos de usuario
antiguo. antiguo.
Sustituye al valor predeterminado
Column a Sustituye al valor predeterminado antiguo.
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 186 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 187 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


Se introduce
Sin entrada Sin entrada, Se introduce null
Definición de null
Sin valor Con valor Valor
columna Sin valor
predeterminado predeterminado predeterminado
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 188 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 189 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 190 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 191 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 192 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 193 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 194 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.
Imprime un mensaje definido por el usuario o una variable local en la pantalla del usuario y define un
raiserror
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 195 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 196 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 197 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 198 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 199 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 200 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
Contiene 0 si la conversión del juego de caracteres no está en efecto. Contiene 1 si la conversión del
@@char_convert
juego de caracteres está en efecto.
Contiene el nombre del juego de caracteres del cliente. Se define como NULL si el juego de caracteres
@@client_csname del cliente nunca fue inicializado; en caso contrario, contiene el nombre del último juego de caracteres
utilizado.
Contiene la ID del juego de caracteres del cliente. Se define como -1 si el juego de caracteres del cliente
@@client_csid 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.
Contiene la cantidad de tiempo, en pulsos, que la CPU empleó en realizar el trabajo de SQL Server desde
@@cpu_busy
la última vez que se inició.
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
@@error
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.
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.
@@identity
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.
Contiene la cantidad de tiempo, en pulsos, que SQL Server empleó para efectuar operaciones de entrada
@@io_busy
y salida.
Contiene el nivel de aislamiento actual del programa Transact-SQL. @@isolation toma el valor del nivel
@@isolation
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 .
Contiene la longitud máxima, en bytes, de los caracteres multibyte del juego de caracteres
@@maxcharlen
predeterminado.
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
@@max_connections
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.
Contiene el nivel de anidación de la ejecución actual, inicialmente cero. Cada vez que un procedimiento
@@nestlevel 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.
Contiene el número de filas afectadas por la última consulta. @@rowcount es definida como cero por
@@rowcount
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 201 of 280


Contiene la ID de columna de la columna referenciada por @@ textptr . El tipo de datos de esta variable
@@textcolid
es tinyint .
Contiene la ID de base de datos de una base de datos que contiene un objeto con la columna
@@textdbid
referenciada por @@ textptr . El tipo de datos de esta variable es smallint.
Contiene la ID de objeto de un objeto que contiene la columna referenciada por @@ textptr . El tipo de
@@textobjid
datos de esta variable es int
Contiene el puntero de texto de la última columna text o image insertada o actualizada por un proceso.
@@textptr
El tipo de datos de esta variable es binary(16) (no confunda esta variable con la función textptr ).
Contiene el límite del número de bytes de datos text o image devueltos por una instrucción select . El
@@textsize 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 .
Contiene la marca horaria de texto de la columna referenciada por @@ textptr . El tipo de datos de esta
@@textts
variable es varbinary(8) .
Contiene la disminución de espacio libre necesaria para activar un umbral. Esta cantidad, también
@@thresh_hysteresis 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.
Contiene el número de microsegundos por pulso. La cantidad de tiempo por pulso es dependiente de la
@@timeticks
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ó.
Contiene el modo de transacción actual del programa Transact-SQL. @@tranchained devuelve 0 para no
@@tranchained
encadenadas o 1 para encadenadas.
@@trancount Contiene el número de transacciones activas del usuario actual.
Contiene el estado actual de una transacción después que se ejecuta una instrucción. Sin embargo,
@@transtate
@@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 202 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 203 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 204 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 205 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 206 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 207 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 208 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 209 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 210 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 211 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 212 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 213 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 214 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 215 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 216 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 217 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 218 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 219 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 220 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 221 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 222 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 223 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 224 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 225 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 226 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 227 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 228 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 229 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 230 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 231 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 232 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 233 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 234 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 235 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 236 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 237 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 238 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 239 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 240 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 241 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 242 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 243 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 244 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.
Indica que no hay más datos en el conjunto de resultados. Esta advertencia puede aparecer si la posición actual del
2
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 245 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 246 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 247 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 248 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 249 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 250 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 251 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 252 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


create default drop default
grant
alter table (se permiten cláusulas distintas de partition y unpartition ) create index drop index
revoke
create procedure drop procedure

Page 253 of 280


create rule drop rule
create schema drop table
create table drop trigger
create trigger drop view
create 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 disk init
load transaction select into
alter table...partition dump database
load database update statistics
alter table...unpartition dump transaction
reconfigure truncate table
create database drop database

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 254 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
Transacción en proceso. Hay una transacción implícita o explícita en efecto; la instrucción anterior se ha ejecutado de
0
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 255 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 256 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 257 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 258 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 259 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 260 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 261 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 262 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 263 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 264 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 265 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 266 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 267 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 268 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 269 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 270 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 271 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 272 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 273 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 274 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 275 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 276 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 277 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 278 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 279 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

Page 280 of 280

También podría gustarte