【问题标题】:SQL Server INSERT statement's OUTPUT clause not returning identity valuesSQL Server INSERT 语句的 OUTPUT 子句不返回标识值
【发布时间】:2016-08-09 14:28:22
【问题描述】:

在 SQL Server 2008 R2 数据库服务器上,我尝试将数据插入表中,但 INSERT 语句的 OUTPUT 子句只为表的 Identity 列返回零。下面的 INSERT 语句是一个更大的脚本的一部分,其中许多语句都包装在一个事务中。

声明如下:

INSERT INTO CountryDivisions (
    [CountryID]
    , [ParentDivisionID]
    , [DivisionCodeISO]
    , [DivisionCodeShort]
    , [DivisionType]
)
    OUTPUT
        inserted.[CountryDivisionID] -- Identity column, returning only zeros!
        , inserted.[CountryID]
        , inserted.[ParentDivisionID]
        , inserted.[DivisionCodeISO]
        , inserted.[DivisionCodeShort]
        , inserted.[DivisionType]
        INTO @NewCountryDivisions
    SELECT
        dc.[CountryID]
        , null
        , COALESCE(mcd.DependentDivisionCodeISO, mcd.ParentCountryAlpha2Code + '-' + mcd.DependentCountryAlpha2Code)
        , mcd.DependentCountryAlpha2Code
        , mcd.DependentDivisionType
    FROM
        @MoreCountryData AS mcd
        JOIN Countries AS dc
            ON dc.Alpha2Code = mcd.DependentCountryAlpha2Code
    WHERE
        NOT EXISTS (
            SELECT *
            FROM CountryDivisions AS cd2
            WHERE
                cd2.[CountryID] = dc.[CountryID]
                AND cd2.[DivisionCodeShort] = mcd.DependentCountryAlpha2Code
        )

这是我从@NewCountryDivisions 中选择时看到的:

这是表的定义:

CREATE TABLE [dbo].[CountryDivisions](
    [CountryDivisionID] [int] IDENTITY(1,1) NOT NULL, -- identity column which is only returning zeros!
    [CountryID] [int] NOT NULL,
    [ParentDivisionID] [int] NULL,
    [DivisionCodeISO] [nvarchar](10) NULL,
    [DivisionCodeShort] [nvarchar](10) NULL,
    [DivisionType] [nvarchar](150) NULL,
    [LastUpdatedBy] [sysname] NOT NULL DEFAULT (user_name()),
    [LastUpdatedDateTime] [datetime] NOT NULL DEFAULT (getutcdate()),
 CONSTRAINT [PK_CountryDivisions_CountryDivisionID] PRIMARY KEY NONCLUSTERED 
(
    [CountryDivisionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)

我正在使用INSTEAD OF 触发器来更新两个LastUpdated... 列。我是编写触发器的新手,虽然我不认为这些会导致问题,但以防万一,这里是它们的定义:

CREATE TRIGGER [dbo].[CountryDivisions_InsertAudit]
    ON [dbo].[CountryDivisions]
    INSTEAD OF INSERT
    AS
    BEGIN
        SET NoCount ON

        INSERT INTO [dbo].[CountryDivisions] (
            -- I am assuming that SQL Server will apply the IDENTITY process to the [CountryDivisionID] column, so I am not inserting it myself.
            [CountryID]
            , [ParentDivisionID]
            , [DivisionCodeISO]
            , [DivisionCodeShort]
            , [DivisionType]
            , [LastUpdatedBy]
            , [LastUpdatedDateTime]
        )
            SELECT
                i.CountryID
                , i.ParentDivisionID
                , i.DivisionCodeISO
                , i.DivisionCodeShort
                , i.DivisionType
                , COALESCE(NULLIF(LTRIM(RTRIM(i.[LastUpdatedBy])), ''), USER_NAME())
                , COALESCE(i.[LastUpdatedDateTime], GETUTCDATE())
            FROM
                inserted AS i

    END

CREATE TRIGGER [dbo].[CountryDivisions_UpdatAudit]
    ON [dbo].[CountryDivisions]
    INSTEAD OF UPDATE
    AS
    BEGIN
        SET NoCount ON

        UPDATE [dbo].[CountryDivisions]
            SET
                CountryID = i.CountryID
                , ParentDivisionID = i.ParentDivisionID
                , DivisionCodeISO = i.DivisionCodeISO
                , DivisionCodeShort = i.DivisionCodeShort
                , DivisionType = i.DivisionType
                , LastUpdatedBy = COALESCE(NULLIF(LTRIM(RTRIM(i.[LastUpdatedBy])), ''), USER_NAME())
                , LastUpdatedDateTime = COALESCE(i.[LastUpdatedDateTime], GETUTCDATE())
            FROM
                [dbo].[CountryDivisions] AS cd
                JOIN inserted AS i
                    JOIN deleted AS d
                        ON d.CountryDivisionID = i.CountryDivisionID
                    ON cd.CountryDivisionID = i.CountryDivisionID
            WHERE
                -- only update records that have actually been updated.
                i.CountryID <> d.CountryID
                OR ISNULL(i.ParentDivisionID, -1) <> ISNULL(d.ParentDivisionID, -1)
                OR ISNULL(i.DivisionCodeISO, '') <> ISNULL(d.DivisionCodeISO, '')
                OR ISNULL(i.DivisionCodeShort, '') <> ISNULL(d.DivisionCodeShort, '')
                OR (
                    ISNULL(i.LastUpdatedBy, '') <> ISNULL(d.LastUpdatedBy, '')
                    AND UPDATE(LastUpdatedBy)
                )
                OR (
                    ISNULL(i.LastUpdatedDateTime, '1900-01-01') <> ISNULL(d.LastUpdatedDateTime, '1900-01-01')
                    AND UPDATE(LastUpdatedDateTime)
                )
    END

【问题讨论】:

    标签: sql-server triggers sql-server-2008-r2 output-clause


    【解决方案1】:

    看来是我的触发器出了问题!

    根据某人在另一个 Stack Overflow 线程中发表的评论,INSERT 语句中的 OUTPUT 子句在基础表包含 INSTEAD OF 触发器的情况下将只为使用 IDENTITY(seed, increment) 函数定义的任何列返回零。

    为了解决这个问题,我将触发器改写为AFTER 触发器。这也让我可以将两个触发器合并为一个触发器。

    CREATE TRIGGER [dbo].[CountryDivisions_Audit]
        ON [dbo].[CountryDivisions]
        AFTER INSERT, UPDATE
        AS
        BEGIN
            SET NoCount ON
    
            -- prevent recursion
            If TRIGGER_NESTLEVEL() > 1 RETURN
    
            UPDATE cdan
                SET
                    [LastUpdatedBy] = USER_NAME()
                    , [LastUpdatedDateTime] = GETUTCDATE()
                FROM
                    [dbo].[CountryDivisions] AS cdan
                    JOIN inserted AS i
                        LEFT JOIN deleted AS d
                            ON d.[CountryDivisionID] = i.[CountryDivisionID]
                        ON i.[CountryDivisionID] = cdan.[CountryDivisionID]
                WHERE
                    -- only update records that have actually been updated.
                    ISNULL(i.[CountryDivisionID], -1) <> ISNULL(d.[CountryDivisionID], -1)
                    OR ISNULL(i.[ParentDivisionID], -1) <> ISNULL(d.[ParentDivisionID], -1)
                    OR ISNULL(i.[DivisionCodeISO], '') <> ISNULL(d.[DivisionCodeISO], '')
                    OR ISNULL(i.[DivisionCodeShort], '') <> ISNULL(d.[DivisionCodeShort], '')
                    OR ISNULL(i.[DivisionType], '') <> ISNULL(d.[DivisionType], '')
                    OR (
                        ISNULL(i.LastUpdatedBy, '') <> ISNULL(d.LastUpdatedBy, '')
                        AND UPDATE(LastUpdatedBy)
                    )
                    OR (
                        ISNULL(i.LastUpdatedDateTime, '1900-01-01') <> ISNULL(d.LastUpdatedDateTime, '1900-01-01')
                        AND UPDATE(LastUpdatedDateTime)
                    )
        END
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-02
      • 2020-04-02
      • 1970-01-01
      • 2013-03-12
      • 1970-01-01
      相关资源
      最近更新 更多