2016-05-13 22 views
0

我正嘗試從數據庫中的兩個表重建數據。第一個表格(數據)包含時間值和代碼。第二個表格(信號)包含代碼和說明。理想情況下,我想最終得到如下所示的結果表格,其中按時間戳分組的列和行名稱已更改爲描述符文本。重建兩個表中的數據並重命名錶數據中的行

我已經設法做到這一職位SQL查詢使用分組和多個轉置,但這並不能很好地擴展。

是否可以在SQL查詢中執行所有這些功能?

數據表

TIMESTAMP   CODE  VALUE 
2016-05-11 13:56:47 1000.ME  26.900 
2016-05-11 13:56:47 1313.ME  9.1136 
2016-05-11 13:56:51 1313.ME  9.1233 
2016-05-11 13:56:56 1313.ME  9.1136 
2016-05-11 13:57:00 1000.ME  27 
2016-05-11 13:57:00 1313.ME  9.1331 

信號表

CODE  DESCRIPTOR 
1000.ME Inlet Thermpcouple 
1313.ME Air Flow 

結果表

Timestamp    Inlet Thermpcouple Air Flow 
2016-05-11 13:56:47 26.900    9.1136 
2016-05-11 13:56:51 26.900    9.1233 
2016-05-11 13:56:56 26.900    9.1136 
2016-05-11 13:57:00 27     9.1331 
+0

在你想要的輸出中,爲什麼第二排和第三排有26.900?對於那個時間戳,你對Inlet Thermpcouple沒有任何價值,那麼你如何選擇26.900而不是27或者null? – Aleksej

+0

您不能動態地使用信號表中的行來確定結果集中的列。 (無論如何,除非你想用XML輸出)。使用固定值,您可以輕鬆獲取該數據,但不能使用動態值。 –

+0

@AlexPoole - 哈,我很高興我提到過,否則我不得不編輯我的帖子。:-) – mathguy

回答

1

好做法,感謝您發佈您的問題!

這裏有一種方法來做你需要的。這個問題有三個部分:首先,您需要連接兩個表,以便使用實際的描述符而不是代碼。其次,您需要旋轉,以便將入口熱電偶和氣流讀數分爲兩列。第三,如果只有一個時間戳,你只有一個空氣流量值,但是入口熱電偶沒有值,你希望IT值填充最近的讀數(值)。

該聯接很簡單,第三部分是IGNORE NULLS選項的LAG()函數的直接應用。 (注意 - 這個函數允許使用一個開窗子句;默認是rows between unbounded preceding and current row,這正是我們需要的,所以我沒有使用這個參數 - 默認是完美的。)

唯一的小故障是 - 除非你使用動態SQL - 您需要必須知道您在SQL語句中使用的每個表中的列的數量和名稱。因此,在您的表格中將「入口熱電偶」和「氣流」描述爲無效 - 在聲明中它們仍然是硬編碼。因此,您可以使用這種方式來編寫查詢,或者您需要開發動態SQL代碼。

下面是代碼,包括您的測試數據,然後是查詢的輸出。

with data_table (ts, code, val) as (
     select to_timestamp('2016-05-11 13:56:47', 'yyyy-mm-dd hh24:mi:ss'), 
                '1000.ME', 26.9  from dual union all 
     select to_timestamp('2016-05-11 13:56:47', 'yyyy-mm-dd hh24:mi:ss'), 
                '1313.ME', 9.1136 from dual union all 
     select to_timestamp('2016-05-11 13:56:51', 'yyyy-mm-dd hh24:mi:ss'), 
                '1313.ME', 9.1233 from dual union all 
     select to_timestamp('2016-05-11 13:56:56', 'yyyy-mm-dd hh24:mi:ss'), 
                '1313.ME', 9.1136 from dual union all 
     select to_timestamp('2016-05-11 13:57:00', 'yyyy-mm-dd hh24:mi:ss'), 
                '1000.ME', 27  from dual union all 
     select to_timestamp('2016-05-11 13:57:00', 'yyyy-mm-dd hh24:mi:ss'), 
                '1313.ME', 9.1331 from dual 
    ), 
    signals_table (code, descriptor) as (
     select '1000.ME', 'Inflow Thermocouple' from dual union all 
     select '1313.ME', 'Air Flow'   from dual 
    ), 
    j as (
     select d.ts, s.descriptor, d.val from data_table d 
            inner join signals_table s on d.code = s.code 
    ), 
    p as (
     select * from j 
      pivot (min(val) for descriptor in ('Inflow Thermocouple' as it, 
               'Air Flow' as af)) 
    ) 
select ts, last_value(it ignore nulls) over (order by ts) as "Inflow Thermocouple", 
      last_value(af ignore nulls) over (order by ts) as "Air Flow" 
from p 
order by ts; 

注 - 下面的輸出顯示了實際的時間戳數據類型;我不確定您的「timestamp」列是否實際上是DATE數據類型或真正的時間戳,查詢應該以任何方式工作。另外,在數據庫中使用Oracle關鍵字(如「timestamp」或「date」)作爲表名或列名通常是一個非常糟糕的主意。我改變了ts。

TS           Inflow Thermocouple Air Flow 
--------------------------------------------- ------------------- ---------- 
11-MAY-16 01.56.47.000000000         26.9  9.1136 
11-MAY-16 01.56.51.000000000         26.9  9.1233 
11-MAY-16 01.56.56.000000000         26.9  9.1136 
11-MAY-16 01.57.00.000000000         27  9.1331 
+0

是的,我有一個類似的解決方案,我決定不發佈;但信號表是無關緊要的,因爲無論如何,您可以直接從數據表中進行數據透視,從而對數據進行硬編碼。那麼,我想我假設固定代碼,你只是假設固定描述符,這是更靈活一點。在信號表中添加一個新行需要修改查詢來匹配。 –

+0

右鍵 - 例如,我假設可能有多個代碼分配給氣流讀數。如果有更多的描述符,只需要修改查詢;如果有更多行將不同(新)代碼分配給流入熱電偶或氣流,則查詢不需要改變。 – mathguy

+0

不夠公平,使用描述符使得查詢的重要部分更加清晰。我仍然認爲OP需要一個動態的答案,但這可能與他們在普通SQL中獲得的答案一樣接近。 –