Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

SQL Server:So erhalten Sie einen Datenbanknamen als Parameter in einer gespeicherten Prozedur

Wenn Sie EXEC @Var verwenden (ohne Klammern - also nicht EXEC (@Var) ) SQL Server sucht nach einer gespeicherten Prozedur, die mit dem in @Var übergebenen Namen übereinstimmt . Sie können dafür eine dreiteilige Benennung verwenden.

Wenn sys.sp_executesql mit einem dreiteiligen Namen aufgerufen wird, wird der Kontext auf die Datenbank gesetzt, in der sie aufgerufen wird.

Sie können dies also mit Null tun SQL-Injection-Risiko wie unten.

CREATE PROCEDURE dbo.test @dbname SYSNAME,
                          @col    SYSNAME
AS
    SET NOCOUNT, XACT_ABORT ON;

    DECLARE @db_sp_executesql NVARCHAR(300) = QUOTENAME(@dbname) + '.sys.sp_executesql'

    EXEC @db_sp_executesql N'
                            SELECT TOP 100 *
                            FROM sys.columns 
                            WHERE name = @col',
                           N'@col sysname',
                           @col = @col 

Selbst wenn das obige nicht möglich wäre, würde ich dennoch argumentieren, dass es durchaus möglich ist, dynamisches SQL dafür auf sichere Weise wie hier zu verwenden.

CREATE PROCEDURE dbo.test
    @dbname SYSNAME, /*Use Correct Datatypes for identifiers*/
    @col SYSNAME
AS
    SET NOCOUNT ON
    SET XACT_ABORT ON

    IF DB_ID(@dbname) IS NULL  /*Validate the database name exists*/
       BEGIN
       RAISERROR('Invalid Database Name passed',16,1)
       RETURN
       END

DECLARE @dynsql nvarchar(max)  

 /*Use QUOTENAME to correctly escape any special characters*/
SET @dynsql = N'USE '+ QUOTENAME(@dbname) + N'

                         SELECT TOP 100 *
                         FROM sys.tables 
                         WHERE name = @col'

 /*Use sp_executesql to leave the WHERE clause parameterised*/
EXEC sp_executesql @dynsql, N'@col sysname', @col = @col