1

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

它返回并非所有强制备件都已更改的所有维修 ID,即至少缺少一个零件。

请注意,备件的数量将来可能不仅名称会发生​​变化。是否可以不使用带有动态 SQL 的存储过程?如果不是,这个 SP 会是什么样子?

编辑:请注意,我不需要知道如何将列表/数组作为参数传递,这是在 SO 上被问到的无数时间。我也已经有了一个Split表值函数。我只是想知道如何重写查询以能够加入(或其他)强制性部分列表,以便找到至少缺少一个部分的所有记录。那么是否可以使用 varchar 参数'1264-3212,1254-2975'而不是列表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)在这里使用。

4

3 回答 3

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
    ) 
于 2012-05-11T10:27:32.497 回答
1

假设存在(或将存在)强制性备件的表或视图,存在的列表可以替换为 SparePartName 上的 tabDataDetail / tabSparePart 对的左连接;不匹配使用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 子句中。

于 2012-05-11T10:57:28.883 回答
0

使用表变量并加入。

于 2012-05-11T10:27:37.347 回答