给出两个表:
'people'表包含以下列:
name
favorite_walking_shoe
favorite_running_shoe
favorite_dress_shoe
favorite_house_shoe
favorite_other_shoe
'shoes'表包含以下列:
shoe
name
description
我想创建一个包含以下内容的结果集:
people.name, people.favorite_shoe_type, shoes.name, shoes.description
我知道我可以使用以下内容获得所需的结果:
select p.name, p.favorite_shoe_type, s.name, s.description
from (select name, favorite_walking_shoe as shoe, 'walking' as favorite_shoe_type
from people where favorite_walking_shoe is not null
union all
select name, favorite_running_shoe, 'running'
from people where favorite_running_shoe is not null
union all
select name, favorite_dress_shoe, 'dress'
from people where favorite_dress_shoe not is null
union all
select name, favorite_house_shoe, 'house'
from people where favorite_house_shoe not is null
union all
select name, favorite_other_shoe, 'other'
from people where favorite_other_shoe not is null
) p
join shoes s on s.shoe = p.shoe
order by 1,2
但这需要5次传递“人员”表。有没有办法在不需要多次通过的情况下完成UNION ALL?
我应该指出,这些结构是供应商产品的一部分,我无法修改。 :(
答案 0 :(得分:1)
您可以通过执行cross join
来解决五次扫描:
select p.name, p.favorite_shoe_type, s.name, s.description
from (select p.*,
(case when favorite_shoetype = 'walking' then p.favore_walking_shoe
when favorite_shoetype = 'running' then p.favorite_running_shoe
when favorite_shoetype = 'dress' then p.favorite_dress_shoe
when favorite_shoetype = 'house' then p.favorite_house_shoe
when favorite_shoetype = 'other' then p.favorite_other_shoe
end) as shoe
from people p cross join
(select 'walking' as favorite_shoe_type union all
select 'running' union all
select 'dress' union all
select 'house' union all
select 'other'
) shoetypes join
shoes s
) p
on s.shoe = p.shoe
我不确定这会更有效率。如果鞋上有索引,这个更复杂的版本可能更有效:
select p.name, p.favorite_shoe_type, s.name, s.description
from (select p.name, favorite_shoe_types,
(case when favorite_shoetype = 'walking' then ws.name
when favorite_shoetype = 'running' then rs.name
when favorite_shoetype = 'dress' then ds.name
when favorite_shoetype = 'house' then hs.name
when favorite_shoetype = 'other' then os.name
end) as name,
(case when favorite_shoetype = 'walking' then ws.description
when favorite_shoetype = 'running' then rs.description
when favorite_shoetype = 'dress' then ds.description
when favorite_shoetype = 'house' then hs.description
when favorite_shoetype = 'other' then os.name
end) as description
from people p left outer join
shoes ws
on ws.shoe = favorite_walking_shoe left outer join
shoes rs
on rs.shoe = favorite_running_shoe left outer join
shoes ds
on ds.shoe = favorite_dress_shoe left outer join
shoes hs
on hs.shoe = favorite_house_shoe left outer join
shoes os
on os.shoe = favorite_other_shoe cross join
(select 'walking' as favorite_shoe_type union all
select 'running' union all
select 'dress' union all
select 'house' union all
select 'other'
) shoetypes
) p
on s.shoe = p.shoe
where s.name is not null
这应该使用索引进行五个连接 - 非常快,一次扫描人员表,并将其提供给交叉连接。然后逻辑返回您想要的值。
注意:这两个都未经测试,因此可能会出现语法错误。
答案 1 :(得分:0)
不幸的是,您当前表的结构方式将有多个传递来获取每个值。如果可能,我建议将表结构更改为包含shoe_type
表,然后在people
和shoes
之间的连接表,并在此表中包含标志这将显示鞋是否是最喜欢的。
所以它将与此类似:
create table people_shoe
(
people_id int,
shoe_id int,
IsFavorite int
);
您还可以使用shoe_type
表来存储每种不同的节目类型:
create table shoe_type
(
id int,
name varchar(10)
);
insert into shoe_type
values('Walking'), ('Running'), ('Dress'), ('House'), ('Other');
shoe_type.id
将被添加到您的shoe
表中,您将加入表格。
编辑#1,如果你可以改造数据库,你可以使用以下(模拟模型):
create table people
(
id int,
name varchar(10)
);
insert into people values (1, 'Jim'), (2, 'Jane');
create table shoe_type
(
id int,
name varchar(10)
);
insert into shoe_type
values(1, 'Walking'), (2, 'Running'), (3, 'Dress'), (4, 'House'), (5, 'Other');
create table shoes
(
id int,
name varchar(10),
description varchar(50),
shoe_type_id int
);
insert into shoes
values(1, 'Nike', 'test', 2), (2, 'Cole Haan', 'blah', 3);
create table people_shoe
(
people_id int,
shoe_id int,
IsFavorite int
);
insert into people_shoe
values (1, 1, 1),
(1, 2, 0),
(2, 1, 1);
然后当您查询时,您的代码将类似于:
select p.name PersonName,
s.name ShoeName,
st.name ShoeType,
ps.isFavorite
from people p
inner join people_shoe ps
on p.id = ps.people_id
inner join shoes s
on ps.shoe_id = s.id
inner join shoe_type st
on s.shoe_type_id = st.id