左连接两个表并根据右表中特定值筛选结果的SELECT语句?

huangapple go评论79阅读模式
英文:

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 = &#39;Red&#39; THEN 1 END) 
  OVER(PARTITION BY tcc.objID) AS countRed,
COUNT(CASE WHEN tcc.color = &#39;Blue&#39; 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 (&#39;Red&#39;,&#39;Blue&#39;)))
SELECT ccId, objId, objName, color 
  FROM redBlue WHERE LEAST(countRed, countBlue) &gt; 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) &gt; 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 = &#39;Red&#39;
	INNER JOIN tblColorCombination ccBlue ON ccBlue.objID = o.objID AND ccBlue.Color = &#39;Blue&#39;
)
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.

huangapple
  • 本文由 发表于 2023年7月3日 12:55:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76601926.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定