Oracle Query - 使用分析函数

时间:2015-03-20 15:23:31

标签: sql oracle11g

假设我们已将带有患者诊断数据的平面文件加载到名为“数据”的表中。表结构是:

Create table Data (
Firstname varchar(50),
Lastname varchar(50),
Date_of_birth datetime,
Medical_record_number varchar(20),
Diagnosis_date datetime,
Diagnosis_code varchar(20))

平面文件中的数据如下所示:

'jane','jones','2/2/2001','MRN-11111','3/3/2009','diabetes'
'jane','jones','2/2/2001','MRN-11111','1/3/2009','asthma'
'jane','jones','5/5/1975','MRN-88888','2/17/2009','flu'
'tom','smith','4/12/2002','MRN-22222','3/3/2009','diabetes'
'tom','smith','4/12/2002','MRN-33333','1/3/2009','asthma'
'tom','smith','4/12/2002','MRN-33333','2/7/2009','asthma'
'jack','thomas','8/10/1991','MRN-44444','3/7/2009','asthma'

您可以假设没有两名患者具有相同的名字,姓氏和出生日期组合。然而,一名患者可能在不同的日子进行多次访问。这些都应该具有相同的医疗记录号。 问题是:汤姆史密斯有2个不同的病历号码。写一个总能显示所有患者的查询 谁就像汤姆史密斯 - 病历数超过一个的病人。

我想出了以下查询。它工作得很好,但想知道是否有更好的方法来使用Oracle Analytical函数编写此查询。提前谢谢

SELECT   a.firstname,
         a.lastname,
         a.date_of_birth,
         a.medical_record_number
FROM     data a, data b
WHERE        a.firstname = b.firstname
         AND a.lastname = b.lastname
         AND a.date_of_birth = b.date_of_birth
         AND a.medical_record_number <> .medical_record_number
GROUP BY a.firstname,
         a.lastname,
         a.date_of_birth,
         a.medical_record_number

2 个答案:

答案 0 :(得分:1)

可以通过分析函数来完成,但它是否比在查询中加入*更快取决于您拥有的数据。你需要测试。

with data (firstname, lastname, date_of_birth, medical_record_number, diagnosis_date, diagnosis_code)
          as (select 'jane','jones','2/2/2001','MRN-11111',to_date('3/3/2009', 'mm/dd/yyyy'),'diabetes' from dual union all
              select 'jane','jones','2/2/2001','MRN-11111',to_date('1/3/2009', 'mm/dd/yyyy'),'asthma' from dual union all
              select 'jane','jones','5/5/1975','MRN-88888',to_date('2/17/2009', 'mm/dd/yyyy'),'flu' from dual union all
              select 'tom','smith','4/12/2002','MRN-22222',to_date('3/3/2009', 'mm/dd/yyyy'),'diabetes' from dual union all
              select 'tom','smith','4/12/2002','MRN-33333',to_date('1/3/2009', 'mm/dd/yyyy'),'asthma' from dual union all
              select 'tom','smith','4/12/2002','MRN-33333',to_date('2/7/2009', 'mm/dd/yyyy'),'asthma' from dual union all
              select 'jack','thomas','8/10/1991','MRN-44444',to_date('3/7/2009', 'mm/dd/yyyy'),'asthma' from dual),
-- end of mimicking your table and its data
      res as (select firstname,
                     lastname,
                     date_of_birth,
                     medical_record_number,
                     count(distinct medical_record_number) over (partition by firstname, lastname, date_of_birth) cnt_med_rec_nums
              from   data)
select distinct firstname,
                lastname,
                date_of_birth,
                medical_record_number
from   res
where  cnt_med_rec_nums > 1;

*顺便说一句,您的示例查询中的group by不是必需的;把它换成一个独特的东西会更有意义 - 它会使你的意图更清晰,因为你想获得一组独特的记录。

答案 1 :(得分:0)

您可以使用HAVING子句简化查询,而不是自我加入

SELECT   a.firstname,
         a.lastname,
         a.date_of_birth,
         MIN(a.medical_record_number) lowest_medical_record_number,
         MAX(a.medical_record_number) highest_medical_record_number
FROM     data a
GROUP BY a.firstname,
         a.lastname,
         a.date_of_birth
HAVING   COUNT( DISTINCT a.medical_record_number ) > 1

我在这里为每位患者返回最小和最大的医疗记录编号(如果大多数有这个问题的患者只有两个数字而不是几十个,我会怎么做) 。您可以只返回一个,或者您可以返回以逗号分隔的所有医疗记录编号列表(如果您更愿意的话)(如果大多数坏人有数十个数字,这可能更有意义。)