sql - 使用多个UNION ALL构建 View : is there a better way?

标签 sql sql-server sql-server-2005 query-optimization

这个问题有一些限制;我没有能力从根本上改变任何数据库结构。

这里的挑战是数据库中的一些行包含真正应该位于其自己的行中的信息。列结构的简化示例:

[PersonID] [FirstName] [LastName] [FirstNameGuest1] [LastNameGuest1]
 1          Ringo       Starr      John              Lennon
 2          George      Harrison   Paul              McCartney

我需要像这样将它们分开,以便能够运行我需要的报告:

[PersonID] [FirstName] [LastName]
 1          Ringo       Starr
 1          John        Lennon
 2          George      Harrison
 2          Paul        McCartney

由于我使用它来生成 View ,因此我必须为每组 guest 列引用相同的表,并使用 UNION ALL 将它们全部连接在一起。

但是,从那时起,我不得不在派生 View 之上构建日益复杂的查询。每一层的复杂性都会导致结果返回的速度越来越慢。

我采取的方法从根本上来说是错误的吗?还有其他更正确的方法来按照我需要的方式对数据进行建模吗?

这是实际查询的一部分,以便您可以看到我正在处理的内容:

--Primary Record
SELECT
 'Franchisee' AS 'Type', 
 Confirmation AS 'BelongingTo', 
 0 AS 'GuestNo', 
 FirstName, 
 LastName, 
 FF_27557_152972 AS 'HotelChoice', 
 HotelCheckIn, 
 HotelCheckOut, 
 HotelSmoking AS 'Smoking', 
 (CASE FF_27554_1 WHEN 'Yes' THEN 1 ELSE 0 END) AS 'PrimaryRoomHolder', 
 '' AS 'SharingWith', 
 'None' AS 'SharingWithName'
FROM dbo.[Table]
WHERE Type = 'Production' AND Submitted = 1 AND Cancelled = 0 AND Label = 'Primary'

UNION ALL
-- First Guest
SELECT
'Guest' AS 'Type',
Confirmation AS 'BelongingTo',
1 AS 'GuestNo', 
FF_27637_1 AS 'FirstName', 
FF_27637_152806 AS 'LastName', 
FF_27637_152822 AS 'HotelChoice', 
FF_27637_152813 AS 'HotelCheckIn', 
FF_27637_152821 AS 'HotelCheckOut', 
FF_27637_152824 AS 'Smoking', 
(CASE WHEN FF_27637_152822 IS NOT NULL THEN 1 ELSE 0 END) AS 'PrimaryRoomHolder', 
FF_27637_154245 AS 'SharingWith', 
(CASE CAST(FF_27637_154245 AS integer) 
  WHEN 0 THEN FirstName + ' ' + LastName 
  WHEN 1 THEN FF_27637_1 + ' ' + FF_27637_152806 
  WHEN 2 THEN FF_27742_1 + ' ' + FF_27742_153577 
  WHEN 3 THEN FF_27638_1 + ' ' + FF_27638_152814 
  WHEN 4 THEN FF_27639_1 + ' ' + FF_27639_152817 
  WHEN 5 THEN FF_27640_1 + ' ' + FF_27640_152852
  WHEN 6 THEN FF_27641_1 + ' ' + FF_27641_152860 
  WHEN 7 THEN FF_27642_1 + ' ' + FF_27642_152868 
  WHEN 8 THEN FF_27643_1 + ' ' + FF_27643_152877
  WHEN 9 THEN FF_27644_1 + ' ' + FF_27644_152885 
  WHEN 10 THEN FF_27645_1 + ' ' + FF_27645_152893 
  ELSE 'None' END) AS 'SharingWithName'
FROM dbo.Event_213_1546 AS Event_213_1546_10
WHERE Type = 'Production' AND Submitted = 1 AND Cancelled = 0 AND Label = 'Primary' AND FF_27637_1 IS NOT NULL
.
.
.
(Iterates through 9 more guests exactly like "First Guest")

最佳答案

您考虑过 UNPIVOT 运算符吗?它做同样的事情,但可能不那么痛苦(也许!:-)。需要 2005 年或更高版本。

http://blogs.msdn.com/craigfr/archive/2007/07/17/the-unpivot-operator.aspx

示例:

declare @names table ( personid int, 
    firstname1 varchar(50), 
    lastname1 varchar(50),
    firstname2 varchar(50), 
    lastname2 varchar(50),
    firstname3 varchar(50), 
    lastname3 varchar(50)

    -- <etc.>
    )

Insert @names values ( 1, 'Fred', 'Flintstone', 'Barney', 'Rubble', 'Wilma', 'Flintstone' )
Insert @names values ( 2, 'Super', 'Man', 'Aqua', 'Man', 'Wonder', 'Woman' )

select * from @names

select personid, firstnamecol, firstname, lastnamecol, lastname
from @names
unpivot( firstname for firstnamecol in ( firstname1, firstname2, firstname3 ) ) firstnames
unpivot( lastname for lastnamecol in ( lastname1, lastname2, lastname3 ) ) lastnames
where right(firstnamecol, 1) = right( lastnamecol, 1 ) -- This is the tricky bit

在一次选择中使用多个逆透视是很棘手的;我从这些人那里得到了上述想法:

http://weblogs.sqlteam.com/jeffs/archive/2008/04/23/unpivot.aspx http://mangalpardeshi.blogspot.com/2009/04/unpivot-multiple-columns.html

需要注意的是,标记为“tricky”的部分将因重复列名称中不同位数的数字而中断(例如,FirstName11 和 FirstName1 将成为问题)。您可以使用一些 substring() 技巧来解决这个问题。可能不是最好的主意,但是......

补充,2 月 22 日:这是一篇有关 unpivot 的精彩文章:http://bradsruminations.blogspot.com/2010/02/spotlight-on-unpivot-part-1.html

关于sql - 使用多个UNION ALL构建 View : is there a better way?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2240332/

相关文章:

sql - 如何在 SQL Server 2008 中同时为多个表设置 IDENTITY_INSERT ON

sql - TOP(1) select 多表性能

sql-server - 为什么我的内部连接不起作用

sql - 如何在 ALTER TABLE 后正确运行 ALTER VIEW

sql-server-2005 - smalldatetime 是否有效?

mysql - SQL - 配对电影流派

sql - 如何在 PostgreSQL 中获取表的列名和数据类型列表?

sql - 在服务器之间复制文件时出现 SSIS 文件系统任务错误

mysql - 向上指望积极变化,向下指望负面变化

sql - 如何制作动态栏目