我在Oracle中具有以下实体-属性-值(EAV)表:
| ID | Key | Value | |----|-------------|--------------| | 1 | phone_num_1 | 111-111-1111 | | 1 | phone_num_2 | 222-222-2222 | | 1 | contact_1 | friend | | 1 | contact_2 | family | | 1 | first_name | mike | | 1 | last_name | smith | | 2 | phone_num_1 | 333-333-3333 | | 2 | phone_num_2 | 444-444-4444 | | 2 | contact_1 | family | | 2 | contact_2 | friend | | 2 | first_name | john | | 2 | last_name | adams | | 3 | phone_num_1 | 555-555-5555 | | 3 | phone_num_2 | 666-666-6666 | | 3 | phone_num_3 | 777-777-7777 | | 3 | contact_1 | work | | 3 | contact_2 | family | | 3 | contact_3 | friend | | 3 | first_name | mona | | 3 | last_name | lisa |
请注意,某些键已索引,因此与其他索引键有关联。例如,phone_num_1将与contact_1关联。
注意:索引数量没有硬性限制。可以有10、20甚至50个phone_num_ *,但是可以保证每个phone_num_N都有一个对应的contact_N
这是我想要的结果:
| ID | Phone_Num | Contact | First_Name | Last_Name | |----|--------------|---------|------------|-----------| | 1 | 111-111-1111 | friend | mike | smith | | 1 | 222-222-2222 | family | mike | smith | | 2 | 333-333-3333 | family | john | adams | | 2 | 444-444-4444 | friend | john | adams | | 3 | 555-555-5555 | work | mona | lisa | | 3 | 666-666-6666 | family | mona | lisa | | 3 | 777-777-7777 | friend | mona | lisa |
我尝试过/看过什么:
我研究了Oracle的枢纽功能;但是,我不相信这可以解决我的问题,因为我没有固定数量的属性要使用。 我看了这些帖子: SQL Query to return multiple key value pairs from a single table in one row
Pivot rows to columns without aggregate
问题:
我想用SQL完全完成的任务是什么?如果是这样,怎么办?如果没有,请解释原因。
非常感谢您的帮助,以下是附表,可帮助您入门:
with
table_1 ( id, key, value ) as (
select 1,'phone_num_1','111-111-1111' from dual union all
select 1,'phone_num_2','222-222-2222' from dual union all
select 1,'contact_1','friend' from dual union all
select 1,'contact_2','family' from dual union all
select 1,'first_name','mike' from dual union all
select 1,'last_name','smith' from dual union all
select 2,'phone_num_1','333-333-3333' from dual union all
select 2,'phone_num_2','444-444-4444' from dual union all
select 2,'contact_1','family' from dual union all
select 2,'contact_2','friend' from dual union all
select 2,'first_name','john' from dual union all
select 2,'last_name','adams' from dual union all
select 3,'phone_num_1','555-555-5555' from dual union all
select 3,'phone_num_2','666-666-6666' from dual union all
select 3,'phone_num_3','777-777-7777' from dual union all
select 3,'contact_1','work' from dual union all
select 3,'contact_2','family' from dual union all
select 3,'contact_3','friend' from dual union all
select 3,'first_name','mona' from dual union all
select 3,'last_name','lisa' from dual
)
select * from table_1;
答案 0 :(得分:1)
这很丑,但是我认为您需要做
select t1.* , t2.value, t3.n, t3.f
from table_1 t1
inner join table_1 t2 on t1.id = t2.id and REPLACE(t1.key, 'phone_num_', '') = REPLACE(t2.key, 'contact_', '')
inner join (
select ID, min(case when Key = 'first_name' then Value end) as n, min(case when Key = 'last_name' then Value end) as f
from table_1
group by ID
) t3 on t1.id = t3.id
where
t1.Key not in('first_name','last_name')
答案 1 :(得分:1)
这不是动态枢轴,因为您有一组固定的键-您只需要首先将键的枚举与键本身分开即可。
您需要:
phone_num
和contact
键前缀;然后Oracle设置:
CREATE TABLE table_1 ( id, key, value ) as
select 1,'phone_num_1','111-111-1111' from dual union all
select 1,'phone_num_2','222-222-2222' from dual union all
select 1,'contact_1','friend' from dual union all
select 1,'contact_2','family' from dual union all
select 1,'first_name','mike' from dual union all
select 1,'last_name','smith' from dual union all
select 2,'phone_num_1','333-333-3333' from dual union all
select 2,'phone_num_2','444-444-4444' from dual union all
select 2,'contact_1','family' from dual union all
select 2,'contact_2','friend' from dual union all
select 2,'first_name','john' from dual union all
select 2,'last_name','adams' from dual union all
select 3,'phone_num_1','555-555-5555' from dual union all
select 3,'phone_num_2','666-666-6666' from dual union all
select 3,'phone_num_3','777-777-7777' from dual union all
select 3,'contact_1','work' from dual union all
select 3,'contact_2','family' from dual union all
select 3,'contact_3','friend' from dual union all
select 3,'first_name','mona' from dual union all
select 3,'last_name','lisa' from dual
查询:
SELECT *
FROM (
SELECT id,
CASE
WHEN key LIKE 'phone_num_%' THEN 'phone_num'
WHEN key LIKE 'contact_%' THEN 'contact'
ELSE key
END AS key,
CASE
WHEN key LIKE 'phone_num_%'
OR key LIKE 'contact_%'
THEN TO_NUMBER( SUBSTR( key, INSTR( key, '_', -1 ) + 1 ) )
ELSE NULL
END AS item,
value,
MAX( CASE key WHEN 'first_name' THEN value END )
OVER ( PARTITION BY id ) AS first_name,
MAX( CASE key WHEN 'last_name' THEN value END )
OVER ( PARTITION BY id ) AS last_name
FROM table_1
)
PIVOT( MAX( value ) FOR key IN ( 'contact' AS contact, 'phone_num' AS phone_num ) )
WHERE item IS NOT NULL
ORDER BY id, item
输出:
ID | ITEM | FIRST_NAME | LAST_NAME | CONTACT | PHONE_NUM -: | ---: | :--------- | :-------- | :------ | :----------- 1 | 1 | mike | smith | friend | 111-111-1111 1 | 2 | mike | smith | family | 222-222-2222 2 | 1 | john | adams | family | 333-333-3333 2 | 2 | john | adams | friend | 444-444-4444 3 | 1 | mona | lisa | work | 555-555-5555 3 | 2 | mona | lisa | family | 666-666-6666 3 | 3 | mona | lisa | friend | 777-777-7777
db <>提琴here
如果您可以重构表,那么一个简单的改进就是添加一个额外的列来保存键的枚举,并在每个枚举通用的值时使用NULL
:
CREATE TABLE table_1 ( id, key, line, value ) as
select 1, 'phone_num', 1, '111-111-1111' from dual union all
select 1, 'phone_num', 2, '222-222-2222' from dual union all
select 1, 'contact', 1, 'friend' from dual union all
select 1, 'contact', 2, 'family' from dual union all
select 1, 'first_name', NULL, 'mike' from dual union all
select 1, 'last_name', NULL, 'smith' from dual
那么您的密钥集始终是固定的,您无需从密钥中提取枚举值。
答案 2 :(得分:0)
选择ID,
电话,
联系,
first_value(last)IGNORE NULLS超过(按ID DESC按ID DESC划分的范围,在CURRENT行之间,并且在其后无边界)last_name,
first_value(FIRST)IGNORE NULLS over(按ID DESC范围按ID顺序划分,在CURRENT行与后无界之后)first_name
从
(选择ID,
值,
row_number()over(partition by id,SUBSTR(KEY,1,instr(KEY,'',1)-1)by KEY order)rn,
SUBSTR(KEY,1,instr(KEY,'',1)-1)键
FROM table_1
)枢纽(MAX(value)FOR KEY IN('phone'AS phone,'last'AS last,'first'AS FIRST,'contact'AS contact))
按ID排序;