拥有跨列有多个重复条目的数据集。
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 :(得分:0)
您可以将三个“测试”列拆分为一个,这基本上就是您的工会正在做的事情;然后将其转回到你想要的列(假设你是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
按日期过滤,例如,将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
但目前尚不清楚是否属实。
答案 1 :(得分:0)
对于寻找特定日期范围的查询,请尝试阅读:Oracle date "Between" Query
看起来这不是一个非常明确的表结构。您应该有一个测试列,而不是多个测试列。但是,就你所拥有的而言,你走在了正确的轨道上。
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