2016-03-08 64 views
1

假設有以下行合併按照順序多行

| Id | MachineName | WorkerName | MachineState | 
|----------------------------------------------| 
| 1 | Alpha  | Young  | RUNNING  | 
| 1 | Beta  |   | STOPPED  | 
| 1 | Gamma  | Foo  | READY  | 
| 1 | Zeta  | Zatta  |    | 
| 2 | Guu   | Niim  | RUNNING  | 
| 2 | Yuu   | Jaam  | STOPPED  | 
| 2 | Nuu   |   | READY  | 
| 2 | Faah  | Siim  |    | 
| 3 | Iem   |   | RUNNING  | 
| 3 | Nyt   | Fish  | READY  | 
| 3 | Qwe   | Siim  |    | 

我們要按照下面的優先級合併這些行:

已停止>運行> READY>(null或空)

如果一行有最大優先級的值,那麼應該使用該行的值(僅當它不爲空時)。如果它爲空,則應使用來自任何其他行的值。該行應由ID進行分組

對於上面輸入正確的輸出是:

| Id | MachineName | WorkerName | MachineState | 
|----------------------------------------------| 
| 1 | Beta  | Foo  | STOPPED  | 
| 2 | Yuu   | Jaam  | STOPPED  | 
| 3 | Iem   | Fish  | RUNNING  | 

這將是一個很好的SQL查詢來做到這一點?我嘗試使用連接,但它沒有解決。

+0

你能告訴什麼是你的查詢? –

+0

如果/當存在多個具有最大'(Id,MachineState)'組合的記錄時,您希望在結果集中包含哪條記錄? – eggyal

+0

@eggyal永遠不會有這樣的情況。 –

回答

1

你可以認爲這是按組最大的問題的情況下,只要你能得到合適的順序在你MachineState列e.g。通過使用CASE表達:

SELECT a.Id, 
     COALESCE(a.MachineName, t.MachineName) MachineName, 
     COALESCE(a.WorkerName , t.WorkerName) WorkerName, 
     a.MachineState 
FROM  myTable a JOIN (
      SELECT Id, 
        MIN(MachineName) AS MachineName, 
        MIN(WorkerName) AS WorkerName, 
        MAX(CASE MachineState 
         WHEN 'READY' THEN 1 
         WHEN 'RUNNING' THEN 2 
         WHEN 'STOPPED' THEN 3 
        END) AS MachineState 
      FROM  myTable 
      GROUP BY Id 
     ) t ON t.Id = a.Id AND t.MachineState = CASE a.MachineState 
      WHEN 'READY' THEN 1 
      WHEN 'RUNNING' THEN 2 
      WHEN 'STOPPED' THEN 3 
     END 

看到它在sqlfiddle

 
| id | machinename | workername | machinestate | 
|----|-------------|------------|--------------| 
| 1 |  Beta |  Foo |  STOPPED | 
| 2 |   Yuu |  Jaam |  STOPPED | 
| 3 |   Iem |  Fish |  RUNNING | 

你可以保存自己使用CASE的疼痛,如果MachineState是一個ENUM類型列(在適當的順序定義)。在這種情況下,對字符串值進行簡單的詞典排序會得到相同的結果,但這是一個巧合,你不應該依賴它,因爲當有人試圖在未來。

1

這是一個優先級查詢。一種方法使用變量。另一種使用union all。 。 。這個工作,如果不重複給定的ID狀態:

select t.* 
from table t 
where machinestate = 'STOPPED' 
union all 
select t.* 
from table t 
where machinestate = 'RUNNING' and 
     not exists (select 1 from table t2 where t2.id = t.id and t2.machinestate in ('STOPPED')) 
union all 
select t.* 
from table t 
where machinestate = 'READY' and 
     not exists (select 1 from table t2 where t2.id = t.id and t2.machinestate in ('STOPPED', 'RUNNING')); 
+1

這不起作用,他想要替換列值,如果其中一個是null .. – sagi

0

變化MachineState爲枚舉:

`MachineState` enum('READY','RUNNING','STOPPED') DEFAULT NULL 

和SQL很簡單:

select t.id,state.machinename,state.workername,t.mstate from state,(select id,max(MachineState) mstate from state group by Id) t where t.mstate=state.machinestate and t.id=state.id;