Чому мій запит на SQL Server поводиться інакше в UPDATE, ніж у SELECT?


10

Я написав запит SQL Server, який оновлює записи, щоб вони мали послідовний номер після розділення на полі. Коли я запускаю це як оператор SELECT, все виглядає чудово:

DECLARE @RunDetailID INT = 448
DECLARE @JobDetailID INT

SELECT @JobDetailID = [JobDetailID] FROM [RunDetails] WHERE [RunDetailID] = @RunDetailID

SELECT
    [OrderedRecords].[NewSeq9],
    RIGHT([OrderedRecords].[NewSeq9], 4)
FROM
    (
        SELECT
            [Records].*,
            [Records].[SortField] + RIGHT('0000' + CAST(ROW_NUMBER() OVER(PARTITION BY [Records].[SortField] ORDER BY [Records].[RunDetailID], [Records].[SortField], [Records].[PieceID]) AS VARCHAR), 4) NewSeq9
        FROM
        (
            SELECT
                [MRDFStorageID], 
                [RunDetailID], 
                [SortField], 
                [PieceID], 
                [Seq9], 
                [BallotType]
            FROM
                [MRDFStorage]
                    JOIN [BallotStyles] ON [MRDFStorage].[SortField] = [BallotStyles].[Style] and [BallotStyles].[JobDetailID] = @JobDetailID
            WHERE
                [RunDetailID] IN (SELECT [RunDetailID] FROM [RunDetails] WHERE [JobDetailID] = @JobDetailID AND [RunStatusID] <> 0)
        ) Records
    ) OrderedRecords 
        JOIN MRDFStorage ON [OrderedRecords].[MRDFStorageID] = [MRDFStorage].[MRDFStorageID]
WHERE
    [MRDFStorage].[RunDetailID] = @RunDetailID

введіть тут опис зображення

Однак коли я вношу запит у команду UPDATE, вона починає пропускати парні числа:

DECLARE @RunDetailID INT = 448
DECLARE @JobDetailID INT 

SELECT @JobDetailID = [JobDetailID] FROM [RunDetails] WHERE [RunDetailID] = @RunDetailID

UPDATE
    [MRDFStorage]
SET
    [Seq9] = [OrderedRecords].[NewSeq9],
    [Overlay1] = [OrderedRecords].[NewSeq9],
    [Overlay10] = RIGHT([OrderedRecords].[NewSeq9], 4)
FROM
    (
        SELECT
            [Records].*,
            [Records].[SortField] + RIGHT('0000' + CAST(ROW_NUMBER() OVER(PARTITION BY [Records].[SortField] ORDER BY [Records].[RunDetailID], [Records].[SortField], [Records].[PieceID]) AS VARCHAR), 4) NewSeq9
        FROM
        (
            SELECT
                [MRDFStorageID], 
                [RunDetailID], 
                [SortField], 
                [PieceID], 
                [Seq9], 
                [BallotType], 
                CAST([SpecialProcessing] as Int) StartCount
            FROM
                [MRDFStorage]
                    JOIN [BallotStyles] ON [MRDFStorage].[SortField] = [BallotStyles].[Style] and [BallotStyles].[JobDetailID] = @JobDetailID
            WHERE
                [RunDetailID] IN (SELECT [RunDetailID] FROM [RunDetails] WHERE [JobDetailID] = @JobDetailID AND [RunStatusID] <> 0)
        ) Records
    ) OrderedRecords 
        JOIN MRDFStorage ON [OrderedRecords].[MRDFStorageID] = [MRDFStorage].[MRDFStorageID]
WHERE
    [MRDFStorage].[RunDetailID] = @RunDetailID

введіть тут опис зображення

Я спробував спеціально зосередитись на цій порції:

[Records].[SortField] + RIGHT('0000' + CAST(ROW_NUMBER() OVER(PARTITION BY [Records].[SortField] ORDER BY [Records].[RunDetailID], [Records].[SortField], [Records].[PieceID]) AS VARCHAR), 4) NewSeq9

Чи є якийсь побічний ефект, який я не знаю?

ОНОВЛЕННЯ З ТАБЛИЧНИМ ВИЗНАЧЕННЯМ

CREATE TABLE [dbo].[MRDFStorage] (
    [MRDFStorageID]           INT            IDENTITY (1, 1) NOT NULL,
    [RunDetailID]             INT            NOT NULL,
    [PieceID]                 VARCHAR (15)   NULL,
    [SortField]               VARCHAR (20)   NULL,
    [BallotType]              VARCHAR (100)  NULL,
    [Seq9]                    VARCHAR (15)   NULL,
    CONSTRAINT [PK_MRDFStorage] PRIMARY KEY CLUSTERED ([MRDFStorageID] ASC),
    CONSTRAINT [FK_MRDFStorage_RunDetails] FOREIGN KEY ([RunDetailID]) REFERENCES [dbo].[RunDetails] ([RunDetailID])
);

CREATE TABLE [dbo].[BallotStyles] (
    [BallotStyleID]     INT           IDENTITY (1, 1) NOT NULL,
    [JobDetailID]       INT           NOT NULL,
    [Style]             VARCHAR (20)  NOT NULL,
    CONSTRAINT [PK_BallotStyles] PRIMARY KEY CLUSTERED ([BallotStyleID] ASC)
);

CREATE TABLE [dbo].[RunDetails] (
    [RunDetailID]        INT            IDENTITY (1, 1) NOT NULL,
    [JobDetailID]        INT            NOT NULL,
    CONSTRAINT [PK_RunDetails] PRIMARY KEY CLUSTERED ([RunDetailID] ASC)
);

2
Хм, я думаю , ви повинні спробувати заміни UPDATE [MRDFStorage]з UPDATE mі JOIN MRDFStorage ON ...з JOIN MRDFStorage m ON ...я боюся , що , може бути , UPDATE оновлює деякі рядки більше , ніж один раз. Прочитайте цю публікацію в блозі: Давайте зневажимо ОНОВЛЕННЯ ВІД!
ypercubeᵀᴹ

Відповіді:


4

Якщо не бачити отриманих вами даних, це трохи складніше, але мені вдалося відтворити те, що ви бачите, якщо ви бачите це:

insert into RunDetails(RunDetailID, JobDetailID) values(448, 1)
insert into MRDFStorage(RunDetailID, SortField) values(448, 'S1')
insert into MRDFStorage(RunDetailID, SortField) values(448, 'S1')
insert into MRDFStorage(RunDetailID, SortField) values(448, 'S1')
insert into BallotStyles(JobDetailID, Style) values(1, 'S1')
insert into BallotStyles(JobDetailID, Style) values(1, 'S1')

Ключовим фактором тут є два рядки BallotStyles.

Ви приєднуєтесь до BallotStylesвнутрішнього запиту, і з такими даними, як вище, ви отримаєте повторювані рядки для кожного рядка в MRDFStorage. Оскільки ви не використовуєте жоден із стовпців, BallotStylesви перевіряєте лише наявність рядків, і це можна зробити existsзамість цього пункту, і це, звичайно, не створюватиме повторювані рядки.

UPDATE
    [MRDFStorage]
SET
    [Seq9] = [OrderedRecords].[NewSeq9]
FROM
    (
        SELECT
            MRDFStorageID,
            [Records].[SortField] + RIGHT('0000' + CAST(ROW_NUMBER() OVER(PARTITION BY [Records].[SortField] ORDER BY [Records].[RunDetailID], [Records].[SortField], [Records].[PieceID]) AS VARCHAR), 4) NewSeq9
        FROM
        (
            SELECT
                M.[MRDFStorageID], 
                M.[RunDetailID], 
                M.[SortField], 
                M.[PieceID], 
                M.[BallotType]
            FROM
                [MRDFStorage] as M
-- Remove this join
--                    JOIN [BallotStyles] ON M.[SortField] = [BallotStyles].[Style] and [BallotStyles].[JobDetailID] = @JobDetailID
            WHERE
                [RunDetailID] IN (SELECT [RunDetailID] FROM [RunDetails] WHERE [JobDetailID] = @JobDetailID) and
-- Add this exists check instead of the join
                EXISTS (
                       SELECT *
                       FROM BallotStyles AS BS
                       WHERE M.SortField = BS.Style and
                             BS.JobDetailID = @JobDetailID
                       )
        ) Records
    ) OrderedRecords 
        JOIN MRDFStorage ON [OrderedRecords].[MRDFStorageID] = [MRDFStorage].[MRDFStorageID]
WHERE
    [MRDFStorage].[RunDetailID] = @RunDetailID
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.