"必须在存储过程中声明表变量"@name""

Tom*_*Tom 13 sql sql-server

我有一个返回错误的过程:

必须声明表变量"@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).


Gar*_*thD 6

您收到此错误的原因是表变量的范围仅限于一个批处理,因为sp_executesql它在自己的批处理中运行,它不知道您已在另一个批处理中声明它.

当你@NotNeededWPRNsNULL因为连接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在某些设置中.


Raj*_*Raj 5

将您的代码更改为:

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。