Domanda

Ho scritto una sceneggiatura lunga diverse migliaia di righe che sto usando per generare alcune procedure memorizzate in modo dinamico.

Voglio fare riferimento allo script che ha generato le procedure memorizzate nei commenti nelle procedure memorizzate e vorrei essere in grado di fare riferimento alla riga nel file di script inserendo il numero di riga del file di script nei commenti nella procedura memorizzata file.

Quindi, ad esempio, se @@ line_number ha dato il numero di riga che desidero nel muggito, quindi @@ line_number dovrebbe essere 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 + ' */'
È stato utile?

Soluzione

È possibile utilizzare Try / Catch con un errore forzato poiché il blocco di cattura può restituire il numero di riga su cui si è verificato l'errore tramite la funzione Error_Line (). Il costrutto completo, formattato per la leggibilità, è:

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

Ora, per far popolare la variabile @Linenumber con il numero di linea su cui viene impostata, è possibile ridurre quel costrutto su una singola riga come segue:

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

Ecco un esempio completo del funzionamento:

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

I numeri di linea restituiti per Proc 1 e Proc 2 sono rispettivamente 12 e 23, il che è corretto per entrambi.

Si prega di notare che il comando di lancio è iniziato in SQL Server 2012. Se si utilizza SQL Server 2005, 2008 o 2008 R2, è necessario utilizzare la funzione Raiserror () invece di lanciare.

Altri suggerimenti

Ho cambiato La risposta di Solomonrutzky Un po 'da ottenere è funzionare nelle versioni SQL Server prima del 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)) + ' */')

Non ho trovato una funzione integrata per restituire il numero di riga corrente, quindi ho iniziato a fare una funzione per trovare il numero di riga per me.

Se ricevo il testo della query in esecuzione corrente in alto e dichiaro una variabile, quindi copia e oltre la chiamata della funzione e il codice di incremento di @LineCounter, posso ottenere il numero di riga corrente.

    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

Questa è la funzione

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

Questo non è un ottimo modo per ottenere il numero di linea e probabilmente dovrei aggiungere altri controlli per assicurarmi di non aver commentato le chiamate di funzione, ma questo è il più vicino che ho ottenuto per il momento.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top