从相关子表创建视图

时间:2013-09-06 16:19:50

标签: sql sql-server sql-server-2008 common-table-expression sql-view

我有以下一般表结构(在我的人为例子中原谅以美国为中心的汽车制造商):

CREATE TABLE Car (
    [Id] int PRIMARY KEY
)

CREATE TABLE Ford (
    [FordId] int PRIMARY KEY, --also a foreign key on Car
    [Model]  nvarchar(max)
)

CREATE TABLE Chevy (
    [ChevyId] int PRIMARY KEY, --also a foreign key on Car
    [Model]  nvarchar(max)
)

我想在这些表的顶部创建一个视图,以便我可以检索所有Fords和Chevys,并在视图中生成一个告诉我make的列。我的第一次尝试是:

SELECT 
    c.CarId,
    case when f.FordId is not null then 'Ford' else 'Chevy' end 
FROM Car as c
LEFT JOIN Ford as f on c.Id = f.FordId
LEFT JOIN Chevy as ch on c.Id = ch.ChevyId
WHERE (f.FordId is not null or ch.ChevyId is not null)

但是这会让我的口味变得不好,我担心表现。我会更好地在单独的CTE值中检索所有Fords和Chevys并且仅对它们执行联合吗?我完全走错了路吗?我还需要包含Model列(以及两个子表共有的一些其他列),这显然会使我的视图变成一系列大量的case语句。处理这种情况的“正确”方法是什么?

编辑:我想我应该补充说这个架构已经存在,因此无法更改基础表。

1 个答案:

答案 0 :(得分:1)

首先,让我们试着看看两种方法的优点和缺点:

create view vw_Car1
as
  SELECT 
      c.Id,
      case when f.FordId is not null then 'Ford' else 'Chevy' end as Maker,
      coalesce(f.Model, ch.Model) as Model
  FROM Car as c
  LEFT JOIN Ford as f on c.Id = f.FordId
  LEFT JOIN Chevy as ch on c.Id = ch.ChevyId
  WHERE (f.FordId is not null or ch.ChevyId is not null);

create view vw_Car2
as
  select FordId as id, 'Ford' as Maker, Model from Ford
  union all
  select ChevyId as id, 'Chevy' as Maker, Model from Chevy;

在连接中使用它时,第一个更好,特别是如果你不使用所有列。例如,假设您在使用vw_Car

时有视图
create table people (name nvarchar(128), Carid int);

insert into people
select 'John', 1 union all
select 'Paul', 2;

create view vw_people1
as
select
    p.Name, c.Maker, c.Model
from people as p
   left outer join vw_Car1 as c on c.ID = p.CarID;

create view vw_people2
as
select
    p.Name, c.Maker, c.Model
from people as p
   left outer join vw_Car2 as c on c.ID = p.CarID;

现在,如果你想做简单的选择:

select Name from vw_people1;

select Name from vw_people2;

首先从people进行简单的选择(vw_Car1根本不会被查询)。第二个会更复杂 - FordChevy都会被查询。 您可以认为第一种方法更好,但让我们尝试另一种查询:

select *
from vw_people1
where Maker = 'Ford' and Model = 'Fiesta';

select *
from vw_people2
where Maker = 'Ford' and Model = 'Fiesta';

此处第二个会更快,特别是如果您在Model列上有索引。

=> sql fiddle demo - 查看这些查询的查询计划。