Sql server tsql-sp_executesql差异

Sql server tsql-sp_executesql差异,sql-server,tsql,stored-procedures,exec,sp-executesql,Sql Server,Tsql,Stored Procedures,Exec,Sp Executesql,我的orm工具执行过程的方式有问题 我是这样执行的: exec PostViewProc @Id='18767F6A-FF7A-47E9-AF09-6DB8A2F3B20E',@AuthorId='5455D9B9-B25A-41BD-BD2C-C9CBAE87D629' 按预期返回1行 orm工具就是这样生成的: exec sp_executesql N'EXEC [PostViewProc] @Id, @AuthorId', N'@Id uniqueidentifier,@AuthorI

我的orm工具执行过程的方式有问题

我是这样执行的:

exec PostViewProc @Id='18767F6A-FF7A-47E9-AF09-6DB8A2F3B20E',@AuthorId='5455D9B9-B25A-41BD-BD2C-C9CBAE87D629'
按预期返回1行

orm工具就是这样生成的:

exec sp_executesql 
N'EXEC [PostViewProc] @Id, @AuthorId',
N'@Id uniqueidentifier,@AuthorId uniqueidentifier',
@Id='18767F6A-FF7A-47E9-AF09-6DB8A2F3B20E',@AuthorId='5455D9B9-B25A-41BD-BD2C-C9CBAE87D629'
一无所获

第一个很好用。但是orm生成的“sp_executesql”永远不能正常工作。如果我删除@AuthorId,orm生成的一个可以正常工作,但是我添加了一些其他参数,它再次崩溃

我有一些其他的程序和生活同样的问题一遍又一遍。不同的参数会导致意外的结果,甚至参数的计数也会导致意外的结果。甚至错误。当使用sp_executesql时,另一个就可以正常工作了

我需要一些关于这里发生的事情的好解释,因为这个过程本身没有问题,我现在很困惑。

试试下面的脚本

exec sp_executesql '18767F6A-FF7A-47E9-AF09-6DB8A2F3B20E','5455D9B9-B25A-41BD-BD2C-C9CBAE87D629'

我们确实讨论过这种情况,并决定最好的解决方案是以精确的rigth顺序传递所有参数。如果过程为自己的参数处理null值,那么只需将它们设置为null或任何其他最适合的值


谢谢你们的时间、耐心和兴趣@GarethD&@Mukund

好的,正如评论中指出的,问题是参数的顺序。要演示此问题,请想象以下简单过程

CREATE PROCEDURE dbo.TestProc @A INT = NULL, @B INT = NULL, @C INT = NULL
AS
BEGIN
    SELECT TOP 1 A = @A, B = @B, C = @C;
END
GO
要记住的关键是变量和参数之间没有映射,例如

DECLARE @C INT = 1;
EXECUTE dbo.TestProc @C;
无法识别您的变量名为@C,因此您希望将其分配给同名参数。如果在调用过程时没有显式地将值分配给参数,则将按照先到先得的原则分配这些值,因此上面将返回:

A   B       C
------------------
1   NULL    NULL
事实上,由于您的变量只不过是一个占位符,因此上述查询与执行没有什么不同:

EXECUTE dbo.TestProc 1;
当然,您不会期望过程知道您打算将1作为@C而不是@A的值传递。您的ORM生成的查询也有类似的问题。上述程序的等效代码为:

EXECUTE sp_executesql N'EXEC dbo.TestProc @A, @C', N'@A INT, @C INT', @A = 1, @C = 2;
返回:

A   B   C
------------
1   2   NULL
现在回答评论中的一些问题

使用sp_executesql时,我会传递参数名称和类型,不是吗

是的,您可以,但这不是强制性的,以下两个语句将产生相同的结果:

EXECUTE sp_executesql 
    N'EXEC dbo.TestProc @A = @A, @B = @B, @C = @C', 
    N'@A INT, @B INT, @C INT', 
    @A = 1, @B = 2, @C = 3; 

EXECUTE sp_executesql 
    N'EXEC dbo.TestProc @A, @B, @C', 
    N'@A INT, @B INT, @C INT', 
    1, 2, 3; 
如果您只想传递某些值,则建议使用命名参数,但不强制使用。不同之处在于,如果不使用参数名称,则必须按正确顺序提供参数:

EXECUTE sp_executesql 
    N'EXEC dbo.TestProc @A = @A, @C = @C', 
    N'@A INT, @C INT', 
    @A = 1, @C = 3; 

EXECUTE sp_executesql 
    N'EXEC dbo.TestProc @A, @B, @C', 
    N'@A INT, @B INT, @C INT', 
    1, NULL, 3; 
为什么proc不能匹配它们

如上所述,过程不知道变量名,只知道它的值,因此以下两条语句是等效的:

DECLARE @C INT = 1;
EXECUTE dbo.TestProc @c;

EXECUTE dbo.TestProc 1;
如果检查前一个查询的执行计划XML,则可以确认:

<ParameterList>
    <ColumnReference Column="@C" ParameterCompiledValue="NULL" ParameterRuntimeValue="NULL" />
    <ColumnReference Column="@B" ParameterCompiledValue="NULL" ParameterRuntimeValue="NULL" />
    <ColumnReference Column="@A" ParameterCompiledValue="NULL" ParameterRuntimeValue="(1)" />
</ParameterList>
@A匹配参数名,但@D不匹配,常数2也不匹配。没有一种合理的方法来解决这个问题,而且没有一种语言可以从传递的变量名推断参数

这4行tsql代码都做了什么

第1行只是调用过程。 第2行是语句参数-这是要执行的sql。 第3行是@params参数,它包含语句中使用的所有参数的定义。 第4行是@params中使用的参数值,除非明确分配,例如@A=1、@B=2。这些参数的分配顺序与参数的定义顺序相同 我还应该对这个过程定义什么,才能让它了解这里发生的事情

我不知道您正在使用什么ORM,因此我不确定如何强制它生成正确的代码,它应该生成:

EXEC sp_executesql 
N'EXEC [PostViewProc] @Id = @Id, @AuthorID = @AuthorId',
N'@Id uniqueidentifier,@AuthorId uniqueidentifier',
@Id='18767F6A-FF7A-47E9-AF09-6DB8A2F3B20E',@AuthorId='5455D9B9-B25A-41BD-BD2C-C9CBAE87D629';
第二行的区别已从

N'EXEC [PostViewProc] @Id, @AuthorId',


如果无法强制使用,则必须以正确的顺序传递所有值,包括空值。

实际过程中定义的参数的顺序是什么?我能看到的唯一区别是,在查询中,您显式地声明了参数,而动态sql只传递值EXEC proc@Param=@ParamValue vs EXEC proc@ParamValue@GarethDId 1,AuthorId 8。我是否必须定义所有参数并为它们设置一些值,即使我不需要它们,因为它是这样工作的。该过程处理空参数,实际上所有参数的默认值都为空。我可以像Exec PostViewProc一样执行它,不需要任何参数。我不确定它是什么ORM,但我想说的是,解决方法是按照正确的顺序传递所有参数,在适当的地方传递null。请记住,该过程不知道要传递的参数的名称-因此,尽管您传递了一个名为@AuthorID的变量,但该过程只看到它的值,因此无法猜测您是否希望将其作为同名参数的值传递。看起来我需要传递所有参数
我相信你,但我得问问;使用sp_executesql时,我会传递参数名称和类型,不是吗?为什么proc不能匹配它们?这4行tsql代码都做了什么?我不明白。我还应该为该过程定义什么,以使其了解此处发生的情况回答所有这些问题,我花了比评论多一点的时间,所以我不得不添加一个答案,但希望它能有所帮助。Msg 214,16级,状态2,过程sp_executesql,第1行过程需要类型为“ntext/nchar/nvarchar”的参数“@statement”。如果存储过程中有更多参数,则可以修改exec语句。语句不是该过程的参数。有比这两个参数更多的参数,但是proc处理空参数,实际上每个参数的默认值都是空的。你能解释一下“修改”吗?我的意思是如何修改?在我的northwind数据库中,创建过程customorderhist'@CustomerID nchar5作为选择产品名,Total=SUMQuantity FROM Products P,[订单详细信息]OD,订单O,客户C其中C.CustomerID=@CustomerID和C.CustomerID=O.CustomerID和O.OrderID=OD.OrderID和OD.ProductID=P.ProductID按产品名称分组我可以以exec dbo.customOrderHist ALFKIOh的身份执行此sp。好了,现在我知道了。不,这里不是这样,我有11个参数,其中一些是空的。例如,在第x页我需要第1和第5个参数,在第y页我需要第3和第8个参数,其余为空。
EXEC sp_executesql 
N'EXEC [PostViewProc] @Id = @Id, @AuthorID = @AuthorId',
N'@Id uniqueidentifier,@AuthorId uniqueidentifier',
@Id='18767F6A-FF7A-47E9-AF09-6DB8A2F3B20E',@AuthorId='5455D9B9-B25A-41BD-BD2C-C9CBAE87D629';
N'EXEC [PostViewProc] @Id, @AuthorId',
N'EXEC [PostViewProc] @Id = @Id, @AuthorID = @AuthorId',