1

与えられた2つのテーブル:

'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パスが必要です。複数のパスを必要とせずにUNIONALLを達成する方法はありますか?

構造は、変更できないベンダー製品の一部であることを指摘しておく必要があります。:(

4

2 に答える 2

1

あなたは:をすることによって5つのスキャンを回避することができます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     

これにより、インデックスを使用して5つの結合が実行されます。非常に高速で、peopleテーブルを1回スキャンし、これを相互結合にフィードします。次に、ロジックは必要な値を返します。

注:これらは両方ともテストされていないため、構文エラーが発生する可能性があります。

于 2013-02-27T18:38:01.190 に答える
0

残念ながら、現在のテーブルの構造では、各値を取得するために複数のパスが必要になります。可能であれば、テーブル構造を変更してテーブルを含め、次にとの間に結合テーブルを含めることをお勧めします。このshoe_typeテーブルには、靴がお気に入りかどうかを示すフラグを含めることができます。peopleshoes

したがって、これは次のようになります。

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 FiddlewithDemoを参照してください

于 2013-02-27T18:01:00.200 に答える