简体   繁体   English

在 MySQL 中,根据条件从多行中选择一行,否则选择第一行并排除其余行

[英]In MySQL, select one row out of multiple rows based on condition, otherwise select first row and exclude the rest

I am interested in MySQL of writing a query that looks through a list consisting of IDs and locations.我对编写查询的 MySQL 感兴趣,该查询查看由 ID 和位置组成的列表。 Each ID represents a unique person who can be tied to multiple locations.每个 ID 代表一个独特的人,可以绑定到多个位置。

I have the following table to simplify things:我有下表来简化事情:

+----+----------+
| ID | Location |
+----+----------+
|  1 | Bldg#1   |
|  1 | Bldg#2   |
|  2 | Bldg#3   |
+----+----------+

I am looking to deduplicate the above table to only end up with ONE row per ID, but I would also like to add a conditional that preferences Bldg#1 for any given ID.我希望对上表进行重复数据删除,以便每个 ID 只得到一行,但我还想为任何给定 ID 添加一个偏好 Bldg#1 的条件。 In other words, given a table of multiple rows with potentially the same ID and multiple locations, I would like to write a query that outputs 1 row per ID, and if any of the rows associated with that ID also have a location of Bldg#1, I want to keep that row and drop the rest.换句话说,给定一个包含可能具有相同 ID 和多个位置的多行表,我想编写一个查询,为每个 ID 输出 1 行,并且如果与该 ID 关联的任何行也有 Bldg# 的位置1,我想保留那一行并放弃其余的。 Otherwise, I just want to keep one arbitrary location row for that ID.否则,我只想为该 ID 保留一个任意位置行。

For the above table, I would like the following as output:对于上表,我希望以下内容作为输出:

+----+----------+
| ID | Location |
+----+----------+
|  1 | Bldg#1   |
|  2 | Bldg#3   |
+----+----------+

You can group by id and use conditional aggregation:您可以按 id 分组并使用条件聚合:

select id,
  case 
    when max(location = 'Bldg#1') then 'Bldg#1' 
    else any_value(location)
  end location 
from tablename
group by id

See the demo .请参阅演示
Results:结果:

| id  | location |
| --- | -------- |
| 1   | Bldg#1   |
| 2   | Bldg#3   |

You can use row_number() with a case expression:您可以将row_number()case表达式一起使用:

select id, location
from (select t.*,
             row_number() over (partition by id
                                order by (case location when 'Bldg#1' then 1 when 'Bldg#2' then 2 when 'Bldg#3' then 3 else 4 end)
                               ) as seqnum
      from t
     ) t
where seqnum = 1;

This does not assume any particular ordering -- such as alphabetical ordering.这不假定任何特定的顺序——例如字母顺序。

Is this you looking for?这是你要找的吗?

Exmaple:例子:

在此处输入图片说明

Query:询问:

DROP TABLE IF EXISTS #TEST
CREATE TABLE #TEST (ID INT, Location NVARCHAR(10))

INSERT INTO #TEST 
SELECT 1,'Bldg#1'
UNION
SELECT 1,'Bldg#2'
UNION
SELECT 2,'Bldg#3'

SELECT ID,Location FROM (
SELECT ID,Location, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ID) AS RNM
FROM #TEST) T
WHERE RNM = 1

inner query will make sure the location is in order so that Bldg#1 is always the first for each id, so then the outer group by will pick the first record内部查询将确保位置有序,以便 Bldg#1 始终是每个 id 的第一个,因此外部 group by 将选择第一条记录

SELECT * FROM 
(
    SELECT id, location
    FROM location
    ORDER BY id, location ASC
)a 
GROUP BY id

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

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