2017-06-06 55 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

相關問題