【问题标题】:Using OUTPUT clause to insert value not in INSERTED使用 OUTPUT 子句插入不在 INSERTED 中的值
【发布时间】:2013-03-14 21:38:59
【问题描述】:

我正在编写一个存储过程来处理属于应用程序的表并将值插入到属于同一应用程序的表中(因此我无法修改任何一个表)。

我必须只处理新记录并记住哪些记录已被处理,为此我创建了第三个简单表。

表格如下,删除了许多列,只留下重要的细节。

源表

CREATE TABLE [dbo].[DETAIL](
    [DET_NET] [float] NULL,
    [DET_VAT] [float] NULL,
    [DET_VATCODE] [varchar](4) NULL,
    [DET_GROSS] [float] NULL,
    [DET_DATE] [datetime] NULL,
    [DET_PRIMARY] [float] NOT NULL
)

目标表

CREATE TABLE [dbo].[TRN_TEMP](
    [TRN_TRAN_DATE] [datetime] NULL,
    [TRN_DESCRIPTION] [varchar](20) NULL,
    [TRN_PRIMARY] [int] NULL,
    [TRN_AMT] [float] NULL
)

跟踪表

CREATE TABLE REGISTER(
    LINE_ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED NOT NULL,
    DET_PRIMARY_LINK FLOAT NOT NULL,
    INS_DATE DATETIME NOT NULL
)

我正在尝试将源表中的值插入到目标表中,同时还将源表的主键插入到跟踪表中。

INSERT INTO TRN_TEMP (TRN_TRAN_DATE, TRN_DESCRIPTION, TRN_AMT)
OUTPUT D.DET_PRIMARY, GETDATE() INTO REGISTER (DET_PRIMARY_LINK, INS_DATE)
SELECT D.DET_DATE, 'SOMETEXT', SUM(D.DET_NET)
FROM DETAIL D
LEFT JOIN REGISTER R ON D.DET_PRIMARY = R.DET_PRIMARY_LINK
WHERE <MY CONDITIONS> AND R.LINE_ID IS NULL -- TO REMOVE LINES ALREADY PROCESSED
GROUP BY D.DET_DATE

我看不到上面的文字有问题,但我收到一个错误“无法绑定多部分标识符'D.DET_PRIMARY'。”。 D.DET_DETAILDETAIL.DET_DETAIL 我都试过了,错误是一样的。

在使用组时是否不能在 OUTPUT 子句中使用源表中的值,或者我的格式是否有错误? 如果不可能,是否有其他方法可以跟踪我处理了哪些行?

【问题讨论】:

    标签: sql sql-server sql-server-2008


    【解决方案1】:

    我知道这个问题已经有将近一年的历史了,但是如果您从 OUTPUT 中选择正确的列名,您的插入可以按照您提出的方式工作

    输出子句为我们提供了两个可能的虚拟表之一,插入或删除,取决于操作,更新操作提供两者。由于您刚刚插入的 TRN_TEMP 表中没有字段名称 DET_DATE,因此在输出语句中无效。

    INSERT INTO TRN_TEMP (TRN_TRAN_DATE, TRN_DESCRIPTION, TRN_AMT)
    OUTPUT INSERTED.TRN_TRAN_DATE, GETDATE() 
    INTO REGISTER (DET_PRIMARY_LINK, INS_DATE)
    SELECT D.DET_DATE, 'SOMETEXT', SUM(D.DET_NET)
    FROM DETAIL D
    LEFT JOIN REGISTER R ON D.DET_PRIMARY = R.DET_PRIMARY_LINK
    WHERE <MY CONDITIONS> AND R.LINE_ID IS NULL -- TO REMOVE LINES ALREADY PROCESSED
    GROUP BY D.DET_DATE
    

    【讨论】:

    • 虽然我已经实现了 MERGE 答案,但我可能会考虑改变它,因为它看起来会表现得更好,谢谢。
    【解决方案2】:

    使用MERGE 代替INSERT

    MERGE
    INTO    trn_temp d
    USING   (
            SELECT  D.DET_DATE, 'SOMETEXT' AS sometext, SUM(D.DET_NET) AS the_sum
            ...
            ) s
    ON      (1 = 0)
    WHEN NOT MATCHED THEN
    INSERT  (TRN_TRAN_DATE, TRN_DESCRIPTION, TRN_AMT)
    VALUES  (det_date, sometext, the_sum)
    OUTPUT  s.*
    

    更新:

    要解决GROUP BY 问题,请使用以下命令:

    DECLARE @tmp TABLE
            (
            det_primary INT NOT NULL PRIMARY KEY
            )
    
    MERGE
    INTO    register r
    USING   detail d
    ON      (r.det_primary_link = d.det_primary)
    WHEN NOT MATCHED THEN
    INSERT  (det_primary_link, ins_date)
    VALUES  (det_primary, GETDATE())
    OUTPUT  d.det_primary
    INTO    @tmp;
    
    INSERT
    INTO    trn_temp (trn_tran_date, trn_description, trn_amt)
    OUTPUT  INSERTED.*
    SELECT  det_date, 'sometext', SUM(det_net)
    FROM    @tmp t
    JOIN    detail d
    ON      d.det_primary = t.det_primary
    GROUP BY
            det_date
    

    【讨论】:

    • 这看起来很有趣,但我没有引用“了解什么去哪里”,看起来目标表在MERGE INTO 之后,但是你在哪里声明跟踪表?这是在OUTPUT 子句之后,例如OUTPUT s.* INTO [REGISTER]
    • @bendataclear:上面的整个OUTPUT 等价于INSERT INTO d SELECT * FROM (...) s。是的,你不能这样做OUTPUT s.* INTO register(或提供逗号分隔的列列表)。
    • 我想我有问题,我正在尝试输出 DET_PRIMARY 字段但我没有按此字段分组,可能每个值中包含 2 个或多个 ID。跨度>
    • 我希望将两个 ID 添加到跟踪表中,因为这两行都已处理完毕。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    相关资源
    最近更新 更多