【问题标题】:Select Data from 2 tables where they extend the rows从扩展行的 2 个表中选择数据
【发布时间】:2017-10-12 08:02:49
【问题描述】:

我的问题是这样的:

我有两张桌子。一个承载真实数据,另一个用作备份。每当真实数据发生变化时,触发器就会将原始行复制到备份表中。

我需要的是:

我想选择所有原始的真实数据。这意味着真实数据表中从未更改过的所有条目以及第一次插入的备份表中的所有数据。

想象一下这些表格:

╔════════╦══════════╗ ╔══════════╦════════╦══════════╗
║ 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
)

但我实在想不出组合表格的正确方法。

【问题讨论】:

  • 认为你已经差不多了,但不要在 EXISTS 中使用你的派生表,从真实表中对其进行 INNER JOIN。
  • 您有一个项目存在于真实表中,但没有备份的情况。一个项目可以存在于备份中但不是真实的,这也是有效的吗?
  • @SimonB real-table 可以在没有备份表的情况下保存具有 RealId 的行以拥有具有相同 RealId 的行。但是备份表总是会有一行 RealId 也存在于 real-table 中

标签: sql sql-server backup


【解决方案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]

【讨论】:

  • 如果两个表都有 20 多列,这将如何扩展? [Numeric] 只是一个示例,表明数据不同
  • 在每列的 SELECT 中添加以下内容: , isnull(First_Value(b.[Col1]) over (partition by r.RealID order by b.BackupID), r.Col1) as [Col1 ]
  • 对于给定的例子,你的答案是正确的,也比我编的更有效。因此,您的答案应该是公认的答案。
【解决方案2】:

我在 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 的答案对此进行测试,看看哪个性能更好。

【讨论】:

【解决方案3】:

对于 2012 年之前的任何人......

(* 现在编辑为假设所有 realID 都将存在于真实表中)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    • 2013-09-04
    • 1970-01-01
    • 2011-11-19
    • 2019-02-25
    • 2014-04-10
    • 2017-10-14
    相关资源
    最近更新 更多