Pourquoi ma requête SQL Server se comporte-t-elle différemment sur UPDATE que sur SELECT?

10

J'ai écrit une requête SQL Server qui met à jour les enregistrements pour avoir un numéro séquentiel après le partitionnement sur un champ. Lorsque je l'exécute en tant qu'instruction SELECT, tout semble parfait:

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

entrez la description de l'image ici

Cependant, lorsque je transforme la requête en commande UPDATE, elle commence à ignorer les nombres pairs:

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

entrez la description de l'image ici

J'ai essayé de me concentrer spécifiquement sur cette partie:

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

Y a-t-il un effet secondaire que j'ignore?

MISE À JOUR AVEC LES DÉFINITIONS DES TABLEAUX

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)
);
Chris Schiffhauer
la source
2
Hm, je pense que vous devriez essayer de remplacer le UPDATE [MRDFStorage]par UPDATE met le JOIN MRDFStorage ON ...avec, JOIN MRDFStorage m ON ...je crains que la MISE À JOUR puisse mettre à jour certaines lignes plus d'une fois. Lisez cet article de blog: Déconseillons la MISE À JOUR DE!
ypercubeᵀᴹ

Réponses:

4

Ne pas voir les données que vous avez rend cela un peu plus difficile, mais j'ai réussi à reproduire ce que vous voyez si vous voyez avec ceci:

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')

Le facteur clé ici est les deux lignes BallotStyles.

Vous vous joignez à BallotStylesla requête la plus interne et avec des données comme ci-dessus, vous obtiendrez des lignes en double pour chaque ligne MRDFStorage. Étant donné que vous n'utilisez aucune des colonnes, BallotStylesvous vérifiez uniquement l'existence de lignes et cela peut être fait avec une existsclause à la place et cela ne créera bien sûr pas les lignes en double.

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
Mikael Eriksson
la source