【问题标题】:SQL joining the same table multiple times on the same column with differing restrictionsSQL 在同一列上以不同的限制多次连接同一个表
【发布时间】:2020-10-22 11:34:31
【问题描述】:

我有两张桌子

| Categories         |      | Products               |
:--------------------:      :------------------------:
| Id int             |      | Id int                 |
| Name nvarchar(max) |      | Name vnarchar(max)     |
                            | ApprovedForRelease bit |
                            | ApprovedForRecall bit  |
                            | CategoryId int         |

我需要获取所有类别的产品approvedForRealease、notapprovedForRelease、ApprovedForRecall 和 ApprovedForRecall 的计数

类似的东西

| Category | #Released | #NotReleased | #Recalled | #NotRecalled |
:----------------------------------------------------------------:
| Arts     | 5         | 1            | 3         | 4            |
| Crafts   | 13        | 7            | 7         | 8            |

我的查询如下所示

SELECT

Category = cat.Name,
#Releases = Count(released.Id),
#NotReleased = Count(notReleased.Id),
#Recalled = Count(recalled.Id),
#NotRecalled = Count(notRecalled.Id),

-- Selected product ids
releasedIds = STRING_AGG(released.Id, ', '),
notReleasedIds = STRING_AGG(notReleased.Id, ', '),
recalledIds = STRING_AGG(recalled.Id, ', '),
notRecalledIds = STRING_AGG(notRecalled.Id, ', ')

FROM
Categories as cat

LEFT JOIN Products as released ON released.CategoryId = cat.Id AND released.ApprovedForRelease = 1
LEFT JOIN Products as notReleased ON released.CategoryId = cat.Id AND notReleased.ApprovedForRelease = 0
LEFT JOIN Products as recalled ON released.CategoryId = cat.Id AND recalled.ApprovedForRecall = 1
LEFT JOIN Products as notRecalled ON released.CategoryId = cat.Id AND notRecalled.ApprovedForRecall = 0

GROUP BY
cat.Name

我注意到产品计数有点过多,所以我添加了 Selected product ids 列来检查实际连接的内容,并注意到连接的表多次具有相同的行

我会得到的结果示例:

| Category | #Released | #NotReleased | #Recalled | #NotRecalled | releasedIds | notReleasedIds | recalledIds | notRecalledIds |
:------------------------------------------------------------------------------------------------------------------------------:
| Arts     | 3         | 3            | 3         | 3            | 1, 2, 3     | 4, 5, 6        | 10, 10, 10  | 6, 6, 6        |
| Crafts   | 2         | 2            | 4         | 2            | 25, 26      | 96, 98         | 7, 8, 7, 8  | 9, 9           |

有人可以向我解释发生了什么以及为什么有些产品会多次加入吗?

有没有办法在不使用子查询的情况下达到我想要的结果:

SELECT
Category = cat.Name,
#Releases = (SELECT COUNT (Id) FROM PRODUCTS WHERE CategoryId = cat.Id AND ApprovedForRelease = 1),
#NotReleased = (SELECT COUNT (Id) FROM PRODUCTS WHERE CategoryId = cat.Id AND ApprovedForRelease = 0),
#Recalled = (SELECT COUNT (Id) FROM PRODUCTS WHERE CategoryId = cat.Id AND ApprovedForRecall= 1),
#NotRecalled = (SELECT COUNT (Id) FROM PRODUCTS WHERE CategoryId = cat.Id AND ApprovedForRecall= 0)
FROM Categories

【问题讨论】:

    标签: sql sql-server join select


    【解决方案1】:

    使用条件聚合:

    SELECT c.name as category,
           SUM(CASE WHEN p.ApprovedForRelease = 1 THEN 1 ELSE 0 END) as released,
           SUM(CASE WHEN p.ApprovedForRelease = 0 THEN 1 ELSE 0 END) as not_released,
           SUM(CASE WHEN p.ApprovedForRecall = 1 THEN 1 ELSE 0 END) as recalled,
           SUM(CASE WHEN p.ApprovedForRecall = 0 THEN 1 ELSE 0 END) as not_recalled
    FROM Categories c LEFT JOIN
         Products p
         ON p.CategoryId = cat.Id 
     released.ApprovedForRelease = 1
    GROUP BY c.name;
    

    【讨论】:

    • 好吧,谢谢。如果您有任何想法,我仍然很想知道为什么我的方法会产生如此奇怪的结果。
    • @Tomas 。 . .是的。当一组中有不止一行时,您将在joins 中获得笛卡尔积。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多