数十个连接到同一个表的可扩展替代方案?

时间:2015-06-02 09:25:03

标签: sql-server tsql

我有一个带有主键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,这可能(并且可能)随时间而变化。想象一下当一个基表记录结束数百个事件时的噩梦。我不想复制粘贴数百个连接!

(值得注意的是 - 所需输出的格式远远超出我的控制范围。我无法将其更改为更明智的内容)

必须有更好的方法。有吗?

2 个答案:

答案 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
')