2017-10-12 58 views
0

我的問題選擇數據是這樣的:從2個表,他們延長了行

我有兩個表。一個攜帶真實數據,另一個用作備份。每當真實數據發生變化時,觸發器會將原始行復制到備份表中。

我需要的是以下幾點:

我想選擇所有的原始真實數據。這意味着真實數據表中所有從未更改的條目以及第一次插入的備份表中的所有數據。

想象這些表:

╔════════╦══════════╗ ╔══════════╦════════╦══════════╗ 
║ RealId ║ Numeric ║ ║ BackupId ║ RealId ║ Numeric ║ 
╠════════╬══════════╣ ╠══════════╬════════╬══════════╣ 
║  1 ║  3 ║ ║  1 ║  1 ║  7 ║ 
║  2 ║  19 ║ ║  2 ║  1 ║  9 ║ 
║  3 ║  24 ║ ║  3 ║  1 ║  14 ║ 
║  4 ║  5 ║ ║  4 ║  2 ║  2 ║ 
║  5 ║  23 ║ ║  5 ║  3 ║  13 ║ 
╚════════╩══════════╝ ║  6 ║  5 ║  9 ║ 
         ║  7 ║  5 ║  4 ║ 
         ╚══════════╩════════╩══════════╝ 

我的目標是做一個查詢,將返回這樣的事情:

╔══════════╦════════╦══════════╗ 
║ BackupId ║ RealId ║ Numeric ║ 
╠══════════╬════════╬══════════╣ 
║ 1  ║  1 ║  7 ║ 
║ 4  ║  2 ║  2 ║ 
║ 5  ║  3 ║  13 ║ 
║ NULL  ║  4 ║  5 ║ 
║ 6  ║  5 ║  9 ║ 
╚══════════╩════════╩══════════╝ 

正如你所看到的,我一直想回到做出的第一項與備份表中的特定Realid進行比較。 (RealId和BACKUPID始終是唯一的)

一種方法我想到了

SELECT MIN(BackupId), RealId 
FROM BackupTable 
GROUP BY RealId 

至於真正的表,我想過像

SELECT * 
FROM real-table A 
WHERE NOT EXISTS (
    SELECT * 
    FROM backup-table B 
    WHERE B.RealId = A.RealId 
) 

但我根本無法想想合併表格的正確方法。

+0

認爲你差不多在那裏,但不要在EXIST中使用派生表,INNER JOIN會從實際表中使用它。 – Leonidas199x

+0

您有一種情況,即某個項目存在於真實表格中,但未備份。項目是否可以存在於備份中,但這不是真實的嗎? – SimonB

+0

@SimonB實數表可以保存具有RealId而沒有備份表的行,使其具有與RealId相同的行。但是備份表總是會有一行RealId,它也存在於實際表中 – Daidon

回答

1

使用窗口功能:

Create table #Real (RealID int, [Numeric] int) 

Create table #Backup (BackupID int, RealID int, [Numeric] int) 

Insert into #Real values(1, 3) 
Insert into #Real values(2, 19) 
Insert into #Real values(3, 24) 
Insert into #Real values(4, 5) 
Insert into #Real values(5, 23) 

Insert into #Backup values (1, 1, 7) 
Insert into #Backup values (2, 1, 9) 
Insert into #Backup values (3, 1, 14) 
Insert into #Backup values (4, 2, 2) 
Insert into #Backup values (5, 3, 13) 
Insert into #Backup values (6, 5, 9) 
Insert into #Backup values (7, 5, 4) 

Select distinct 
First_Value(b.[BackupID]) over (partition by r.RealID order by b.BackupID) as [BackupID] 
    , r.RealID as [RealID] 
    , isnull(First_Value(b.[Numeric]) over (partition by r.RealID order by b.BackupID), r.numeric) as [Numeric] 
from #Real r 
left join #Backup b on r.realID = b.realid 
order by r.[RealID] 
+0

如果這兩個表都有20列以上,這將如何擴展? [Numeric]只是一個示例,表示數據不同 – Daidon

+0

將以下內容添加到每列的SELECT:,isnull(First_Value(b。[Col1])over(分區由r.RealID按b.BackupID排序) ,r。Col1)作爲[Col1] – cloudsafe

+1

對於給定的例子,你的回答是正確的,而且比我編寫的回答更有效。因此,你的答案應該是被接受的答案。 – Daidon

0

對於任何預2012 ....

(*現在編輯假設所有realIDs將在真正的表存在)

SELECT   
    firstB.minBU AS [first Backup] 
    , R.realid 
    , ISNULL(B.numeric, R.numeric) AS [original value] 
FROM    
    (SELECT realid, MIN(backupid) AS minBU 
     FROM test.[backup] AS backup_1 GROUP BY realid 
    ) AS firstB 
    INNER JOIN 
    test.[backup] AS B 
     ON firstB.realid = B.realid AND firstB.minBU = B.backupid 
    RIGHT OUTER JOIN 
     test.real AS R ON firstB.realid = R.realid 
1

我發現這個職位上的SO:

Select from table if record found in another table

的回答這個問題幫我彌補了這樣一個解決方案:

SELECT NULL AS BackupId, A.* FROM real-table A 
WHERE NOT EXISTS (
    SELECT * 
    FROM backup-table B 
    WHERE B.RealId = A.RealId 
) 

union all 

Select C.* FROM backup-table C 
INNER JOIN (
    SELECT MIN(BackupId) AS BackupId, 
      RealId 
     FROM backup-table 
     GROUP BY RealId 
    ) D 
on D.BackupId = C.BackupId 

ORDER BY RealId Asc 

不過,我想測試這一對cloudsafes回答,看它有更好的表現。

+0

執行計劃如下:https://www.brentozar.com/pastetheplan/?id=HJSueThnZ 36%vs 64% – cloudsafe

+0

對於多個數字列,您提供的解決方案將會更好。 – cloudsafe