我有一个带有主键BaseTableID
的基表和一个表示基表中单个记录的多个事件的事件表,即
BaseTableID | EventCode | EventSequenceNumber
------------|-----------|--------------------
1 | A123 | 1
1 | A557 | 2
1 | 45AB | 3
1 | 0987 | 4
...
1 | SD12 | 70
2 | Z902 | 1
2 | D92C | 2
... etc ...
我需要对其进行非规范化,以便以以下格式提供平面文件:
BaseTableID | Event01 | Event02 | Event03 | ... | Event70
------------|---------|---------|---------|-----|---------
1 | A123 | A557 | 45AB | ... | SD12
2 | Z902 | D92C |
... etc ...
我可以目前使用查询
实现此目的select BaseTable.BaseTableID,
Event01 = Event01.EventCode,
Event02 = Event02.EventCode,
Event03 = Event03.EventCode,
Event04 = Event04.EventCode,
...
from BaseTable
left join Events Event01
on BaseTable.BaseTableID = Event01.BaseTableID
and Event01.EventSequenceNumber = 1
left join Events Event02
on BaseTable.BaseTableID = Event02.BaseTableID
and Event02.EventSequenceNumber = 2
left join Events Event03
on BaseTable.BaseTableID = Event03.BaseTableID
and Event03.EventSequenceNumber = 3
left join Events Event04
on BaseTable.BaseTableID = Event04.BaseTableID
and Event04.EventSequenceNumber = 4
... etc...
哪个有效,但可扩展性很强,连接/列的数量完全取决于select max(EventSequenceNumber) from Events
,这可能(并且可能)随时间而变化。想象一下当一个基表记录结束数百个事件时的噩梦。我不想复制粘贴数百个连接!
(值得注意的是 - 所需输出的格式远远超出我的控制范围。我无法将其更改为更明智的内容)
必须有更好的方法。有吗?
答案 0 :(得分:0)
这将有效..
CREATE TABLE temp(BaseTableID INT, EventCode VARCHAR(10), EventSequenceNumber INT)
DECLARE @EventSequenceNumber VARCHAR(MAX)
DECLARE @Query VARCHAR(MAX)
INSERT INTO temp(BaseTableID,EventCode,EventSequenceNumber)
SELECT 1 ,' A123', 1 UNION
SELECT 1 ,' A557 ', 2 UNION
SELECT 1 ,' 45AB ', 3 UNION
SELECT 2 ,' 0987', 4
SELECT @EventSequenceNumber= ISNULL(@EventSequenceNumber+',','')+'Event'+
CAST(EventSequenceNumber AS VARCHAR) FROM temp ORDER BY EventSequenceNumber
SET @Query='SELECT BaseTableID,'+@EventSequenceNumber+' FROM (SELECT BaseTableID,EventCode,
''Event''+CAST(EventSequenceNumber AS VARCHAR)AS EventSequenceNumber
FROM temp)pvt PIVOT
(MAX(EventCode) FOR EventSequenceNumber IN ('+@EventSequenceNumber+
'))dst'
execute(@Query)
DROP TABLE temp
答案 1 :(得分:0)
我最终转动如下。它不是100%可伸缩的(如果事件超过100则需要手动调整),但是出于所需的目的,可以在不需要使用动态SQL和字符串的情况下获得可用的余额。
with EventsPivot as (
select
BaseTableID,
Event01 = [01], Event02 = [02], Event03 = [03], Event04 = [04], Event05 = [05],
Event06 = [06], Event07 = [07], Event08 = [08], Event09 = [09], Event10 = [10],
Event11 = [11], Event12 = [12], Event13 = [13], Event14 = [14], Event15 = [15],
Event16 = [16], Event17 = [17], Event18 = [18], Event19 = [19], Event20 = [20]
from (
select BaseTableID, EventSequenceNumber, EventCode
from Events
) a
pivot (
max(EventCode) for EventSequenceNumber in (
[01], [02], [03], [04], [05], [06], [07], [08], [09], [10],
[11], [12], [13], [14], [15], [16], [17], [18], [19], [20]
)
) p
)
select
BaseTableID,
Event01 = EventsPivot.Event01,
Event02 = EventsPivot.Event01,
Event03 = EventsPivot.Event01,
...
from BaseTable
left join EventsPivot
on BaseTable.BaseTableID = EventsPivot.BaseTableID
您可以使用动态SQL实现真正可扩展的版本,可读性/可维护性成本(从https://stackoverflow.com/a/10404455/2061621改编而来,如果它有用的话,请提升):
-- creates '[01],[02],[03]' etc, though order not guaranteed
declare @shortCols as nvarchar(max) =
stuff((
select distinct Value = ',' + quotename(right('0' + cast(EventSequenceNumber as varchar), 2))
from Events
order by Value
for xml path(''),
type).value('.', 'nvarchar(max)'), 1, 1, '')
-- creates 'Event01 = EventsPivot.[01],Event02 = EventsPivot.[02],Event03 = EventsPivot.[03]' etc, though order not guaranteed
declare @longCols as nvarchar(max) =
stuff((
select distinct Value = ',' + quotename('Event' + right('0' + cast(EventSequenceNumber as varchar), 2)) + ' = ' + quotename(right('0' + cast(EventSequenceNumber as varchar), 2))
from Events
order by Value
for xml path(''),
type).value('.', 'nvarchar(max)'), 1, 1, '')
exec('
with EventsPivot as (
select
BaseTableID,
' + @shortCols + '
from (
select BaseTableID, EventSequenceNumber, EventCode
from Events
) a
pivot (
max(EventCode) for EventSequenceNumber in (
' + @shortCols + '
)
) p
)
select
BaseTable.BaseTableID,
' + @longCols + '
from BaseTable
left join EventsPivot
on BaseTable.BaseTableID = EventsPivot.BaseTableID
')