【问题标题】:MERGE INTO insertion order合并到广告订单
【发布时间】:2010-10-27 10:02:42
【问题描述】:

我有一个类似这样的声明:

MERGE INTO someTable st
USING
(
    SELECT id,field1,field2,etc FROM otherTable
) ot on st.field1=ot.field1
WHEN NOT MATCHED THEN
    INSERT (field1,field2,etc)
    VALUES (ot.field1,ot.field2,ot.etc)

其中 otherTable 有一个自动递增的 id 字段。

我希望插入 someTable 的顺序与 otherTableid 字段的顺序相同,这样 当插入不匹配的字段时,id的顺序被保留。

快速查看docs 似乎表明没有支持此功能的功能。

这可能吗,或者有其他方法可以满足我的要求吗?

编辑:一种方法是向 someTable 添加一个额外的字段来捕获排序。如果可能,我宁愿不这样做。

...经过反思,上述方法似乎是可行的方法。

【问题讨论】:

    标签: sql sql-server tsql sql-server-2008 merge


    【解决方案1】:

    我无法说出提问者在这里的要求,因为它没有任何意义。

    让我们假设一个不同的问题:

    假设我有一个没有身份字段的堆表,但它确实有一个“已访问”日期字段。
    堆表记录个人网页访问,我将其加载到我的数据仓库中。
    在这个数据仓库中,我想使用代理键“WebHitID”来引用这些关系。
    让我们使用 Merge 来执行表的初始加载,然后继续调用它以保持表同步。

    我知道,如果我将记录插入表中,那么我希望 ID(由识别字段生成)根据我选择的任何 Order-By 是连续的(比如说“访问”日期)。
    期望 Integer-ID 与相对于表中其余记录的创建时间相关联并不罕见。
    我知道这并不总是 100% 的,但请幽默一下。

    这可以通过合并实现。

    使用(感觉像 hack)TOP 将允许在我们的插入中进行排序:

    MERGE DW.dbo.WebHit AS Target --This table as an Identity Field called WebHitID.
    USING
    (
        SELECT TOP 9223372036854775807 --Biggest BigInt (to be safe).
               PWV.PersonID, PWV.WebPageID, PWV.Visited
          FROM ProdDB.dbo.Person_WebPage_Visit AS PWV
         ORDER BY PWV.Visited --Works only with TOP when inside a MERGE statement.
    ) AS Source
      ON Source.PersonID  = Target.PersonID
     AND Source.WebPageID = Target.WebPageID
     AND Source.Visited   = Target.Visited
    WHEN NOT MATCHED BY Target THEN --Not in Target-Table, but in Source-Table.
        INSERT (PersonID, WebPageID, Visited) --This Insert populates our WebHitID.
        VALUES (Source.PersonID, Source.WebPageID, Source.Visited)
    WHEN NOT MATCHED BY Source THEN --In Target-Table, but not in Source-Table.
        DELETE --In case our WebHit log in Prod is archived/trimmed to save space.
    ;
    


    您可以看到我选择使用 TOP 9223372036854775807(最大的整数)来拉取所有内容。
    如果您有更多的资源可以合并,那么您应该将其分块。
    虽然这对我来说是“hacky workaround”,但它应该能让你到达你需要去的地方。

    我已经在一个小样本集上对此进行了测试并验证了它的工作原理。 我还没有研究过它对更大的复杂数据集的性能影响,所以 YMMV 有和没有 TOP。

    【讨论】:

      【解决方案2】:

      跟进 MikeTeeVee 的回答。

      使用 TOP 将允许您在子查询中进行排序,但是我会使用

      而不是 TOP 9223372036854775807
      SELECT TOP 100 PERCENT 
      

      不太可能达到这个数字,但这种方式更有意义,看起来更干净。

      【讨论】:

      • SELECT TOP 100 PERCENT 在这种情况下对我不起作用,它会留下 unsorted 顺序。可能它被捕获为特殊情况并被优化器绕过。如果我用SELECT TOP 9223372036854775807 替换它,排序就会立即生效。 SQL Server 2008 R2。
      • 另见: MSDN 博客文章TOP 100 Percent ORDER BY Considered Harmful
      【解决方案3】:

      为什么要关心 id 匹配的顺序?这对您查询数据的方式有什么影响?相关表应该通过主键和外键连接,而不是插入订单记录。表在数据库中并不是以特定的方式排序的。 order 应该来自 order by 子句。

      更多解释您为什么要这样做可能会帮助我们引导您找到合适的解决方案。

      【讨论】:

      • +1 如果您确实关心,那么您尝试捕获的数据中的某些内容对您很重要 - 所以请正确执行。听起来数据告诉您它需要一个明确的订单列。
      • 我试图插入的数据是按时间顺序排列的,但没有任何明确的字段来指示这种顺序......但是,当按 id 排序时,otherTable 中的顺序是按时间顺序正确的。考虑您的回答让我想知道我的架构是否可以进行更新。您是正确的,依赖 id 字段可能是一种狡猾的方法。
      • 虽然您的回答在学术上是正确的,但在某些情况下您无法承担更改架构等的费用。或者请参阅MikeTeeVee's answer。然后,您想要一个简单的提示,如何绕过该学术原则并在合并操作中强制执行排序。您的回答缺少这些细节,因此-1
      • @miroxlav,我没有包括这些细节,因为操作员要求的是一件坏事,在任何情况下都不应该这样做。这不是学术,而是现实生活。他想要的永远无法保证事情是正确匹配的。破解一些可能正确但无法保证的东西是不负责任的。这是数据完整性的问题。假设一条记录在插入第二张表时被拒绝,那么从那里开始的所有其他匹配都是不正确的。假设同时插入两条记录?
      • "你为什么要关心 ids 匹配的顺序?"不是对“如何使用合并确保插入以正确的顺序发生?”问题的答案?
      猜你喜欢
      • 1970-01-01
      • 2014-05-05
      • 2014-07-23
      • 1970-01-01
      • 2020-04-26
      • 2016-03-25
      • 2014-06-20
      • 2018-07-09
      • 1970-01-01
      相关资源
      最近更新 更多