【问题标题】:Is it possible to write a query where table name is retrieved from cell in another table?是否可以编写从另一个表的单元格中检索表名的查询?
【发布时间】:2022-01-15 06:56:57
【问题描述】:

我有一个表 dbo.TableNames 有一个 varcharTableName 包含表名:

    |    Id     | TableName             |
    +-----------+-----------------------+
    |    1      | dbo.BookDictionary    |     
    |    2      | dbo.AnotherDictionary |      

我很好奇,有没有办法代替写作:

SELECT * 
FROM dbo.BookDictionary

这样写:

SELECT * 
FROM 
    (SELECT TableName FROM dbo.TableNames WHERE Id = 1)

【问题讨论】:

  • 是的,但您必须为此使用动态 SQL。看看stackoverflow.com/questions/20678725/…
  • 如果您正在像这样存储表名,我建议分别存储模式和表名。你的表不叫dbo.BookDictionary,它叫BookDictionary,它在一个叫dbo的模式上。虽然这有XY Problem 的强烈气味。

标签: sql sql-server tsql


【解决方案1】:

如果您的TableNames 值有任何可能由最终用户控制,您需要仔细验证检索到的值以避免潜在的SQL Injection 攻击。

DECLARE @TableName nvarchar(max);
SELECT @TableName = TableName FROM dbo.TableNames WHERE ID = @ID;
If @TableName Is Null RAISERROR('Table %d does not exist.', 16, 1, @ID);

DECLARE @VerifiedSchemaName sysname, @VerifiedTableName sysname;

SELECT
    @VerifiedSchemaName = S.name,
    @VerifiedTableName = T.name
FROM
    sys.tables As T
    INNER JOIN sys.schemas As S
    ON S.schema_id = T.schema_id
WHERE
    @TableName = S.name + N'.' + T.name
;

If @@ROWCOUNT = 0 RAISERROR('Table "%s" does not exist.', 16, 1, @TableName);

DECLARE @sql nvarchar(max);
SET @sql = CONCAT('SELECT * FROM ', 
    QUOTENAME(@VerifiedSchemaName), 
    N'.', 
    QUOTENAME(@VerifiedTableName), 
    N';');

EXEC(@sql);

【讨论】:

    【解决方案2】:

    这是可能的,但我不推荐它,因为它会导致性能下降很快退出

    declare @sql varchar(max)
    
    SELECT @sql = CONCAT('SELECT * FROM ', [TableName], ';') 
    FROM [dbo].[TableNames] 
    WHERE Id = 1
    
    sp_executesql @sql
    

    【讨论】:

    • 小心,如果TableName 列中的值不是非常 严格控制的,这很容易受到注入攻击。此外,您对sp_executesql 的调用也不起作用,因为它不是批处理中的第一条语句,并且参数数据类型错误也会产生错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多