英文:
Select statement to do a left join between tables, while filtering the results based on specific values in the right table?
问题
这是你想要的 SQL 查询:
SELECT T1.ccID, T0.objID, T0.objName, T1.Color
FROM tblObject T0
LEFT JOIN tblColorCombination T1 ON T1.objID = T0.objID AND T1.Color IN ('Red', 'Blue')
希望对你有所帮助。
英文:
I need an SQL Server Select statement to perform a left join between tables that filters the results based on specific values in the right table.
Here is an example:
The left table will hold color values. The right table will hold rows for the color combination of the left table.
tblObject /*this is the left table */
objID objName
1 Violet
2 Rose
3 Grass
4 Sky
5 Magenta
tblColorCombination /*this is the right table */
ccID objID Color
1 1 Red
2 1 Blue
3 2 Red
4 3 Green
5 4 Blue
6 5 Blue
7 5 Red
The select should return the tblObject rows with 'Red', 'Blue' combination in the tblColorCombination
ccID obj ID objName Color
1 1 Violet Red
2 1 Violet Blue
6 5 Magenta Blue
7 5 Magenta Red
I tried this query but failed to filter out the Rose and sky in the right table
SELECT T1.ccID, T0.objID, T0.objName, T1.Color
FROM tblObject T0
LEFT JOIN tblColorCombination T1 ON T1.objID = T0.objID AND T1.Color IN ('Red', 'Blue')
答案1
得分: 2
如果我理解正确,您希望仅获取那些同时出现红色和蓝色的行,并且还要筛选掉那些同时出现其他颜色的行。可以使用类似以下的CTE来实现:
WITH redBlue AS
(
SELECT
tcc.ccID, tbo.objID, tbo.objName, tcc.color,
COUNT(CASE WHEN tcc.color = 'Red' THEN 1 END)
OVER(PARTITION BY tcc.objID) AS countRed,
COUNT(CASE WHEN tcc.color = 'Blue' THEN 1 END)
OVER(PARTITION BY tcc.objID) AS countBlue
FROM tblObject tbo
INNER JOIN tblColorCombination tcc
ON tbo.objID = tcc.objID
WHERE
NOT EXISTS (SELECT 1 FROM tblColorCombination
WHERE objID = tcc.objID
AND color NOT IN ('Red','Blue'))
)
SELECT ccId, objId, objName, color
FROM redBlue WHERE LEAST(countRed, countBlue) > 0;
NOT EXISTS
部分会筛选掉具有其他颜色的条目。计数条件确保仅获取那些至少同时具有这两种颜色的条目。
这是CTE查询创建的结果:
ccID | objID | objName | Color | countRed | countBlue |
---|---|---|---|---|---|
1 | 1 | Violet | Red | 1 | 1 |
2 | 1 | Violet | Blue | 1 | 1 |
3 | 2 | Rose | Red | 1 | 0 |
5 | 4 | Sky | Blue | 0 | 1 |
6 | 5 | Magenta | Blue | 1 | 1 |
7 | 5 | Magenta | Red | 1 | 1 |
对于您的示例数据,完整的查询生成以下结果:
ccID | objID | objName | Color |
---|---|---|---|
1 | 1 | Violet | Red |
2 | 1 | Violet | Blue |
6 | 5 | Magenta | Blue |
7 | 5 | Magenta | Red |
在这里尝试:db<>fiddle
如果打算检查出现的次数而不仅仅是两者都大于0,则可以将最后部分的 LEAST(countRed, countBlue) > 0
更改为类似于 countRed = 1 AND countBlue = 1
。
注意:根据您的确切要求和数据,CTE查询的 WHERE
子句是不是必需的,即使没有这部分,结果仍然相同。查看示例fiddle,它展示了这部分何时有差异和何时没有差异。您可以根据确切的需求决定是否需要它。
英文:
If I understand correctly, you want to get those rows only which occur with both colors, Red
and blue
and additionaly filter out such rows that occur with other colors, too. This can for example be done using a CTE like this:
WITH redBlue AS
(SELECT
tcc.ccID, tbo.objID, tbo.objName, tcc.color,
COUNT(CASE WHEN tcc.color = 'Red' THEN 1 END)
OVER(PARTITION BY tcc.objID) AS countRed,
COUNT(CASE WHEN tcc.color = 'Blue' THEN 1 END)
OVER(PARTITION BY tcc.objID) AS countBlue
FROM tblObject tbo
INNER JOIN tblColorCombination tcc
ON tbo.objID = tcc.objID
WHERE
NOT EXISTS (SELECT 1 FROM tblColorCombination
WHERE objID = tcc.objID
AND color NOT IN ('Red','Blue')))
SELECT ccId, objId, objName, color
FROM redBlue WHERE LEAST(countRed, countBlue) > 0;
The NOT EXISTS
part filters out entries having other colors. The count conditions make sure to only get those entries which have both colors at least once.
This is the result created by the CTE query:
ccID | obj ID | objName | Color | countRed | countBlue |
---|---|---|---|---|---|
1 | 1 | Violet | Red | 1 | 1 |
2 | 1 | Violet | Blue | 1 | 1 |
3 | 2 | Rose | Red | 1 | 0 |
5 | 4 | Sky | Blue | 0 | 1 |
6 | 5 | Magenta | Blue | 1 | 1 |
7 | 5 | Magenta | Red | 1 | 1 |
The complete query produces following result for your sample data:
ccID | obj ID | objName | Color |
---|---|---|---|
1 | 1 | Violet | Red |
2 | 1 | Violet | Blue |
6 | 5 | Magenta | Blue |
7 | 5 | Magenta | Red |
Try out here: db<>fiddle
If it is intended to check an exact number of occurences rather than just both should be > 0, then the last part LEAST(countRed, countBlue) > 0
can be changed to something like countRed = 1 AND countBlue = 1
.
Note: Depending on your exact requirements and data, the WHERE
clause of the CTE query is not required and the result will still be the same without that part. See the sample fiddle. It show when this makes a difference and when not. It's up to you what exactly you need.
答案2
得分: 2
请注意,LEFT JOIN
(以及RIGHT JOIN
)在SQL中有特定的含义:它们都指的是OUTER JOIN
,并不是你在这里想要的内容。
从你的问题中不太清楚你是要从tblObject中获取既有红色又有蓝色且没有其他颜色的记录,还是要获取至少有红色和蓝色的所有记录。如果你想要后者,那么以下方法相对简单易懂:
WITH cte AS
(
SELECT ccRed.ccID AS redID, ccBlue.ccID as blueId, o.objName,
ccRed.Color as redColor, ccBlue.Color as blueColor
FROM tblObject o
INNER JOIN tblColorCombination ccRed ON ccRed.objID = o.objID AND ccRed.Color = 'Red'
INNER JOIN tblColorCombination ccBlue ON ccBlue.objID = o.objID AND ccBlue.Color = 'Blue'
)
SELECT redID as ccID, objName, redColor as Color
FROM cte
UNION
SELECT blueID as ccID, objName, blueColor as Color
FROM cte
ORDER BY 1;
简要解释一下,这个公共表达式(CTE)通过两个内连接(inner joins)到同一张表,每个连接都有不同的额外特征 - Color,来找到同时存在两种颜色的记录。只有具有红色和蓝色的记录才能满足这两次连接。
然后,我们使用SELECT ... UNION SELECT ...
来将CTE中的组合值拆分为单独的记录。
英文:
Please note that LEFT JOIN
(and RIGHT JOIN
for that matter) have specific meanings in SQL: they both refer to an OUTER JOIN
and is not what you want here.
It was not clear from your question, if you are seeking those records from tblObject that have both red and blue and no other, or all records that have at least red and blue. If you want the latter, then the following approach is relatively simple to understand:
WITH cte AS
(
SELECT ccRed.ccID AS redID, ccBlue.ccID as blueId, o.objName,
ccRed.Color as redColor, ccBlue.Color as blueColor
FROM tblObject o
INNER JOIN tblColorCombination ccRed ON ccRed.objID = o.objID AND ccRed.Color = 'Red'
INNER JOIN tblColorCombination ccBlue ON ccBlue.objID = o.objID AND ccBlue.Color = 'Blue'
)
SELECT redID as ccID, objName, redColor as Color
FROM cte
UNION
SELECT blueID as ccID, objName, blueColor as Color
FROM cte
ORDER BY 1;
By way of explanation, the CTE finds records that exist with both colours by means of two inner joins to the same table, each with a different extra characteristic - Color. The only records with red and blue are the only ones to meet the double join.
We then do a SELECT ... UNION SELECT ...
to split the combined values in the CTE back to separate records.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论