繁体   English   中英

组中多个列的Oracle SQL计数

[英]Oracle SQL Counting across multiple columns within a group

具有一个数据集,该数据集在各列中具有多个重复条目。

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')
)

使我大致达到了该目标,但随后我很难通过其他控件,例如有限的日期范围,或链接到客户端表,以便可以将客户端代码转换为实际名称。

您可以将三个“测试”列取消转为一个列,这实际上是您的联合会所做的; 然后将其转到所需的列(假设您使用的是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

但目前尚不清楚。

对于正在寻找特定日期范围的查询,请尝试阅读此处: Oracle date“ Between”查询

看起来这不是一个定义良好的表结构。 您应该只有一个测试列,而不是多个。 对于您所拥有的,您走在正确的道路上。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM