什么是最佳的MySQL语句来从同一个表中选择具有某些ID但不包含其他ID的行?

时间:2016-01-16 16:54:10

标签: mysql

我们需要从下表segments_id, em_id中选择mytable为5或8但不是1或7的所有segments_id。要在下面的评论后更清楚,结果将是一个包含segments_id, em_id所有em_id行的集合,其中segments_id的{​​{1}}为5或8但不是1或7.

 +-------------+-------+
 | segments_id | em_id |
 +-------------+-------+
 |    1        |   8   |
 |    1        |  17   |
 |    5        |   2   |
 |    5        |   4   |
 |    5        |   5   |
 |    5        |  16   |
 |    5        |  17   |
 |    7        |   4   |
 |    7        |   5   |
 |    7        |   8   |
 |    7        |  16   |
 |    8        |   4   |
 |    8        |   6   |
 |    8        |   8   |
 |    8        |  18   |
 |    18       |   6   |
 |    18       |  99   |
 +-------------+-------+

结果应为:

 +-------------+-------+
 | segments_id | em_id |
 +-------------+-------+
 |    5        |   2   |
 |    8        |   6   |
 |    8        |  16   |
 +-------------+-------+

我们需要避免使用IN子句,因为这可以扩展到数百万行。

我理解这将涉及自身和/或子查询的连接,但我没有看到它。我看过这篇文章Stackoverflow: Selecting rows from a table that have the same value for one field但看不到解决方案。

3 个答案:

答案 0 :(得分:1)

使用聚合:

SELECT segments_id,em_id   -- GROUP_CONCAT(segments_id) AS segments_ids
FROM mytable
GROUP BY em_id
HAVING SUM(segments_id IN (8,5)) > 0
   AND SUM(segments_id IN (1,7)) = 0;

SqlFiddleDemo

输出:

╔══════════════╦═══════╗
║ segments_id  ║ em_id ║
╠══════════════╬═══════╣
║           5  ║     2 ║
║           8  ║     6 ║
║           8  ║    18 ║
╚══════════════╩═══════╝

答案 1 :(得分:1)

不确定你在这里要求什么。您告诉我们您想要一个全部选择,但您发布的结果不会显示满足您条件的所有记录。如果你打算排除segment_id = 5或8而不是1或7的记录,请详细说明条件。

SELECT segments_id,em_id 
FROM mytable 
WHERE ( segments_id = 5 OR segments_id = 8 ) 
AND segments_id != 1 
AND segments_id != 7;

这会有效!

答案 2 :(得分:1)

您可以使用LEFT JOIN消除em_id segment_id为{1}}的所有OR 7:

SELECT m.segments_id, m.em_id
FROM myTable as m
LEFT JOIN (SELECT * FROM myTable WHERE (segments_id=1 OR segments_id=7)) as n
ON m.em_id=n.em_id
WHERE n.segments_id IS NULL
GROUP BY m.em_id;

请参阅SQLfiddle here

如果它是5和8你想保留并且所有其余部分都应该被删除,那么你可以调整你的WHERE条款之一:

SELECT m.segments_id, m.em_id
FROM myTable as m
LEFT JOIN (SELECT * FROM myTable WHERE NOT (segments_id=5 OR segments_id=8)) as n
ON m.em_id=n.em_id
WHERE n.segments_id IS NULL
GROUP BY m.em_id;

第二个查询的SQLfiddle是here

如果只想5和8你要保留,你想要消除1和7,你可以使用它(但在这种情况下,@ lad2025给出的答案可能是更好的选择):

SELECT m.segments_id, m.em_id
FROM myTable as m
LEFT JOIN (SELECT * FROM myTable WHERE (segments_id=1 OR segments_id=7)) as n
ON m.em_id=n.em_id
WHERE (n.segments_id IS NULL AND (m.segments_id=5 OR m.segments_id=8))
GROUP BY m.em_id;

PLS。使用改进的集合here检查第三个SQLfiddle。