1

给定两个表:

'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

但这需要 'people' 表的 5 次通行证。有没有一种方法可以在不需要多次通过的情况下完成 UNION ALL?

我应该指出,这些结构是我无法修改的供应商产品的一部分。:(

4

2 回答 2

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     

这应该使用索引进行五次连接——非常快,一次扫描人员表,并将其提供给交叉连接。然后该逻辑返回您想要的值。

注意:这两个都未经测试,因此它们可能存在语法错误。

于 2013-02-27T18:38:01.190 回答
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

请参阅带有演示的 SQL Fiddle

于 2013-02-27T18:01:00.200 回答