【问题标题】:SQL Table Value Parameter only works when its data is copied to temporary tableSQL 表值参数仅在其数据复制到临时表时有效
【发布时间】:2019-10-07 05:34:18
【问题描述】:

我正在使用 dapper 将数据通过 c# 传递到 sql 存储过程。

c#(使用 dapper):

 var dt = new DataTable("dbo.TVPtype");
 dt.SetTypeName("dbo.TVPtype");
 dt.Columns.Add("ID", typeof(int));
 dt.Rows.Add(5);
_db.Execute("mysp", param: new { TVP = dt.AsTableValuedParameter("dbo.TVPtype"), commandType: CommandType.StoredProcedure);

下面的 SQL 查询将不起作用,我不知道为什么!它会从 mytable 中删除所有数据。 SQL 存储过程:

CREATE PROCEDURE [dbo].[mysp] @TVP dbo.TVPtype READONLY AS
DELETE FROM [dbo].[mytable] WHERE NOT EXISTS
(
SELECT NULL FROM @TVP na
WHERE ID = na.ID
)

为了解决这个问题,我在存储过程中使用了一个临时表,如下所示,它运行良好。 我使用临时表的解决方案:

CREATE table temptb (ID int)
insert into temptb select * from @TVP

现在我在删除查询中使用 temptb 而不是 @TVP:

DELETE FROM [dbo].[mytable] WHERE NOT EXISTS
(
SELECT NULL FROM temptb na
WHERE ID = na.ID
)

它运作良好并删除特定数据(不是所有数据)! 那么我的第一个查询有什么问题?

【问题讨论】:

  • 首先,找出问题出在 c# 还是 SQL - 尝试直接从 SSMS 运行第一个存储过程,看看会发生什么。

标签: c# sql stored-procedures table-valued-parameters


【解决方案1】:

我不能告诉你,为什么它与临时表一起工作,但如果你把它改成 DELETE 语句,问题就出在:

DELETE t1 
FROM [dbo].[mytable] AS t1 WHERE NOT EXISTS
(
    SELECT NULL FROM @TVP na
    WHERE t1.ID = na.ID
)

它会起作用的。看,当我将别名添加到 mytable 条件时,它应该比较哪个 ID 变得清晰。在您的示例中,它可能会将@TVP ID 与其自身进行比较(这是我的猜测)。

我想在您的查询中再添加两点:

  1. 在检查是否存在时最好选择非 NULL 的内容,因为 NULL 在 SQL 中是特殊的(尽管它在您的示例中有效)。例如SELECT 1 FROM @TVP... 会更易读

  2. 为什么不这样做:

片段:

DELETE FROM [dbo].[mytable] AS t1 WHERE ID NOT IN
(
    SELECT na.ID FROM @TVP na
)

【讨论】:

    【解决方案2】:

    限定您的列名!你以为你在写:

    DELETE FROM [dbo].[mytable]
        WHERE NOT EXISTS (SELECT 1
                          FROM @TVP na
                          WHERE mytable.ID = na.ID
                         );
    

    但你不是。 SQL 的作用域规则将您的查询解释为:

    DELETE FROM [dbo].[mytable]
        WHERE NOT EXISTS (SELECT 1
                          FROM @TVP na
                          WHERE na.ID = na.ID
                         );
    

    这是相当荒谬的。 WHERE 与外部查询不相关。它将删除所有行(如果@TVP 为空或ID 始终为NULL)或不删除行(任何其他情况)。

    如果您限定所有列引用,您将永远不会遇到这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-17
      • 1970-01-01
      • 2016-08-17
      • 2011-01-29
      • 2021-07-17
      • 2014-02-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多