查询以获取不在列表中的项目

时间:2019-10-23 06:30:09

标签: sql sql-server

我有一个表'tbl_Items',下面是列

    [Id] [int] NULL,
    [ItemNo] [varchar](50) NULL,
    [TotalPieces] [int] NULL

和另一个具有以下列的表'tbl_ItemPieces'

    [Id] [int] NULL,
    [ItemId] [int] NULL,
    [PieceNo] [int] NULL

样本值如下:

tbl_Items

Id  ItemNo  TotalPieces
1   1001    5
2   1002    3
3   1003    4

tbl_ItemPieces

Id  ItemId  PieceNo
1   1       1
2   1       2
3   2       1
4   2       3
5   3       3
6   3       4

我使用以下查询来获取可用件数和总件数以及可用件数作为逗号分隔的字符串。

    select 
        a.ItemNo, COUNT(b.PieceNo) ActualPieces, a.TotalPieces,    

        STUFF((SELECT ', ' + CAST( PieceNo as varchar(50))
        FROM tbl_ItemPieces b 
        WHERE b.itemId = a.Id
        FOR XML PATH('')), 1, 2, '')    

    from tbl_Items a
    inner join tbl_ItemPieces b
    on a.Id = b.itemId
    group by a.ItemNo, a.TotalPieces, a.Id

结果低于

ItemNo  ActualPieces    TotalPieces AvailablePieces
1001    2                  5            1, 2
1002    2                  3            1, 3
1003    2                  4            3, 4

我希望将另一列作为逗号分隔的字符串,其中包含不在表中的件号,例如,如果总数为5,且包含的件数为1,3,则此列值为'2,4,5'

预期结果

ItemNo  ActualPieces    TotalPieces  AvailablePieces NotAvailablePieces
1001    2               5            1, 2            3,4,5
1002    2               3            1, 3            2
1003    2               4            3, 4            1,2

2 个答案:

答案 0 :(得分:2)

下面的解决方案使用recursive ctecte_AllPieceNo)生成每个项目可能的PieceNo的列表

从那里开始,只需使用它并检查NOT EXISTS()中的tbl_ItemPieces

; with
cte_AllPieceNo as                 -- Added this
(
    select  Id, TotalPieces, PieceNo = 1
    from    tbl_Items
    union all
    select  Id, TotalPieces, PieceNo = PieceNo + 1
    from    cte_AllPieceNo
    where   PieceNo < TotalPieces
)
SELECT   
    a.ItemNo, 
    COUNT(b.PieceNo) ActualPieces, 
    a.TotalPieces,
    STUFF(( SELECT  ', ' + CAST( PieceNo as varchar(50) )
            FROM    tbl_ItemPieces b 
            WHERE   b.ItemId = a.Id
            FOR XML PATH('')), 1, 2, '') as AvailablePieces,
    STUFF(( SELECT  ', ' + CAST( c.PieceNo as varchar(50) ) -- added this
            FROM    cte_AllPieceNo c
            WHERE   c.Id    = a.Id
            AND     NOT EXISTS
                    (
                        SELECT  *
                        FROM    tbl_ItemPieces d
                        WHERE   d.ItemId    = c.Id 
                        AND     d.PieceNo   = c.PieceNo
                    )
            FOR XML PATH('')),1,2, '') as NotAvailablePieces
FROM    tbl_Items a
        INNER JOIN tbl_ItemPieces b on a.Id = b.ItemId
GROUP BY a.ItemNo, 
         a.TotalPieces, 
         a.Id

如果您有tally table,则可以用它代替recursive cte

这是使用提示表的代码部分。

cte_AllPieceNo as
(
    select  Id, PieceNo = n
    from    tbl_Items
            cross join tally
    where   n >= 1
    and     n <= TotalPieces
)

答案 1 :(得分:2)

使用public function setCoefficient(float $coefficient): self { $this->coefficient = (float) $coefficient; return $this; } public function getCoefficient(): float { return $this->coefficient; } 实现此目的的唯一方法。

首先,是使用recursive query生成那些PieceNo,然后将cte的结果返回到您的原始查询,其中不包括join

PieceNo
相关问题