tsql - usar - tipos de signos de puntuacion
¿Cuándo no debo usar un punto y coma? (3)
La sintaxis de T-SQL no requiere un punto y coma para terminar una declaración.
En realidad, esto está en deprecated 1 . No puedo recordarlo con seguridad, pero creo que aún puede evitar usarlos en el próximo Sql Server 2012, pero es probable que algunas versiones posteriores requieran un punto y coma para cada declaración. El uso de un punto y coma también es técnicamente requerido por el estándar ansi . El punto es que ahora es el momento de acostumbrarse a usar uno para cada declaración.
Como cuestión práctica, no espero que sigan adelante con esto directamente. Más bien, espero que Sql Server Management Studio y otras herramientas de desarrollo comiencen a emitir advertencias en lugar de errores, quizás para varias versiones. Esto ayudará a los desarrolladores a encontrar y reparar todo el código no compatible anterior. Pero eso no disminuye el mensaje: los puntos y coma vienen y pronto.
Para una heurística simple sobre cuándo no utilizar un punto y coma, piense en el código como si fuera un lenguaje de procedimiento que usaba llaves para bloques, como C / C ++. Las declaraciones que se emparejarían con un corchete de apertura (que no se cierra) si estuvieran escritos en el lenguaje del procedimiento no deberían tener un punto y coma.
1 Está casi hasta el final de la página.
O: ¿Qué no es una declaración T-SQL?
Excepto para resolver la ambigüedad, la sintaxis de T-SQL no requiere un punto y coma para terminar una declaración. A pesar de esto, Itzik Ben-Gan recomienda usar un punto y coma para terminar una declaración T-SQL porque hace que el código sea más limpio, más legible, más fácil de mantener y más portátil.
No conozco una definición precisa de lo que es una declaración T-SQL válida, por lo que podría confundirme aquí. Pero por lo que sé, un bloque BEGIN ... END es una instrucción T-SQL, por lo que debe terminar con un punto y coma. Por ejemplo:
IF OBJECT_ID(''tempdb.dbo.#TempTable'') IS NOT NULL
BEGIN
DROP TABLE #TempTable;
END;
El ejemplo de código en la documentación BEGIN ... END de Microsoft admite esta conjetura:
USE AdventureWorks2008R2;
GO
BEGIN TRANSACTION;
GO
IF @@TRANCOUNT = 0
BEGIN
SELECT FirstName, MiddleName
FROM Person.Person WHERE LastName = ''Adams'';
ROLLBACK TRANSACTION;
PRINT N''Rolling back the transaction two times would cause an error.'';
END;
ROLLBACK TRANSACTION;
PRINT N''Rolled back the transaction.'';
GO
/*
Rolled back the tranaction.
*/
Itzik Ben-Gan contradice esto en el ejemplo de código del Ejercicio 1-1 de los Fundamentos de T-SQL :
SET NOCOUNT ON;
USE TSQLFundamentals2008;
IF OBJECT_ID(''dbo.Nums'', ''U'') IS NOT NULL DROP TABLE dbo.Nums;
CREATE TABLE dbo.Nums(n INT NOT NULL PRIMARY KEY);
DECLARE @i AS INT = 1;
BEGIN TRAN
WHILE @i <= 100000
BEGIN
INSERT INTO dbo.Nums VALUES(@i);
SET @i = @i + 1;
END
COMMIT TRAN
SET NOCOUNT OFF;
El documento de las Convenciones de Sintaxis de Transact-SQL de Microsoft establece que el punto y coma "se requerirá en una versión futura" de T-SQL.
Al comentar sobre la intención de Microsoft de requerir el punto y coma en una versión futura de T-SQL, Itzik señala algunas excepciones que no deben terminarse:
Hasta ahora era un requisito utilizar un punto y coma solo en casos específicos. Ahora parece que el plan es convertirlo en un terminador requerido para todas las declaraciones * T-SQL en alguna versión futura de SQL Server.
(*) Naturalmente, hay casos que no deben terminarse con un punto y coma; esos incluyen (pero no se limitan a):
EMPEZAR
COMENZAR TRAN
SI
MÁS
MIENTRAS
Comience
Prueba final
Comenzar a captar
Itzik parece ser consistente con él mismo, pero Microsoft no sigue sus recomendaciones. Compare la BEGIN TRANSACTION;
Microsoft BEGIN TRANSACTION;
y BEGIN TRAN
Itzik en los ejemplos anteriores.
En el código que mantengo, he visto incluso la palabra clave BEGIN
terminada por punto y coma:
IF @HasWidget = 0x1
BEGIN;
SELECT WidgetID
FROM tbWidgets;
END;
Creo que un analizador T-SQL puede considerar el punto y coma después de la palabra clave BEGIN
para terminar una declaración vacía en lugar de terminar la palabra clave BEGIN
; No creo que BEGIN
sí sea una declaración válida de T-SQL.
Esta conjetura es compatible con el hecho de que SQL Server 2008 analiza y ejecuta con éxito la siguiente consulta:
SELECT 0;;
Es tan confuso porque no hay una especificación ampliamente disponible del lenguaje T-SQL, como la Especificación del lenguaje Java para Java, por lo que en ninguna parte hay una definición formal de una declaración T-SQL.
¿Me equivoco? ¿Existe tal especificación para T-SQL, y está disponible públicamente?
De lo contrario, ¿debería simplemente creer lo que dice Itzik?
La única situación en la que uso un punto y coma con frecuencia es cuando se usan las expresiones de tabla comunes mediante la palabra clave WITH
, y solo en este caso porque la palabra clave WITH
debe ir precedida por un punto y coma, de lo contrario, devuelve un error. En esos casos, escribo.
;WITH [exp]...
es decir, precedo al WITH
con un punto y coma, en lugar de terminar la declaración anterior.
El uso de punto y coma en SQL parece ser muy raro; Ocasionalmente lo veo después de que un procedimiento almacenado o una declaración de función es la excepción y no la regla. De todos los desarrolladores con los que he trabajado, no creo que ninguno haya usado realmente el punto y coma de la forma que describiste.
Declaraciones como
BEGIN;
SELECT WidgetID
FROM tbWidgets;
END;
son difíciles de entender - si BEGIN;
se considera una declaración independiente de su correspondiente END;
, ¿por qué SELECT WidgetID
no es una declaración válida independiente de su correspondiente FROM
?
Resumen, basado en la lista original citada del OP.
Sí punto y coma:
- COMENZAR TRAN;
Sin punto y coma:
- EMPEZAR
- SI
- MÁS
- MIENTRAS
- Comience
- Prueba final
- Comenzar a captar
Además, úsalos después de END
y END CATCH
.
Detalles:
BEGIN TRAN
es una declaración y debe terminarse con un punto y coma.
La documentación de Microsoft señala el punto y coma opcional:
BEGIN { TRAN | TRANSACTION }
[ { transaction_name | @tran_name_variable }
[ WITH MARK [ ''description'' ] ]
]
[ ; ]
El ejemplo de Microsoft tiene punto y coma:
BEGIN TRAN T1;
UPDATE table1 ...;
BEGIN TRAN M2 WITH MARK;
UPDATE table2 ...;
SELECT * from table1;
COMMIT TRAN M2;
UPDATE table3 ...;
COMMIT TRAN T1;
Ambos de los anteriores son de:
https://msdn.microsoft.com/en-us/library/ms188929(v=sql.90).aspx
Coinciden con la documentación actual:
https://msdn.microsoft.com/en-us/library/ms188929(v=sql.120).aspx
En cuanto a BEGIN...END
, la documentación de Microsoft no proporciona una guía clara.
La definición no tiene punto y coma:
BEGIN
{
sql_statement | statement_block
}
END
Sin embargo, su ejemplo muestra un punto y coma después de END:
IF @@TRANCOUNT = 0
BEGIN
SELECT FirstName, MiddleName
FROM Person.Person WHERE LastName = ''Adams'';
ROLLBACK TRANSACTION;
PRINT N''Rolling back the transaction two times would cause an error.'';
END;
https://msdn.microsoft.com/en-us/library/ms190487.aspx
El punto y coma final no es consistente con la documentación propia de Microsoft para el control de IF
de la construcción del lenguaje de flujo:
IF Boolean_expression
{ sql_statement | statement_block }
[ ELSE
{ sql_statement | statement_block } ]
Ni esa definición ni su código de ejemplo muestran ningún punto y coma:
DECLARE @compareprice money, @cost money
EXECUTE Production.uspGetList ''%Bikes%'', 700,
@compareprice OUT,
@cost OUTPUT
IF @cost <= @compareprice
BEGIN
PRINT ''These products can be purchased for less than
$''+RTRIM(CAST(@compareprice AS varchar(20)))+''.''
END
ELSE
PRINT ''The prices for all products in this category exceed
$''+ RTRIM(CAST(@compareprice AS varchar(20)))+''.''
https://msdn.microsoft.com/en-us/library/ms182717(v=sql.110).aspx
Sin embargo, su documentación ELSE
, aunque no muestra ningún punto y coma en la definición, muestra uno en el ejemplo, después del END
final.
Definición:
IF Boolean_expression { sql_statement | statement_block }
[ ELSE { sql_statement | statement_block } ]
Ejemplo:
IF 1 = 1 PRINT ''Boolean_expression is true.''
ELSE PRINT ''Boolean_expression is false.'' ;
https://msdn.microsoft.com/en-us/library/ms182587(v=sql.110).aspx
El estándar ANSI no resuelve la ambigüedad porque estas son extensiones no estándar:
Las instrucciones de control de flujo no están cubiertas por el estándar ANSI SQL porque son extensiones de SQL propietarias. Los Libros en pantalla de SQL Server son incompletos sobre el tema y muchos de los ejemplos (en el momento de esta escritura) son inconsistentes y no siempre incluyen terminadores de instrucciones. Además, los bloques de instrucciones de control de flujo son confusos debido a las numerosas variaciones, el anidamiento y las especificaciones opcionales BEGIN / END.
http://www.dbdelta.com/always-use-semicolon-statement-terminators/
Sin embargo, el comportamiento del servidor arroja algo de luz. Lo siguiente no es un error de sintaxis en SQL Server 2005:
DECLARE @foo int;
IF @foo IS NULL
BEGIN
WITH Blah AS
(
SELECT
''a'' AS a
)
SELECT
a
FROM Blah;
END
Así que el BEGIN
sí mismo no requiere un punto y coma. Sin embargo, lo siguiente produce un error de sintaxis en SQL Server 2005:
DECLARE @foo int;
IF @foo IS NULL
BEGIN
WITH Blah AS
(
SELECT
''a'' AS a
)
SELECT
a
FROM Blah;
END
WITH Blah2 AS
(
SELECT
''a'' AS a
)
SELECT
a
FROM Blah2;
Lo anterior resulta en este error:
Mensaje 319, nivel 15, estado 1, línea 13 Sintaxis incorrecta cerca de la palabra clave ''con''. Si esta declaración es una expresión de tabla común o una cláusula xmlnamespaces, la instrucción anterior debe terminar con un punto y coma.
También arroja ese error en SQL Server 2008 R2.
Se pone aún más confuso. La documentación de Microsoft para TRY...CATCH
muestra un punto y coma opcional después de END CATCH
, y sus ejemplos son consistentes con eso.
BEGIN TRY
{ sql_statement | statement_block }
END TRY
BEGIN CATCH
[ { sql_statement | statement_block } ]
END CATCH
[ ; ]
Sin embargo, si tiene un CTE inmediatamente después de un BEGIN TRY
, sin un punto y coma, se producirá un error.
BEGIN TRY
WITH Blah AS
(
SELECT
''a'' AS a
)
SELECT
a
FROM Blah;
END TRY
BEGIN CATCH
END CATCH
En SQL Server 2008 R2, el lote anterior produce este error:
Mensaje 319, nivel 15, estado 1, línea 2 Sintaxis incorrecta cerca de la palabra clave ''con''. Si esta declaración es una expresión de tabla común, una cláusula xmlnamespaces o una cláusula de contexto de seguimiento de cambios, la instrucción anterior debe terminar con un punto y coma.
El error implica que BEGIN TRY
es una declaración (que no lo es), y que un punto y coma "soluciona" el problema (que lo hace). Eso es correcto, esto funciona:
BEGIN TRY;
WITH Blah AS
(
SELECT
''a'' AS a
)
SELECT
a
FROM Blah;
END TRY
BEGIN CATCH
END CATCH
Sin embargo, Microsoft dice que no es una buena práctica:
Publicado por Microsoft el 29/12/2009 a las 12:11 p. M. Estoy resolviendo el siguiente error de SQL11 como "por diseño". Aquí está la explicación:
El punto y coma entre END TRY y BEGIN CATCH no debe permitirse, ya que en realidad no son declaraciones diferentes, sino partes de la misma instrucción TRY-CATCH. Solo permitimos puntos y coma cuando separan dos declaraciones en una secuencia.
Una explicación por qué entonces permitimos puntos y coma después de BEGIN TRY y BEGIN CATCH. Estas palabras clave sirven como "paréntesis" de apertura que inician una secuencia de instrucciones incrustada. Los puntos y coma después de BEGIN TRY / BEGIN CATCH se analizan como parte de esa secuencia incrustada, con la primera frase de la secuencia vacía. Si bien permitimos esta sintaxis, no lo recomendaría como una buena práctica de codificación porque crea una impresión errónea de que BEGIN TRY / BEGIN CATCH son declaraciones independientes e independientes.
La forma recomendada de manejar esa situación es con un BEGIN...END
adicional BEGIN...END
para mayor claridad:
BEGIN TRY
BEGIN
WITH Blah AS
(
SELECT
''a'' AS a
)
SELECT
a
FROM Blah;
END
END TRY
BEGIN CATCH
END CATCH
Sin embargo, ese END
antes de END TRY
probablemente debería tener un punto y coma. Después de todo, esto arrojará un error:
BEGIN TRY
BEGIN
WITH Blah AS
(
SELECT
''a'' AS a
)
SELECT
a
FROM Blah;
END
WITH Blah2 AS
(
SELECT
''b'' AS b
)
SELECT
b
FROM Blah2;
END TRY
BEGIN CATCH
END CATCH
Tal vez siempre antes de un CTE WITH
un punto y coma no es tan tonto.