我目前正面临一个我的Oracle知识无法解决的问题,我绝对不是数据库专家,这就是为什么我问你是否知道如何解决我的SQL查询问题。
这是我的问题,我有两个表,让我们称之为DEVICE_TABLE和COUNT_TABLE
COUNT_TABLE看起来像是:
DEVICE (Int) PK | QUANTITY (Int) - - - - - - - - - - - - - - - - - - - - - - - - - - - 1001 | 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - 1002 | 20 - - - - - - - - - - - - - - - - - - - - - - - - - - - 1003 | 1 …
DEVICE_TABLE看起来像:
ID (Int) PK | WiFi (String) | Email (String) | Bluetooth(String) | … - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1001 | Yes | No | No | … - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1002 | Yes | Yes | No | … - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1003 | Unknown | Unknown | Yes | … …
约束是:
DEVICE_TABLE.ID = COUNT_TABLE.DEVICE
WiFi,电子邮件,蓝牙...字符串只能是:“是”,“否”或“未知”
最后,我预期的SQL请求结果是(基于我的例子):
Feature | Yes | No | Unknown - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WiFi | 24 | 0 | 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Email | 20 | 4 | 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Bluetooth | 1 | 24 | 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - …
简而言之,此请求的目的是将所有与特定功能兼容的设备数量相加。
如果您对如何实现这一点有任何线索,请提前感谢您! (也许这是不可能的......)
答案 0 :(得分:3)
在Oracle 11中,您可以将pivot
子句与unpivot
子句一起使用:
with
count_table as (
select 1001 device_id, 4 quantity from dual union all
select 1002 device_id, 20 quantity from dual union all
select 1003 device_id, 1 quantity from dual
),
device_table as (
select 1001 id, 'Yes' wifi, 'No' email, 'No' bluetooth from dual union all
select 1002 id, 'Yes' wifi, 'Yes' email, 'No' bluetooth from dual union all
select 1003 id, 'Unknown' wifi, 'Unknown' email, 'Yes' bluetooth from dual
)
----------------------------------------
select * from (
select
feature,
yes_no_unknown,
sum(quantity) quantity
from
count_table c join
device_table d on c.device_id = d.id
unpivot ( yes_no_unknown
for feature in (wifi, email, bluetooth)
)
group by
feature,
yes_no_unknown
)
pivot ( sum (quantity)
for yes_no_unknown in ('Yes' as yes, 'No' as no, 'Unknown' as unknown)
)
;
或者,您可能希望将两个现有表连接到第三个表,该表包含三个所需行的值。它也可能更容易阅读:
with
count_table as (
select 1001 device_id, 4 quantity from dual union all
select 1002 device_id, 20 quantity from dual union all
select 1003 device_id, 1 quantity from dual
),
device_table as (
select 1001 id, 'Yes' wifi, 'No' email, 'No' bluetooth from dual union all
select 1002 id, 'Yes' wifi, 'Yes' email, 'No' bluetooth from dual union all
select 1003 id, 'Unknown' wifi, 'Unknown' email, 'Yes' bluetooth from dual
)
----------------------------------------
select
f.txt,
sum(case when ( f.txt = 'wifi' and d.wifi = 'Yes' ) or
( f.txt = 'email' and d.email = 'Yes' ) or
( f.txt = 'bluetooth' and d.bluetooth = 'Yes' )
then c.quantity
else 0 end
) yes,
sum(case when ( f.txt = 'wifi' and d.wifi = 'No' ) or
( f.txt = 'email' and d.email = 'No' ) or
( f.txt = 'bluetooth' and d.bluetooth = 'No' )
then c.quantity
else 0 end
) no,
sum(case when ( f.txt = 'wifi' and d.wifi = 'Unknown' ) or
( f.txt = 'email' and d.email = 'Unknown' ) or
( f.txt = 'bluetooth' and d.bluetooth = 'Unknown' )
then c.quantity
else 0 end
) unknown
from
count_table c join
device_table d on c.device_id = d.id cross join
(
select 'wifi' txt from dual union all
select 'email' txt from dual union all
select 'bluetooth' txt from dual
) f
group by
f.txt;
答案 1 :(得分:1)
我很高兴为您取悦 - 您的数据库设计在相对数据库方面远非完美。 唯一可行的方法是使用UNION:
select 'WiFi' as Feature, (select count(*) from DEVICE_TABLE where WiFi = 'Yes') as Yes, (select count(*) from DEVICE_TABLE where WiFi = 'No') as No
union
select 'Email' as Feature, (select count(*) from DEVICE_TABLE where Email = 'Yes') as Yes, (select count(*) from DEVICE_TABLE where Email = 'No') as No
...
答案 2 :(得分:1)
1)通过创建具有设备ID,引用DEVICE_TABLE.ID和Capability的设备能力表,可以改进数据模型。
如果设备表中有“是”,请在设备功能中输入一行,并从设备表中删除功能/功能列。
除非:
with Capabilities as (
select ID, 'WiFi' as capability, Wifi as has_capability
from device_table
union all
select ID, 'Email', Email
from device_table
union all
select ID, 'BlueTooth', BlueTooth
from device_table
)
select C.capability
, sum(case when C.has_capability = 'Yes' then CNT.quantity end) as Yes
, sum(case when C.has_capability = 'No' then CNT.quantity end) as No
from device_table D
inner join Capabilities C on C.ID = D.ID
left outer join count_table CNT on CNT.DEVICE = D.ID
group by
C.capability
order by
C.capability
答案 3 :(得分:0)
如果您使用的是Oracle 11g,可以使用Pivot功能获取解决方案。请参阅以下查询:
select features,nvl(yes,0) yes,nvl(no,0) no,nvl(unknown,0) unknown from (
select * from (select 'Wifi' as features,wifi,nvl(quantity,0) quantity from count_table, device_table where id = device_id)
pivot (sum(nvl(quantity,0)) for Wifi in ('Yes' as yes,'No' as no,'Unknown' as unknown))
Union all
select * from (select 'Bluetooth' as features,bluetooth,nvl(quantity,0) quantity from count_table, device_table where id = device_id)
pivot (sum(nvl(quantity,0)) for bluetooth in ('Yes' as yes,'No' as no,'Unknown' as unknown))
union all
select * from (select 'Email' as features,Email,nvl(quantity,0) quantity from count_table, device_table where id = device_id)
pivot (sum(nvl(quantity,0)) for Email in ('Yes' as yes,'No' as no,'Unknown' as unknown))
)
order by yes desc
请参阅SQLFiddle:http://sqlfiddle.com/#!4/97793/1/0