2017-06-06 53 views
1

使用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中尝试这样做?我可以写一个脚本来做,但我希望不必走这条路。

任何意见,将不胜感激。

+0

这是为了在其他DBMS非常简单,你'd只需用'ROW_NUMBER'对您的记录进行排名,并且在MySQL中非常困难(或至少笨拙)。我想这是人们从MySQL切换到MariaDB的原因之一。也许你也有选择? –

回答

1

我相信这样的事情应该这样做:

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 
+1

原始的sql不正确,并且已被更正。这给出了你正在寻找的结果。 – John

+1

完美的作品。任何你为什么使用ifnull(max(active_records.id)...为ID字段,然后if(max(active_records.id)为null ...为ACTIVE字段?你可以交换使用吗? – dinologic

+0

ifnull和如果语法略有不同,在两个地方都可以使用其中的一种,我写这些的方式似乎对我最有意义。 – John

0

你可以试试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 
) 
+0

反馈:这似乎可行,但在约2300条记录上运行需要将近30秒。可能是一个索引问题,但约翰的解决方案几乎是即时运行的。而且,与John的解决方案相比,您的回报少了4条。我没有花时间找出缺失的记录。 – dinologic

相关问题