微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在参数化查询中传递模式名称

如何解决如何在参数化查询中传递模式名称

我需要将架构值动态添加查询中。我试图按照我们通常使用值的方式构建它,但意识到它不能以相同的方式使用模式名称

这就是我想要做

sql = "SELECT Name FROM [@dbo].[Members]";
...
command.Parameters.Add("@dbo",sqlDbType.VarChar).Value = "dbo";

我知道我可以通过直接在查询添加变量来构建查询,如下所示:

sql = $@"SELECT Name FROM [{parameter}].[Members]";

但我想禁止任何类型的 sql 注入,所以想继续使用上述参数化查询

任何人都可以帮助实现这个想法吗?

TIA

解决方法

据我所知,您只能将参数传递给动态查询,而不是对象名称。您可以执行以下操作:

在看到 Panagiotis 的解决方案后更新。我们可以把存在的部分取出来。我不是 C# 专家,但我们想做类似的事情:

DECLARE @Table NVARCHAR(100);
DECLARE @Schema NVARCHAR(50);

SET @Schema = 'dbo';  --This part will come from C#
SET @Table = 'Tablename';  --This part will come from C#

DECLARE @sql NVARCHAR(MAX);

IF EXISTS(SELECT * FROM sys.tables WHERE name = @Table and schema_id = SCHEMA_ID(@Schema))
BEGIN
  SET @sql = N'SELECT TOP 1 *  FROM '+ QUOTENAME(@Schema) + '.' + QUOTENAME(@Table) +';';
  PRINT @sql;
  EXEC sp_executesql @sql;
END 
ELSE
  RAISERROR('Table or Schema doesn''t exist.',16,1);

IF EXISTS 中,您需要将表名和架构名作为参数传递给动态查询。

在实际查询中,您需要将表名和模式名串联起来。

这也将防止 sql 注入,如果表不存在,则会引发错误。

,

架构不是参数。查询参数等效于例如 C# 中的函数参数。它们用于传递值。在 SQL 中,表和列等效于 C# 类型和属性。您不能按名称指定它们。 SQL 查询中的架构类似于 C# 中的命名空间。该表相当于一个类型。在 C# 中,仅仅因为 Sales.RecordDiagnostics.Record 具有相同的类型名称并不意味着这两种类型可以以相同的方式使用。

这个问题没有解释为什么动态传递架构名称。几乎可以肯定有更简单、更有效和更安全的方法来查询多个模式中的相似表,但解决方案将取决于实际问题。

如果效率不高,有一些技术可用于使此类动态查询安全。 我真的,真的尽量避免将架构视为值。

使用 QUOTENAME

一种选择是在 T-SQL 脚本中使用 QUOTENAME 来构建动态查询。至少这样,如果模式和表名错误,则会抛出语法错误:

sql = @"declare @sql nvarchar(max)='SELECT Name FROM ' + QUOTENAME(@dbo) + '.[Members]';
select @sql;
exec sp_executesql @sql;";
...
command.Parameters.Add("@dbo",SqlDbType.NVarChar,100).Value = "dbo";

QUOTENAME 会将 sys].schemas; PRINT ''x''; -- 之类的内容转换为 [[sys]].schemas; PRINT 'x'; --]。这将导致错误:

declare @sql nvarchar(max)= 'select * from [' +quotename('sys].schemas; PRINT ''x''; --')
select @sql
exec sp_executesql @sql;
--------
select * from [[sys]].schemas; PRINT 'x'; --]

Invalid object name '[sys].schemas; PRINT 'x'; --'.

使用此类脚本很容易出现引用错误。这可以提取到存储过程中:

CREATE PROCEDURE GetMemberNameBySchema
     @dbo nvarchar(100)
as
declare @sql nvarchar(max)='SELECT Name FROM ' + QUOTENAME(@dbo) + '.[Members]';
exec sp_executesql @sql;

验证架构名称

在构造查询之前查询 sys.schema 以确保架构正确。假设您正在使用 Dapper(因此我不必编写所有 ADO.NET 代码):

var schema="dbo";
var isValid=connection.ExecuteScalar<bool?>(
    "select 1 from sys.schema where name=@name",new {name=schema});
//isValid will be null if nothing is found
if(isValid ==true)
{
    var names=connection.Query($"SELECT Name FROM [{schema}].[Members]");
    ...
}

这样做是安全的,因为第一个查询确保架构名称有效。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。