我有一个返回错误的过程:
必须声明表变量"@PropIDs".
但接下来的信息是:
(123行受影响)
我执行它时会出现错误
EXEC [dbo].[GetNeededProperties] '1,3,5,7,2,12', '06/28/2013', 'TT'
Run Code Online (Sandbox Code Playgroud)
但是工作得很好
EXEC [dbo].[GetNeededProperties] NULL, '06/28/2013', 'TT'
Run Code Online (Sandbox Code Playgroud)
任何人都可以帮助我吗?程序,流程:
CREATE PROCEDURE [dbo].[GetNeededProperties]
@NotNeededWPRNs nvarchar(max), --string like '1,2,3,4,5'
@LastSynch datetime,
@TechCode varchar(5)
AS
BEGIN
DECLARE @PropIDs TABLE
(ID bigint)
Declare @ProductsSQL nvarchar(max);
SET @ProductsSQL = 'Insert into @PropIDs (ID)
SELECT [WPRN] FROM [dbo].[Properties] WHERE(WPRN in (' + @NotNeededWPRNs + '))'
exec sp_executesql @ProductsSQL
SELECT p.WPRN AS ID,
p.Address AS Address,
p.Address AS Street
FROM [dbo].[Properties] AS p
WHERE
p.WPRN NOT IN( SELECT ID FROM @PropIDs)
Run Code Online (Sandbox Code Playgroud)
我在声明这样的表时找到了一种解决方案:
IF OBJECT_ID('#PropIDs', 'U') IS NOT NULL
DROP TABLE #PropIDs
CREATE TABLE #PropIDs
Run Code Online (Sandbox Code Playgroud)
但是当从C#(linq sql)执行过程时,它会返回错误
All*_*sen 15
问题是您将动态SQL与非动态SQL混合在一起.
首先 - 当你将NULL放入@NotNeededWPRNs时它起作用的原因是因为当该变量为NULL时,你的@ProductsSQL变为NULL.
您需要做的是将@PropsIDs表作为非表变量以及临时表或物理表.或者您需要将所有内容包装在动态SQL中并执行它.
所以简单的方法是做这样的事情:
Declare @ProductsSQL nvarchar(max);
SET @ProductsSQL = '
DECLARE @PropIDs TABLE
(ID bigint)
Insert into @PropIDs (ID)
SELECT [WPRN] FROM [dbo].[Properties] WHERE(WPRN in (' + @NotNeededWPRNs + '))
SELECT p.WPRN AS ID,
p.Address AS Address,
p.Address AS Street
FROM [dbo].[Properties] AS p
WHERE
p.WPRN NOT IN( SELECT ID FROM @PropIDs)
'
Run Code Online (Sandbox Code Playgroud)
并执行它.或者如上所述 - 将@ProdIDs更改为临时表.(你在CREATE #ProdIds中接近的路线,但是你需要在sproc中的每个地方使用#ProdIDs而不是@ProdIDs).
您收到此错误的原因是表变量的范围仅限于一个批处理,因为sp_executesql它在自己的批处理中运行,它不知道您已在另一个批处理中声明它.
当你@NotNeededWPRNs是NULL因为连接NULL收益率NULL(除非另有设置),它可以工作,所以你只是执行:
exec sp_executesql null;
Run Code Online (Sandbox Code Playgroud)
我还要说,如果您使用的是SQL Server 2008或更高版本,请考虑使用表值参数而不是分隔的字符串列表.这是更安全,更高效,验证输入,如果我传递1); DROP TABLE dbo.Prioperties; --的@NotNeededWPRNs,你会发现自己没有一个属性表.
首先,您需要创建类型(我倾向于使用通用名称来实现可重用性):
CREATE TYPE dbo.IntegerList TABLE (Value INT);
Run Code Online (Sandbox Code Playgroud)
然后你可以将它添加到你的程序:
CREATE PROCEDURE [dbo].[GetNeededProperties]
@NotNeededWPRNs dbo.IntegerList READONLY,
@LastSynch DATETIME,
@TechCode VARCHAR(5)
AS
BEGIN
SELECT p.WPRN AS ID,
p.Address AS Address,
p.Address AS Street
FROM [dbo].[Properties] AS p
WHERE p.WPRN NOT IN (SELECT Value FROM @NotNeededWPRNs)
Run Code Online (Sandbox Code Playgroud)
在一个不相关的说明中,你应该尽可能避免使用文化敏感的日期格式,06/28/2013显然应该是6月28日,但是如果06/07/2013没有设置DATEFORMAT或语言你怎么知道这将是7月6日或6月7日?使用的最佳格式是yyyyMMdd,它永远不会模糊,甚至ISO标准格式yyyy-MM-dd也可以解释为yyyy-dd-MM在某些设置中.
将您的代码更改为:
Declare @ProductsSQL nvarchar(max);
SET @ProductsSQL = 'DECLARE @PropIDs TABLE
(ID bigint);
Insert into @PropIDs (ID)
SELECT [WPRN] FROM [dbo].[Properties] WHERE(WPRN in (' + @NotNeededWPRNs + '))'
exec sp_executesql @ProductsSQL
Run Code Online (Sandbox Code Playgroud)
在动态 SQL 之外声明的表变量将不可用于动态 SQL。