2017-04-20 11 views
2

複数の列に複数の繰り返しエントリがあるデータセットがあります。Oracle SQLグループ内の複数の列にまたがって計算する

ID DATE  CLIENT TEST0 TEST1 TEST2 
================================================ 
1 04/12/17 123  CBC  LIPID (null) 
2 04/12/17 345  LIPID (null) (null) 
3 04/13/17 123  BMP  CBC  (null) 
4 04/13/17 345  TSH  LIPID (null) 

理想的には、私はその後、TEST0、TEST1、TEST2列内のデータによってテストカウントを与え、出力がクライアントによってグループ化することにしたいと思います。
は返す必要があります。

CLIENT CBC LIPID BMP TSH 
==================================== 
123  2  1  1  0 
345  0  2  0  1 

select * 
from 
(
select test0 as testid from orders 
union all 
select test1 as testid from orders 
) t1 
pivot 
(
count(testid) 
for testid in ('CBCWD','LIPID','BMP','TSH') 
) 

そのターゲットで大体私を取得しているが、その後、私は限られた日付範囲のような他のコントロールに渡すのに苦労し、またはクライアントへのアウトリンクてるの使い方クライアントコードを実際の名前に変換することができます。

答えて

0

「テスト」の3つの列を1つにアンピボットすることができます。これは本質的にあなたのユニオンがやっていることです。それをあなたが望む列に戻します(あなたが11g以上であると仮定して)。 CTEでのサンプルデータで:日付でフィルタリングするに

with orders (ID, DT, CLIENT, TEST0, TEST1, TEST2) as (
    select 1, date '2017-04-12', 123, 'CBC', 'LIPID', null from dual 
    union all select 2, date '2017-04-12', 345, 'LIPID', null, null from dual 
    union all select 3, date '2017-04-13', 123, 'BMP', 'CBC', null from dual 
    union all select 4, date '2017-04-13', 345, 'TSH', 'LIPID', null from dual 
) 
select * from (
    select client, test 
    from orders 
    unpivot (test for num in (test0 as '0', test1 as '1', test2 as '2')) 
) 
pivot (count(test) as cnt for (test) 
    in ('CBC' as cbc, 'LIPID' as lipid, 'BMP' as bmp, 'TSH' as tsh)); 

    CLIENT CBC_CNT LIPID_CNT BMP_CNT TSH_CNT 
---------- ---------- ---------- ---------- ---------- 
     123   2   1   1   0 
     345   0   2   0   1 

、行は表から選んだrestircts別のサブクエリにfrom ordersを変更する、と言います。別のテーブルに結果を結合し、どちらかその内側のクエリ内での参加、または全部内側のクエリの別のレベル、のようなものにするには:時間内に単一の値のみ欄に表示されることができる場合

select c.client_name, o.cbc_cnt, o.lpid_cnt, o.dmp_cnt, o.tsh_cnt 
from (
    select * from (
     select client, test 
     from (
     select * 
     from orders 
     where dt = date '2017-04-12' 
    ) 
     unpivot (test for num in (test0 as '0', test1 as '1', test2 as '2')) 
    ) 
    pivot (count(test) as cnt for (test) 
     in ('CBC' as cbc, 'LIPID' as lipid, 'BMP' as bmp, 'TSH' as tsh)) 
) o 
join your_client_table c on c.client = o.client; 

を行 - あなたはTEST0およびTEST1の両方を持つ行を持って、両方のCBCに設定し、例えばことができませんでした - あなたは、より簡単に行うことができます:

select client, 
    count(case when test0 = 'CBC' or test1 = 'CBC' or test2 = 'CBC' then client end) as cbc, 
    count(case when test0 = 'LIPID' or test1 = 'LIPID' or test2 = 'LIPID' then client end) as lipid, 
    count(case when test0 = 'BMP' or test1 = 'BMP' or test2 = 'BMP' then client end) as bmp, 
    count(case when test0 = 'TSH' or test1 = 'TSH' or test2 = 'TSH' then client end) as tsh 
from orders 
group by client; 

    CLIENT  CBC  LIPID  BMP  TSH 
---------- ---------- ---------- ---------- ---------- 
     123   2   1   1   0 
     345   0   2   0   1 

をそうであることは明らかではありません。特定の日付範囲を探しているクエリのために

0

、ここで読んでみてください:Oracle date "Between" Query

は、非常に明確に定義されたテーブル構造であるようにそれは見えません。複数のテスト列ではなく、1つのテスト列が必要です。あなたが持っているものについては、あなたは正しい方向にあります。あなたが特定の日付範囲をしたい場合は

WITH ModifedTable AS (
    SELECT ID, DATE, CLIENT, TEST0 AS TEST_TYPE FROM Table WHERE TEST0 IS NOT NULL 
    UNION ALL 
    SELECT ID, DATE, CLIENT, TEST1 FROM Table WHERE TEST1 IS NOT NULL 
    UNION ALL 
    SELECT ID, DATE, CLIENT, TEST2 FROM Table WHERE TEST2 IS NOT NULL) 
SELECT 
    CLIENT, 
    SUM(DECODE(TEST_TYPE, "CBC", 1, NULL)) AS CBC_COUNT, 
    SUM(DECODE(TEST_TYPE, "LIPID", 1, NULL)) AS LIPID_COUNT, 
    SUM(DECODE(TEST_TYPE, "BMP", 1, NULL)) AS BMP_COUNT, 
    SUM(DECODE(TEST_TYPE, "TSH", 1, NULL)) AS TSH_COUNT 
FROM ModifiedTable 
GROUP BY CLIENT 
ORDER BY CLIENT 

、ModifiedTableサブクエリ内でそれをフィルタリング、またはフィルタリングする第二副問合せを使用します。

WITH ModifiedTable AS (SELECT ....), 
ModifiedTableDates AS (SELECT * FROM ModifiedTable WHERE DATE BETWEEN date1 AND date2) 
SELECT ... FROM ModifiedTableDates 
関連する問題