Mysql从具有三个条件之一的组中选择一条记录
使用MySQL。我需要提取根据以下条件每STOREID + profitCenter的组中的一个记录:Mysql从具有三个条件之一的组中选择一条记录
1)如果组具有单一活性记录(活性= 1),选择与记录
2)如基团具有不活动记录选择最近(MAX(ID))
3)如果组中有多个活动记录,选择最近的活动记录
样品表: (空行增加了清晰度)
ID | storeID | profitCenter | active
--------------------------------------
1 | X | 1 | 1
2 | X | 1 | 0
3 | X | 1 | 0
4 | X | 2 | 0
5 | X | 2 | 1
6 | X | 3 | 0
7 | X | 3 | 0
8 | X | 3 | 0
9 | X | 4 | 1
10 | X | 4 | 1
11 | X | 4 | 0
12 | X | 5 | 1
13 | X | 6 | 0
期望的结果:
ID | storeID | profitCenter | active
------------------------------------------
1 | X | 1 | 1
5 | X | 2 | 1
8 | X | 3 | 0
10 | X | 4 | 1
12 | X | 5 | 1
13 | X | 6 | 0
单查询将是巨大的,但我想我需要做一个存储过程,由于其复杂性。我需要将记录写入新表,以便在连接等中使用它。到目前为止,所有我真的得是......
...一个简单的查询拉“单”的记录,像这样....
SELECT * FROM table GROUP BY storeID, profitCenter HAVING count(*) = 1 AND active = 1
UNION
SELECT * FROM table GROUP BY storeID, profitCenter HAVING count(*) = 1 AND active = 0
...这将产生...
ID | storeID | profitCenter | active
------------------------------------------
12 | X | 5 | 1
13 | X | 6 | 0
然后,我可以做...
SELECT sum(active),tmult.* FROM
(SELECT t.* FROM t LEFT JOIN
(SELECT t.* FROM t GROUP BY storeID, profitCenter HAVING count(*) = 1 AND active = 1
UNION
SELECT t.* FROM t GROUP BY storeID, profitCenter HAVING count(*) = 1 AND active = 0) tsing
ON t.id = tsing.id
WHERE tsing.id IS NULL) tmult
GROUP BY storeid, profitCenter
HAVING sum(active)=1;
...这给活动记录对于只有一个活动记录各组:
ID | storeID | profitCenter | active
--------------------------------------
1 | X | 1 | 1
5 | X | 2 | 1
这是一组没有活动记录或多个活动记录,我甚至不能开始弄清楚。
我采取了正确的做法吗?我是否应该在SQL中尝试这样做?我可以写一个脚本来做,但我希望不必走这条路。
任何意见,将不胜感激。
我相信这样的事情应该这样做:
select
ifnull(max(active_records.id), max(all_records.id)) id,
all_records.store_id,
all_records.profit_center,
if(max(active_records.id) is null, 0, 1) active
from
store all_records
left outer join store active_records on all_records.id = active_records.id and active_records.active = 1
group by
all_records.store_id,
all_records.profit_center
;
与DDL和插入一个完整的示例如下所示:
create table store (
id int,
store_id varchar(64),
profit_center int,
active bit
);
insert into store values (1 , 'X' , 1 , 1);
insert into store values (2 , 'X' , 1 , 0);
insert into store values (3 , 'X' , 1 , 0);
insert into store values (4 , 'X' , 2 , 0);
insert into store values (5 , 'X' , 2 , 1);
insert into store values (6 , 'X' , 3 , 0);
insert into store values (7 , 'X' , 3 , 0);
insert into store values (8 , 'X' , 3 , 0);
insert into store values (9 , 'X' , 4 , 1);
insert into store values (10 , 'X' , 4 , 1);
insert into store values (11 , 'X' , 4 , 0);
insert into store values (12 , 'X' , 5 , 1);
insert into store values (13 , 'X' , 6 , 0);
select
ifnull(max(active_records.id), max(all_records.id)) id,
all_records.store_id,
all_records.profit_center,
if(max(active_records.id) is null, 0, 1) active
from
store all_records
left outer join store active_records on all_records.id = active_records.id and active_records.active = 1
group by
all_records.store_id,
all_records.profit_center
;
+ ------- + ------------- + ------------------ + ----------- +
| id | store_id | profit_center | active |
+ ------- + ------------- + ------------------ + ----------- +
| 1 | X | 1 | 1 |
| 5 | X | 2 | 1 |
| 8 | X | 3 | 0 |
| 10 | X | 4 | 1 |
| 12 | X | 5 | 1 |
| 13 | X | 6 | 0 |
+ ------- + ------------- + ------------------ + ----------- +
6 rows
你可以试试union all
。
SELECT *
FROM TABLE
WHERE (storeID, profitCenter, Id) IN (
SELECT storeID, profitCenter, MAX(case when active=1 then id end) as maxid
FROM table
GROUP BY storeID, profitCenter
HAVING SUM(active) >= 1
UNION ALL
SELECT storeID, profitCenter, MAX(id)
FROM table
GROUP BY storeID, profitCenter
HAVING SUM(active) = 0
)
反馈:这似乎可行,但在约2300条记录上运行需要将近30秒。可能是一个索引问题,但约翰的解决方案几乎是即时运行的。而且,与John的解决方案相比,您的回报少了4条。我没有花时间找出缺失的记录。 – dinologic
这是为了在其他DBMS非常简单,你'd只需用'ROW_NUMBER'对您的记录进行排名,并且在MySQL中非常困难(或至少笨拙)。我想这是人们从MySQL切换到MariaDB的原因之一。也许你也有选择? –