如何创建基于条件从多行获取数据的SQL查询?
我有两张桌子: 保险信息表:如何创建基于条件从多行获取数据的SQL查询?,sql,database,oracle,querying,Sql,Database,Oracle,Querying,我有两张桌子: 保险信息表: Name |Insurance_ID|Insurance_Effective|Insurance_Expiry |Insurance_type John |30 |20100502 |20120502 |Primary Reggy |50 |20110904 |20160803 |Tertiary John
Name |Insurance_ID|Insurance_Effective|Insurance_Expiry |Insurance_type
John |30 |20100502 |20120502 |Primary
Reggy |50 |20110904 |20160803 |Tertiary
John |54 |20120503 |20170403 |Primary
Reggy |30 |20120503 |20140101 |Secondary
Reggy |39 |20110904 |20160803 |Primary
服务表:
Name | Date_of_Service |Other_info
John | 20110102 |Foo
John | 20110102 |Bar
Reggy | 20150304 |Sth
John | 20130206 |Other
现在我必须返回:
Name |Primary_Insurance | Secondary_Insurance | Tertiary_Insurance | Date_of_Service
John | 30 |null | null |20110102
John | 54 |null | null |20130206
Reggy | 39 |null | 50 |20150304
从服务表中每人每天最多只能有一个服务日期。此外,保险信息表中的一级、二级和三级保险被选中,其中保险生效日期<服务日期<人员服务的每个日期的保险到期日期
如何在Oracle SQL中编写此查询?您似乎在寻找一个轴心点。在Oracle 11g之前,您可以使用
MAX
和CASE
手动执行此操作:
select s.name,
max(case when ii.insurance_type = 'Primary' then ii.insurance_id end)
as primary_insurance,
max(case when ii.insurance_type = 'Secondary' then ii.insurance_id end)
as secondary_insurance,
max(case when ii.insurance_type = 'Tertiary' then ii.insurance_id end)
as tertiary_insurance,
s.date_of_service
from service s
left join insurance_info ii on ii.name = s.name
and s.date_of_service between ii.insurance_effective and ii.insurance_expiry
group by s.name, s.date_of_service
order by s.name, s.date_of_service;
NAME PRIMARY_INSURANCE SECONDARY_INSURANCE TERTIARY_INSURANCE DATE_OF_SERVICE
---------- ----------------- ------------------- ------------------ ---------------
John 30 02-JAN-11
John 54 06-FEB-13
Reggy 39 50 04-MAR-15
这是建立在两个表之间的一个基本连接之上的,这两个表之间是相互关联的。三个CASE
语句添加了伪列,其中包含。最后,MAX
聚合将拆分出的值向下折叠,因此每个名称/服务日期只有一行
从11g开始,您可以使用内置的,并有效地为您做同样的事情:
select *
from (
select s.name,
s.date_of_service,
ii.insurance_type,
ii.insurance_id
from service s
left join insurance_info ii on ii.name = s.name
and s.date_of_service between ii.insurance_effective and ii.insurance_expiry
)
pivot (max(insurance_id) as insurance for (insurance_type)
in ('Primary' as primary, 'Secondary' as secondary, 'Tertiary' as tertiary))
order by name, date_of_service;
NAME DATE_OF_SERVICE PRIMARY_INSURANCE SECONDARY_INSURANCE TERTIARY_INSURANCE
---------- --------------- ----------------- ------------------- ------------------
John 02-JAN-11 30
John 06-FEB-13 54
Reggy 04-MAR-15 39 50
我假设(希望)日期字段实际上是
DATE
而不是VARCHAR2
值,如果需要,您只需将结果格式化为YYYYMMDD
。如果它们是该格式的字符串,因为它们是可比较的,那么它仍然可以工作,但是您不应该将日期存储为字符串
另外,假设您希望日期范围包括在内,那么使用
BETWEEN
相当于Insurance\u您尝试过什么吗?@TMNT2014这应该是一个答案,而不是一个注释。@TMNT2014为什么删除您的注释?我之前很忙,没有机会看一遍….+1,因为包含了SQL Fiddle。我不知道这件事=我仍然使用Oracle 10g:(你能解释一下MAX在这种情况下的用法吗?我对它的理解仅限于返回列中的最高值。@user3808188-它是这样做的,但是对于使用case
生成的伪列中的最高值。我已经添加了一些解释;如果你查看额外的SQL Fiddle链接,希望它会更清晰。我不知道。)我看不出使用(CASE-WHEN(任何可能的选项)然后使用ID)和只使用ID之间的区别。据我所知,无论哪种方式,它都返回一个MAX函数正在运行的值。我看不出在这种情况下,我们是如何获得更少的具有完全匹配列的行的。即使在看到SQL Fiddle之后