2016-08-25 5 views
1

Ich versuche eine Stored Procedure zu erstellen, die dynamisch SQL lädt. Ich versuche, String-Injektion zu verhindern, indem Sie die sp_executesql verwenden, um alle Parameter an die Abfrage zu übergeben. Die Abfrage scheint gut auszuführen, aber ich habe zwei Probleme. Erstens, wenn ich unter Verwendung meiner Alias Name, der das Muster xx\xxxxx verwendet, es löst einen Fehler aus, der besagt, dass ein Fehler in der Nähe der ersten beiden Buchstaben des Alias ​​ist. Ich denke, das liegt an dem NVARCHAR-Typ, aber nicht ganz sicher, wie man mit dem \ darin umgehen soll. Zweitens, und noch wichtiger, gibt das Gesamtverfahren nichts zurück. Es sagt mir, dass es gut ausgeführt hat, aber ich bekomme meine Tabelle der Ergebnisse nicht wie erwartet.So geben Sie die Tabellenausgabe von SP_ExecuteSQL zurück

Ich habe die Aussagen weggelassen, um die Parameter für die Kürze zu erzeugen (diese gut funktionieren, wenn ich die ganze Zeichenfolge erzeugen und Ausführen EXEC string

Ich bin auch die Verwendung von globalen temporären Tabellen vorsichtig, da dies in einen ausgeführt werden Multi-User-Umgebung

mit vollständigem Code

DECLARE @IDType NVARCHAR(255) = NULL 
DECLARE @Customer NVARCHAR(MAX) = NULL 
DECLARE @IdentifiedBy NVARCHAR(255) = NULL 
DECLARE @ImpactArea NVARCHAR(MAX) = NULL 
DECLARE @Gateway NVARCHAR(255) = NULL 
DECLARE @ProbabilityRating NVARCHAR(255) = NULL 
DECLARE @ImpactRating NVARCHAR(255) = NULL 
DECLARE @CostRevenue NVARCHAR(255) = NULL 
DECLARE @Status NVARCHAR(255) = NULL 
DECLARE @Keywords NVARCHAR(MAX) = NULL 
DECLARE @govOwner NVARCHAR(255) = NULL 

DECLARE @Alias VARCHAR(50) 
DECLARE @Role NVARCHAR(255) 
DECLARE @SQL NVARCHAR(MAX) 
DECLARE @Where NVARCHAR(MAX) = '' 
DECLARE @SQLOrder NVARCHAR(MAX) 

SET @Alias = SUSER_SNAME() 
SET @Role =(SELECT [Role] FROM [FB].[Users] WHERE [Alias] = @Alias) 

IF @IDType IS NOT NULL 
BEGIN 
IF @IDType = 'Blank' 
    SET @Where += ' AND IDType = NULL OR IDType = ''''' 
ELSE IF @IDType != 'All' 
    SET @Where += ' AND IDType = @IDType' 
END 
IF @Customer IS NOT NULL 
BEGIN 
IF @Customer = 'Blank' 
    SET @Where += ' AND Customer = NULL OR Customer = ''''' 
ELSE IF @Customer != 'All' 
    SET @Where += ' AND Customer = @Customer' 
END 
IF @IdentifiedBy IS NOT NULL 
BEGIN 
IF @IdentifiedBy = 'Blank' 
    SET @Where += ' AND IdentifiedBy = NULL OR IdentifiedBy = ''''' 
ELSE IF @IdentifiedBy != 'All' 
    SET @Where += ' AND IdentifiedBy = (SELECT FB.Alias(@IdentifiedBy))' 
END 
IF @ImpactArea IS NOT NULL 
BEGIN 
IF @ImpactArea = 'Blank' 
    SET @Where += ' AND ImpactArea = NULL OR ImpactArea = ''''' 
ELSE IF @ImpactArea != 'All' 
    SET @Where += ' AND ImpactArea = @ImpactArea' 
END 
IF @Gateway IS NOT NULL 
BEGIN 
IF @Gateway = 'Blank' 
    SET @Where += ' AND Gateway = NULL OR Gateway = ''''' 
ELSE IF @Gateway != 'All' 
    SET @Where += ' AND Gateway = @Gateway' 
END 
IF @ProbabilityRating IS NOT NULL 
BEGIN 
IF @ProbabilityRating = 'Blank' 
    SET @Where += ' AND ProbabilityRating = NULL OR ProbabilityRating = ''''' 
ELSE IF @ProbabilityRating != 'All' 
    SET @Where += ' AND ProbabilityRating = @ProbabilityRating' 
END 
IF @ImpactRating IS NOT NULL 
BEGIN 
IF @ImpactRating = 'Blank' 
    SET @Where += ' AND ImpactRating = NULL OR ImpactRating = ''''' 
ELSE IF @ImpactRating != 'All' 
    SET @Where += ' AND ImpactRating = @ImpactRating' 
END 
IF @CostRevenue IS NOT NULL 
BEGIN 
IF @CostRevenue = 'Blank' 
    SET @Where += ' AND CostRevenue = NULL OR CostRevenue = ''''' 
ELSE IF @CostRevenue != 'All' 
    SET @Where += ' AND CostRevenue = @CostRevenue' 
END 
IF @Status IS NOT NULL 
BEGIN 
IF @Status = 'Blank' 
    SET @Where += ' AND Status = NULL OR Status = ''''' 
ELSE IF @Status != 'All' 
    SET @Where += ' AND Status = @Status' 
END 
IF @Keywords IS NOT NULL 

IF @govOwner IS NOT NULL 
BEGIN 
IF @govOwner = 'Blank' 
    SET @Where += ' AND govOwner = NULL OR govOwner = ''''' 
ELSE IF @govOwner != 'All' 
    SET @Where += ' AND govOwner = (SELECT FB.Alias(@govOwner))' 
END 
CREATE TABLE #tmp (
    ID int 
    ,FeedbackType varchar(255) 
    ,ImpactArea varchar(255) 
    ,CreatedDate varchar(11) 
    ,Customer varchar(255) 
    ,IdentifiedBy varchar(255) 
    ,CriticalityRating varchar(255) 
    ,govOwner varchar(255) 
    ,Status varchar(255) 
) 

SET @SQL = 'SELECT 
      fb.ID 
      ,FeedbackType 
      ,ImpactArea 
      ,CONVERT(VARCHAR(11), CreatedDate, 3) AS CreatedDate 
      ,Customer 
      ,IdentifiedBy 
      ,CriticalityRating 
      ,govOwner 
      ,Status 
     INTO #tmp 
     FROM [FB].[Feedback] fb 
     INNER JOIN (SELECT 
         ID 
         ,MAX(Version) AS MaxVer 
        FROM FB.Feedback 
        GROUP BY ID 
     ) mv ON fb.ID = mv.ID AND fb.Version = mv.MaxVer' 

SET @SQLOrder = ' ORDER BY [ID] DESC' 

IF @Where IS NOT NULL 
    SET @Where = ' WHERE ' + (SELECT STUFF(@Where,1 , 4, '')) + ' ' 

IF (@Role != 'Governance Board' AND @Role != 'Admin') 
    BEGIN 
    IF @Where IS NOT NULL 
     SET @Where += ' AND [Author] = @Alias OR [IdentifiedBy] = @Alias' 
    ELSE 
     SET @Where = ' WHERE [Author] = @Alias OR [IdentifiedBy] = @Alias' 
    END 

SET @SQL += @Where + @SQLOrder 

EXECUTE SP_ExecuteSQL @SQL 
    ,@Alias = @Alias 
    ,@Customer = @Customer 
    ,@IdentifiedBy = @IdentifiedBy 
    ,@ImpactArea = @ImpactArea 
    ,@Gateway = @Gateway 
    ,@ProbabilityRating = @ProbabilityRating 
    ,@ImpactRating = @ImpactRating 
    ,@CostRevenue = @CostRevenue 
    ,@Status = @Status 
    ,@Keywords = @Keywords 
    ,@govOwner = @govOwner 

SELECT * FROM #tmp 
DROP TABLE #tmp 

Antwort

2

ändern @SQL durch die Linie

INTO #tmp 

Dann oben EXECUTE SP_ExecuteSQL Entfernen der Linie

INSERT INTO #tmp 

hinzufügen Diese Ihre EXECUTE zu einer select Aussage ändern, und fügen Sie dann, was in Ihrem ausgewählt ist temporäre Tabelle, alle in dieser Sitzung.

Der Fehler, den Sie über den Parameter Alias bekommen, ist, weil Sie tatsächlich ein bisschen vermissen. sp_executesql erfordert @params bei Verwendung von Parametern, die die von Ihnen verwendeten Parameter definieren. Von der documentation:

-- Syntax for SQL Server, Azure SQL Database, Azure SQL Data Warehouse, Parallel Data Warehouse 

sp_executesql [ @stmt = ] statement 
[ 
    { , [ @params = ] N'@parameter_name data_type [ OUT | OUTPUT ][ ,...n ]' } 
    { , [ @param1 = ] 'value1' [ ,...n ] } 
] 

und

[@ params =] N '@ parameter_namedata_type [, ... n]' Ist eine Zeichenfolge, die die Definitionen aller Parameter enthält, die gewesen sind eingebettet in @stmt. Die Zeichenfolge muss entweder eine Unicode-Konstante oder eine Unicode-Variable sein. Jede Parameterdefinition besteht aus einem Parameternamen und einem Datentyp. n ist ein Platzhalter, der zusätzliche Parameterdefinitionen angibt. Jeder in @stmt angegebene Parameter muss in @params definiert sein. Wenn die Transact-SQL-Anweisung oder der Batch in @stmt keine Parameter enthält, ist @params nicht erforderlich.Der Standardwert für diesen Parameter ist NULL.

In Ihrem Fall wird dies wie folgt aussehen:

DECLARE @params NVARCHAR(300) = N'@Alias VARCHAR(50), @Customer NVARCHAR(MAX), @IdentifiedBy NVARCHAR(255), @ImpactArea NVARCHAR(MAX),@Gateway NVARCHAR(255),@ProbabilityRating NVARCHAR(255), @ImpactRating NVARCHAR(255), @CostRevenue NVARCHAR(255), @Status NVARCHAR(255), @Keywords NVARCHAR(MAX), @govOwner NVARCHAR(255)'; 

Und es dann wie folgt verwenden:

EXECUTE SP_ExecuteSQL @SQL, @params 
,@Alias = @Alias 
etc, etc 

So haben Sie Ihre Variablen für die gespeicherte procedue zu definieren, die Sie getan haben, aber auch für die dynamische sql Sie laufen, die @params ist.

+0

groß, dass arbeitete dank. Das einzige Problem, das ich jetzt habe, ist die Verwendung des '@Alias'-Parameters und was ist die beste Vorgehensweise, um' sp_executesql' auszuführen, wenn die Variablen null sind? – Tom

+0

Antwort mit diesem Bit aktualisiert. – BeanFrog

+1

nur für zukünftige ref die 'DECLARE @ params NVARCHAR (300)' war zu kurz. Ich habe dies auf 'NVARCHAR (400)' aktualisiert und es hat gut funktioniert – Tom

0
    Aktualisiert
  1. Sie müssen params Definition sp_executesql passieren, wie unten dargestellt:
DECLARE @p NVARCHAR(MAX) = 'test'; 
SET @SQL = 'select @p'; 
EXECUTE SP_ExecuteSQL @SQL, N'@p NVARCHAR(MAX)', @p = @p; 
  1. Verwenden #tbl statt @tbl, entfernen ,@tbl = @tbl OUTPUT. Verwenden Sie keine SELECT INTO Anweisung. Lokale temporäre Tabellen sind in der aktuellen Sitzung sichtbar und enthalten Code in aufgerufenen Prozeduren und verschachteltem dynamischem SQL.
+0

Ich habe sie bereits oben deklariert, also muss ich nicht neu deklarieren Ich dachte – Tom

+0

@Tom, versuche mein Beispiel ohne Params Definition zu übergeben, gibt es Fehler –

Verwandte Themen