如何在NOT EXISTS的SQL查询中使用参数?

时间:2012-05-11 10:00:23

标签: tsql sql-server-2005 parameters

如何更改以下查询,以便我能够参数化SparePartNames

它返回所有维修ID,而不是所有强制性备件都被更改,换句话说,至少有一部分缺失。

请注意,备件的数量将来可能会更改名称。没有使用动态SQL的存储过程是否可行?如果没有,这个SP怎么样?

编辑:请注意,我不需要知道如何将列表/数组作为参数传递,这在SO上被问到了无数的时间。我还有一个Split表值函数。我只是想知道如何重写查询以便能够加入(或其他)强制部分列表,这样我就能找到至少有一部分缺失的所有记录。那么可以使用像'1264-3212,1254-2975'这样的varchar参数而不是NOT EXISTS列表吗?如果首先不清楚,请注意混淆。

SELECT  d.idData
FROM    tabData d
INNER JOIN modModel AS m ON d.fiModel = m.idModel 
WHERE  (m.ModelName = 'MT27I') 
AND (d.fiMaxServiceLevel >= 2) 
AND (d.Manufacture_Date < '20120511') 
AND (NOT EXISTS
      (SELECT NULL
        FROM  tabDataDetail AS td 
        INNER JOIN tabSparePart AS sp ON sp.idSparePart = td.fiSparePart
        WHERE (td.fiData = d.idData) 
        AND (sp.SparePartName = '1264-3212'))
    OR (NOT EXISTS
      (SELECT NULL
        FROM  tabDataDetail AS td 
        INNER JOIN tabSparePart AS sp ON sp.idSparePart = td.fiSparePart
        WHERE (td.fiData = d.idData) 
        AND (sp.SparePartName = '1254-2975'))
    )
)

很遗憾,我不知道如何在这里使用sp.SparePartName IN/NOT IN(@sparePartNames)

3 个答案:

答案 0 :(得分:2)

一种方法是创建一个分割分隔字符串的函数:

CREATE FUNCTION [dbo].[Split] 
(
    @Delimiter char(1), 
    @StringToSplit varchar(512)
)
RETURNS table
AS
RETURN 
(
    WITH Pieces(pieceNumber, startIndex, delimiterIndex) 
    AS 
    (
        SELECT 1, 1, CHARINDEX(@Delimiter, @StringToSplit)
        UNION ALL
        SELECT pieceNumber + 1, delimiterIndex + 1, CHARINDEX(@Delimiter, @StringToSplit, delimiterIndex + 1)
        FROM Pieces
        WHERE delimiterIndex > 0
    )
    SELECT 
        SUBSTRING(@StringToSplit, startIndex, CASE WHEN delimiterIndex > 0 THEN delimiterIndex - startIndex ELSE 512 END) AS Value
    FROM Pieces
)

使用备件名称填充表变量:

DECLARE @SpareParts TABLE
(
    SparePartName varchar(50) PRIMARY KEY CLUSTERED
);

INSERT INTO @SpareParts
SELECT Value FROM dbo.Split(',', '1264-3212,1254-2975');

然后加入表变量:

SELECT  d.idData
FROM    tabData d
INNER JOIN modModel AS m ON d.fiModel = m.idModel 
WHERE  (m.ModelName = 'MT27I') 
AND (d.fiMaxServiceLevel >= 2) 
AND (d.Manufacture_Date < '20120511') 
AND EXISTS (
        SELECT 1
        FROM  tabDataDetail AS td 
        INNER JOIN tabSparePart AS sp ON sp.idSparePart = td.fiSparePart
        LEFT JOIN @SpareParts AS s ON s.SparePartName = sp.SparePartName
        WHERE td.fiData = d.idData
            AND s.SparePartName IS NULL
    ) 

答案 1 :(得分:1)

假设存在(或将来)强制备件的表或视图,则可以使用SparePartName上的tabDataDetail / tabSparePart对的左连接替换exists的列表;使用td.fiSparePart is null报告不匹配。

; with mandatorySpareParts (SparePartName) as (
  select '1264-3212'
  union all
  select '1254-2975'
)
SELECT  d.idData
FROM    tabData d
INNER JOIN modModel AS m ON d.fiModel = m.idModel 
WHERE  (m.ModelName = 'MT27I') 
AND (d.fiMaxServiceLevel >= 2) 
AND (d.Manufacture_Date < '20120511') 
AND exists
(
  SELECT null
    from mandatorySpareParts msp
    left join ( tabDataDetail AS td 
                INNER JOIN tabSparePart AS sp 
                   ON sp.idSparePart = td.fiSparePart 
                  AND td.fiData = d.idData
              )
      ON msp.SparePartName = sp.SparePartName
   WHERE td.fiSparePart is null
)

部件名称应替换为其ID,这将简化左连接并加快查询速度。

编辑:我错误地在where子句中过滤了td,这使左连接无效。它现在属于它所属的ON子句。

答案 2 :(得分:0)

使用表变量并加入其中。