简体   繁体   English

SQL 在同一列上多次加入同一个表,但有不同的限制

[英]SQL joining the same table multiple times on the same column with differing restrictions

I have 2 tables我有2张桌子

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

I need to get the counts for products approvedForRealease, not approvedForRelease, ApprovedForRecall and not ApprovedForRecall for all Categories我需要获取所有类别的 ApprovedForRealease、notapprovedForRelease、ApprovedForRecall 和 not ApprovedForRecall 的产品计数

Something like this像这样的东西

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

My query looks like this我的查询看起来像这样

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

I noticed that product counts are a little too much, so I added the Selected product ids columns to check what actually gets joined and noticed that the joined tables have the same rows multiple times我注意到产品数量有点太多,所以我添加了 Selected product ids 列来检查实际连接的内容,并注意到连接的表多次具有相同的行

Example of the result I would get:我会得到的结果示例:

| 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           |

Could somebody explain to me what's happening and why do some products get joined multiple times?有人可以向我解释发生了什么以及为什么某些产品会多次加入吗?

And Is there a way to achieve my desired result without using subqueries like:有没有办法在不使用子查询的情况下实现我想要的结果,例如:

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

Use conditional aggregation:使用条件聚合:

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM