Numéro de ligne d'impression SQL en commentaire de la procédure stockée dynamiquement créée?

StackOverflow https://stackoverflow.com/questions/19850270

Question

J'ai écrit un script qui fait plusieurs milliers de lignes que j'utilise pour générer des procédures stockées dynamiquement.

Je souhaite référencer le script qui a généré les procédures stockées dans les commentaires dans les procédures stockées, et je voudrais être en mesure de se référer à la ligne dans le fichier de script en insérant le numéro de ligne du fichier de script dans les commentaires dans la procédure stockée dossier.

Ainsi, par exemple, si @@ line_number a donné le numéro de ligne que je veux dans le code ci-dessous, alors @@ line_number devrait être 5

1| declare @job varchar(max)
2| SET @job = '/* this is generated dynamicly by _______  */'
3| SET @job = @job + 'SELECT *' + CHAR(10)
4| SET @job = @job + 'FROM ' + @Table_Name + CHAR(10)
5| SET @job = @job + '/* ' + @@line_number + ' */'
Était-ce utile?

La solution

Vous pouvez utiliser Try / Catch avec une erreur forcée car le bloc de capture peut renvoyer le numéro de ligne sur lequel l'erreur s'est produite via la fonction error_line (). La construction complète, formatée pour la lisibilité, est:

BEGIN TRY
    ;THROW 50000, 'Line#', 1 -- all 3 values are arbitrary, but required
END TRY
BEGIN CATCH
    SET @LineNumber = ERROR_LINE()
END CATCH

Maintenant, pour faire en sorte que la variable @lineNumber remplisse avec le numéro de ligne sur lequel il est réglé, vous pouvez réduire cette construction en une seule ligne comme suit:

BEGIN TRY;THROW 50000,'',1;END TRY BEGIN CATCH;SET @Line=ERROR_LINE();END CATCH

Voici un exemple complet de celui-ci:

SET ANSI_NULLS ON
SET NOCOUNT ON
GO
-- Line #1 (of current batch, not of the entire script if GOs are used)

DECLARE @CRLF NCHAR(2) = NCHAR(13) + NCHAR(10),
        @SQL1 NVARCHAR(MAX) = '',
        @SQL2 NVARCHAR(MAX) = '', -- Line #5
        @Line INT = -1 -- default to an invalid line #

SET @SQL1 += N'/********************' + @CRLF
SET @SQL1 += N' *' + @CRLF
SET @SQL1 += N' * Test Auto-' + @CRLF -- Line #10
SET @SQL1 += N' * Generated Proc 1' + @CRLF
BEGIN TRY;THROW 50000,'',1;END TRY BEGIN CATCH;SET @Line=ERROR_LINE();END CATCH
SET @SQL1 += N' * Line #:' + CONVERT(NVARCHAR(10), @Line) + @CRLF
SET @SQL1 += N' *' + @CRLF
SET @SQL1 += N' ********************/' + @CRLF -- Line #15

-- more code here

SET @SQL2 += N'/********************' + @CRLF
SET @SQL2 += N' *' + @CRLF -- Line #20
SET @SQL2 += N' * Test Auto-' + @CRLF
SET @SQL2 += N' * Generated Proc 2' + @CRLF
BEGIN TRY;THROW 50000,'',1;END TRY BEGIN CATCH;SET @Line=ERROR_LINE();END CATCH
SET @SQL2 += N' * Line #:' + CONVERT(NVARCHAR(10), @Line) + @CRLF
SET @SQL2 += N' *' + @CRLF -- Line #25
SET @SQL2 += N' ********************/' + @CRLF

PRINT @SQL1
PRINT @SQL2
GO

Les numéros de ligne renvoyés pour Proc 1 et Proc 2 sont respectivement de 12 et 23, ce qui est correct pour les deux.

Veuillez noter que la commande Throw a commencé dans SQL Server 2012. Si vous utilisez SQL Server 2005, 2008 ou 2008 R2, vous devez utiliser la fonction Raiserror () au lieu de lancer.

Autres conseils

j'ai changé La réponse de Salomonrutzky Un peu à obtenir, c'est fonctionner dans les versions SQL Server avant 2012:

DECLARE @Line INT
SET @Line = 0 BEGIN TRY RAISERROR ('Line#', 11, 1)WITH NOWAIT   END TRY BEGIN CATCH SET @Line=ERROR_LINE() END CATCH

PRINT('/* testing ... I messed up somewhere near line: ' + CONVERT(varchar(10), ISNULL(@Line, 0)) + ' */')

Je n'ai pas trouvé de fonction intégrée pour renvoyer le numéro de ligne actuel, j'ai donc commencé à faire une fonction pour trouver le numéro de ligne pour moi.

Si j'obtiens le texte de la requête en cours d'exécution actuelle en haut et que je déclare une variable, puis de copier et de passer l'appel de fonction et le code d'incrément @lineCounter, je peux obtenir le numéro de ligne actuel.

    DECLARE @var1 NVARCHAR(MAX) 
    SELECT @var1 = sqltext.TEXT
    FROM sys.dm_exec_requests req
    CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext
    WHERE req.session_id = @@SPID
    DECLARE @LineCounter int
    SET @LineCounter = 0
    DECLARE @Current_Line_Number int
    SET @Current_Line_Number = 0
SET @LineCounter = @LineCounter + 1
SELECT @Current_Line_Number = [MSMS].[dbo].[ReturnLineNumber] (@var1, @LineCounter)
PRINT @Current_Line_Number

C'est la fonction

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      James J
-- Create date: 11/11/2013
-- Description: Function to return the line number for 
-- where the query was called from when passed the query 
-- an the count of the times it has already been used.
-- =============================================
ALTER FUNCTION ReturnLineNumber 
(
    @CurrentQuery nvarchar(max), 
    @Count  int
)
RETURNS int
AS
BEGIN
    DECLARE @var1 NVARCHAR(MAX) 
    DECLARE @functionName nvarchar(30)
    SET @functionName = 'ReturnLineNumber'
    SET @var1 = @CurrentQuery

    DECLARE @LineCount int
    SET @LineCount = 0

    IF (CHARINDEX(CHAR(13), @var1) > 0)
    BEGIN
        DECLARE @queryString nvarchar(max)
        SET @queryString = @var1
        DECLARE @LineIndex int
        SET @LineIndex = 1
        DECLARE @LineLength int
        DECLARE @linestring nvarchar(max)
        DECLARE @functioncount int
        SET @functioncount = 0
        WHILE (@LineIndex > 0)
        BEGIN
            SET @LineIndex = CHARINDEX(CHAR(13), @queryString)
            SET @LineLength = LEN(@queryString) - CHARINDEX(CHAR(13), @queryString)
            SET @linestring = SUBSTRING(@queryString, 0, @LineIndex + 1)
            SET @queryString = SUBSTRING(@queryString, @LineIndex + 1, @LineLength)
            SET @LineCount = @LineCount + 1
            IF (CHARINDEX(@functionName, @linestring) > 0)
            BEGIN
                SET @functioncount = @functioncount + 1
                IF (@functioncount = @Count)
                BEGIN
                    RETURN @LineCount
                END
            END
        END
    END
    RETURN 0
END
GO

Ce n'est pas un excellent moyen d'obtenir le numéro de ligne et je devrais probablement ajouter quelques chèques supplémentaires pour m'assurer que je n'ai pas commenté les appels de fonction, mais c'est le plus proche que j'ai pour le moment.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top