C# SQL表值参数仅在其数据复制到临时表时有效
我使用dapper通过c到sql存储过程传递数据 c使用简洁:C# SQL表值参数仅在其数据复制到临时表时有效,c#,sql,stored-procedures,table-valued-parameters,C#,Sql,Stored Procedures,Table Valued Parameters,我使用dapper通过c到sql存储过程传递数据 c使用简洁: 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:
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
)
为了解决这个问题,我在存储过程中使用了一个临时表,如bellow,它工作得很好。
使用临时表的我的解决方案:
CREATE table temptb (ID int)
insert into temptb select * from @TVP
现在我在删除查询中使用了TENTEB而不是@TVP:
DELETE FROM [dbo].[mytable] WHERE NOT EXISTS
(
SELECT NULL FROM temptb na
WHERE ID = na.ID
)
它可以很好地删除特定数据,而不是所有数据!
那么,我的第一个问题出了什么问题 我无法告诉您,为什么它使用临时表,但如果将DELETE语句更改为:
DELETE t1
FROM [dbo].[mytable] AS t1 WHERE NOT EXISTS
(
SELECT NULL FROM @TVP na
WHERE t1.ID = na.ID
)
它会起作用的。请看,当我将alias添加到mytable时,条件变得很清楚,它应该比较哪个ID。在您的示例中,它可能会将@TVP ID与其自身进行比较,这是我的猜测
我想在您的查询中再添加两点:
当您检查是否存在时,最好选择非NULL的内容,因为NULL在sql中是特殊的,尽管它在您的示例中起作用。例如,从@TVP中选择1。。。会更具可读性
为什么不这样做:
片段:
DELETE FROM [dbo].[mytable] AS t1 WHERE ID NOT IN
(
SELECT na.ID FROM @TVP na
)
我无法告诉您为什么它使用临时表,但如果将其更改为:
DELETE t1
FROM [dbo].[mytable] AS t1 WHERE NOT EXISTS
(
SELECT NULL FROM @TVP na
WHERE t1.ID = na.ID
)
它会起作用的。请看,当我将alias添加到mytable时,条件变得很清楚,它应该比较哪个ID。在您的示例中,它可能会将@TVP ID与其自身进行比较,这是我的猜测
我想在您的查询中再添加两点:
当您检查是否存在时,最好选择非NULL的内容,因为NULL在sql中是特殊的,尽管它在您的示例中起作用。例如,从@TVP中选择1。。。会更具可读性
为什么不这样做:
片段:
DELETE FROM [dbo].[mytable] AS t1 WHERE ID NOT IN
(
SELECT na.ID FROM @TVP na
)
限定您的列名!你认为你在写:
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始终为空,或者在任何其他情况下都没有行,那么它将删除所有行
如果您限定所有列引用,您将永远不会遇到此问题。限定您的列名!你认为你在写:
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始终为空,或者在任何其他情况下都没有行,那么它将删除所有行
如果您限定了所有列引用,您将永远不会遇到此问题。首先,找出问题是在c中还是在SQL中-尝试直接从SSMS运行第一个存储过程,看看会发生什么。首先,找出问题是在c中还是在SQL中-尝试直接从SSMS运行第一个存储过程,看看会发生什么。