将表和列名称作为参数传递并检索值

Ari*_*rie 0 sql t-sql sql-server

我正在尝试构建通用查询以传递我想要依赖的列名和表名我要选择值.

到目前为止这是我的代码:

ALTER PROCEDURE [dbo].[GenericCountAll]
    @TableName VARCHAR(100),
    @ColunName VARCHAR(100)
AS
BEGIN
    DECLARE @table VARCHAR(30);
    DECLARE @Rowcount INT;

    SET @table = N'SELECT COUNT(' + @ColunName +') FROM ' + @TableName + '';
    EXEC(@table)

    SET @Rowcount = @@ROWCOUNT
    SELECT @Rowcount
END
Run Code Online (Sandbox Code Playgroud)

试图像这样执行:

EXEC GenericCountAll 'T_User', 'Id';
Run Code Online (Sandbox Code Playgroud)

但看起来我得到两个结果,第一个结果总是返回值1,第二个结果返回实际计数.有人可以看看吗?

Lar*_*rnu 5

不要像那样创建动态sql!想象一下,如果我跑:

EXEC GenericCountAll '*/DROP PROCEDURE dboGenericCountAll;--', '1);/*';
Run Code Online (Sandbox Code Playgroud)

生成的执行SQL将是:

SELECT COUNT(1);/*) FROM */ DROP PROCEDURE dboGenericCountAll;--
Run Code Online (Sandbox Code Playgroud)

那很简单,就是DROP你的程序.这只是一个简单的例子.如果我知道我可以继续做恶意事情,我甚至可以创建一个新的登录或用户,并创建一个db_ownersysadmin(取决于用于运行该过程的权限).

我不知道这是什么意思@@ROWCOUNT,我怀疑是否需要.因此,为了使这个安全,你需要做这样的事情:

ALTER procedure [dbo].[GenericCountAll]
    @TableName sysname, --Note the datatype change
    @ColumnName sysname
AS
BEGIN
    DECLARE @SQL nvarchar(MAX);

    SELECT  N'SELECT COUNT(' + QUOTENAME(c.[name]) + N') AS RowCount' + NCHAR(10) +
            N'FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.name) + N';'
    FROM sys.tables t
         JOIN sys.schemas s ON t.schema_id = s.schema_id
         JOIN sys.columns c ON t.object_id = c.object_id
    WHERE t.[name] = @TableName
      AND c.[name] = @ColumnName;
    /*
    If either the column or the table doesn't exist, then @SQL
    will have a value of NULL. This is a good thing, as it 
    is a great way to further avoid injection, if a bogus
    table or column name is passed
    */

    IF @SQL IS NOT NULL BEGIN;
        PRINT @SQL; --Your best debugging friend
        EXEC sp_executesql @SQL;
    END ELSE BEGIN;
        RAISERROR(N'Table does not exist, or the Column does not exist for the Table provided.',11,1);
    END;

END
Run Code Online (Sandbox Code Playgroud)