T-SQL需要协助复杂的连接

时间:2012-11-02 13:08:19

标签: tsql join insert-update

我真的不知道如何解决这个问题,需要一些帮助 - 不仅解决方案,而且欢迎如何处理的想法。

我有下表:

TABLE Data
( 
     RecordID
    ,DateAdd
    ,Status
)

样本日期如下:

11  2012-10-01 OK
11  2012-10-04 NO
11  2012-11-05 NO
22  2012-10-01 OK
33  2012-11-01 NO
33  2012-11-15 OK

此表包含以下示例数据:

TABLE Periods
(
    PeriodID
   ,PeriodName
   ,DateStart
   ,DateEnd
)

1 Octomer  2012-10-01 2012-10-31
2 November 2012-11-01 2012-11-30

我需要做的是填充新表:

TABLE DataPerPeriods
(
    PeriodID,
    RecordID,
    Status
)

这将存储PeriodID和RecordID的所有可能组合以及句点的最新状态(如果可用)。如果给定期间的状态不可用,则表示先前期间的状态。如果根本没有先前的状态 - 那么状态为NULL。

例如,我需要以下数据:

1 11 NO //We have status "OK" and "NO", but "NO" is latest for the period
1 22 OK 
1 33 NULL//Because there are no records for this and previous periods
2 11 NO //We get the previos status as there are no records in this periods
2 22 OK //There are not records for this period, but record for last periods is available
2 33 NO //We have status "OK" and "NO", but "OK" is latest for the period

编辑:我已经在最后一个表格中填充了期间ID和记录ID,我需要更多关于状态更新的帮助。

3 个答案:

答案 0 :(得分:1)

在另一个问题上查看我的答案,了解如何获取第一个或最后一个状态:Aggregate SQL Function to grab only the first from each group

答案 1 :(得分:1)

可能有更好的方法来做到这一点。但这是我所知道的最直接的道路,可以得到你正在寻找的东西,它看起来是非常规的。对于较大的数据集,您可能需要更改方法:

SELECT p.PeriodID, td.RecordID, statusData.[Status] FROM Periods p
CROSS JOIN (SELECT DISTINCT RecordID FROM Data) td
OUTER APPLY (SELECT TOP 1 [Status], [DateAdd] 
         FROM Data 
         WHERE [DateAdd] <= p.DateEnd 
         AND [RecordID] = td.RecordID 
         ORDER BY [DateAdd] DESC) statusData
ORDER BY p.PeriodID, td.RecordID

CROSS JOIN为您提供RecordID和DISTINCT期间的所有可能组合。

OUTER APPLY选择每个Period之前的最新Status。

答案 2 :(得分:1)

好的,这是个主意。没有人喜欢游标,包括我,但有时像这样的事情它们会派上用场。

这个想法是这个游标循环遍历每个数据记录,将ID作为标识符拉出。在循环内部,它找到单个数据记录并获取符合条件的联接计数。

如果@count = 0,则不符合条件,您不应插入该期间的记录。

如果@ Count = 1,则满足条件,因此插入该期间的记录。

如果需要经常更新这些条件,您可以查询工作并每分钟或每小时运行一次......你有什么。

希望这会有所帮助。

DECLARE @ID int
DECLARE merge_cursor CURSOR FAST_FORWARD FOR 
select recordID
from data 
OPEN merge_cursor
FETCH NEXT FROM merge_cursor INTO @ID

WHILE @@FETCH_STATUS = 0
BEGIN

--get join if record is found in the periods
    declare @Count int
    select @Count= count(*) 
    from data a inner join periods b 
    on a.[dateadd] between b.datestart and b.dateend  
    where a.recordID = @ID 

    if @count>0

        --insert into DataPerPeriods(PeriodID, RecordID, Status)
        select b.periodid, a.recordid, a.status 
        from data a inner join periods b on a.[dateadd] between b.datestart and b.dateend --between beginning of  month and end of  month
        where a.recordid = @ID  
    else
        --insert into DataPerPeriods(PeriodID, RecordID, Status)
        select b.periodid, a.recordid, a.status 
        from data a inner join periods b on a.[dateadd] < b.dateend 
        where a.recordID = @ID --fix this area

FETCH NEXT FROM merge_cursor INTO @ID
END

CLOSE merge_cursor 
DEALLOCATE merge_cursor 
相关问题