2009-04-09 8 views
1

Ich habe eine Tabelle mit einigen doppelten Einträgen. Ich muss alle bis auf eine ablegen und dann diese neueste aktualisieren. Ich habe versucht, mit einer temporären Tabelle und einer while-Anweisung, auf diese Weise:Wie kann ich eine Datenbank massiv aktualisieren?

CREATE TABLE #tmp_ImportedData_GenericData 
(
    Id int identity(1,1), 
    tmpCode varchar(255) NULL, 
    tmpAlpha3Code varchar(50) NULL, 
    tmpRelatedYear int NOT NULL, 
    tmpPreviousValue varchar(255) NULL, 
    tmpGrowthRate varchar(255) NULL 
) 

INSERT INTO #tmp_ImportedData_GenericData 
SELECT 
    MCS_ImportedData_GenericData.Code, 
MCS_ImportedData_GenericData.Alpha3Code, 
MCS_ImportedData_GenericData.RelatedYear, 
MCS_ImportedData_GenericData.PreviousValue, 
MCS_ImportedData_GenericData.GrowthRate 
FROM MCS_ImportedData_GenericData 
INNER JOIN 
(
    SELECT CODE, ALPHA3CODE, RELATEDYEAR, COUNT(*) AS NUMROWS 
    FROM MCS_ImportedData_GenericData AS M 
    GROUP BY M.CODE, M.ALPHA3CODE, M.RELATEDYEAR 
    HAVING count(*) > 1 
) AS M2 ON MCS_ImportedData_GenericData.CODE = M2.CODE 
    AND MCS_ImportedData_GenericData.ALPHA3CODE = M2.ALPHA3CODE 
    AND MCS_ImportedData_GenericData.RELATEDYEAR = M2.RELATEDYEAR 
WHERE 
(MCS_ImportedData_GenericData.PreviousValue <> 'INDEFINITO') 

-- SELECT * from #tmp_ImportedData_GenericData 
-- DROP TABLE #tmp_ImportedData_GenericData 

DECLARE @counter int 
DECLARE @rowsCount int 

SET @counter = 1 

SELECT @rowsCount = count(*) from #tmp_ImportedData_GenericData 
-- PRINT @rowsCount 

WHILE @counter < @rowsCount 
BEGIN 
    SELECT 
     @Code = tmpCode, 
     @Alpha3Code = tmpAlpha3Code, 
     @RelatedYear = tmpRelatedYear, 
     @OldValue = tmpPreviousValue, 
     @GrowthRate = tmpGrowthRate 
    FROM 
     #tmp_ImportedData_GenericData 
    WHERE 
     Id = @counter 

    DELETE FROM MCS_ImportedData_GenericData 
    WHERE 
     Code = @Code 
     AND Alpha3Code = @Alpha3Code 
     AND RelatedYear = @RelatedYear 
     AND PreviousValue <> 'INDEFINITO' OR PreviousValue IS NULL 

    UPDATE 
     MCS_ImportedData_GenericData 
     SET 
      PreviousValue = @OldValue, GrowthRate = @GrowthRate 
    WHERE 
     Code = @Code 
     AND Alpha3Code = @Alpha3Code 
     AND RelatedYear = @RelatedYear 
     AND MCS_ImportedData_GenericData.PreviousValue ='INDEFINITO' 

    SET @counter = @counter + 1 
END 

aber es dauert zu langer Zeit, auch wenn es nur 20.000 bis 30.000 Zeilen zu verarbeiten.

Hat jemand einige Vorschläge, um die Leistung zu verbessern?

Vielen Dank im Voraus!

+0

Verwenden Sie keine Schleife! –

+0

Vereinbart, während TSQL Schleifen enthält, ist es nicht für sie optimiert. – MatBailie

+0

Wenn dies Microsoft SQL Server-spezifisch ist, bitte als sqlserver markieren. Nun, entweder das oder ich gebe auf und ignoriere einfach Tag SQL. – Thomas

Antwort

3
WITH q AS (
     SELECT m.*, ROW_NUMBER() OVER (PARTITION BY CODE, ALPHA3CODE, RELATEDYEAR ORDER BY CASE WHEN PreviousValue = 'INDEFINITO' THEN 1 ELSE 0 END) 
     FROM MCS_ImportedData_GenericData m 
     WHERE PreviousValue <> 'INDEFINITO' 
     ) 
DELETE 
FROM q 
WHERE rn > 1 
1

Quassnoi Antwort verwendet SQL Server 2005+ Syntax, so hatte ich dachte, dass ich wert mit etwas allgemeineren ...

in meinem tuppence setzen Zuerst alle Duplikate zu löschen, aber nicht die " Original ", benötigen Sie eine Möglichkeit, die doppelten Datensätze voneinander zu unterscheiden. (Der ROW_NUMBER() - Teil von Quassnois Antwort)

Es scheint, dass in Ihrem Fall die Quelldaten keine Identitätsspalte haben (Sie erstellen eine in der temporären Tabelle). Wenn das der Fall ist, gibt es zwei Möglichkeiten, die mir in den Sinn kommen: 1. Fügen Sie den Daten die Identitätsspalte hinzu, entfernen Sie dann die Duplikate
2. Erstellen Sie einen "de-duped" Datensatz, löschen Sie alles aus das Original, und legen Sie die de-deduped Daten wieder in die ursprünglichen

Option 1 könnte so etwas wie ... (Mit dem neu geschaffenen ID-Feld)

DELETE 
    [data] 
FROM 
    MCS_ImportedData_GenericData AS [data] 
WHERE 
    id > (
     SELECT 
      MIN(id) 
     FROM 
      MCS_ImportedData_GenericData 
     WHERE 
      CODE = [data].CODE 
      AND ALPHA3CODE = [data].ALPHA3CODE 
      AND RELATEDYEAR = [data].RELATEDYEAR 
     ) 

OR ...

seine
DELETE 
    [data] 
FROM 
    MCS_ImportedData_GenericData AS [data] 
INNER JOIN 
(
    SELECT 
     MIN(id) AS [id], 
     CODE, 
     ALPHA3CODE, 
     RELATEDYEAR 
    FROM 
     MCS_ImportedData_GenericData 
    GROUP BY 
     CODE, 
     ALPHA3CODE, 
     RELATEDYEAR 
) 
AS [original] 
    ON [original].CODE = [data].CODE 
    AND [original].ALPHA3CODE = [data].ALPHA3CODE 
    AND [original].RELATEDYEAR = [data].RELATEDYEAR 
    AND [original].id <> [data].id 
0

Ich verstehe verwendete Syntax nicht perfekt genug, um eine genaue Antwort zu posten, aber hier ist ein Ansatz.

Zeilen identifizieren Sie erhalten wollen (z. B. Auswahlwert, ... aus .. wo ...)

die Logik-Update durchführen, während die Identifizierung (z. B. Auswahlwert + 1 ... aus .. . wo ...)

Einfügen in eine neue Tabelle einfügen.

Drop the original, umbenennen neu original, neu erstellen alle Zuschüsse/Synonyme/Trigger/Indizes/FKs/... (oder das Original gestutzt und wählen Sie Einfügen aus dem neuen)

Offensichtlich ist dies eine prety groß hat Overhead, aber wenn Sie Millionen von Zeilen aktualisieren/löschen möchten, wird es der schnellste Weg sein.

Verwandte Themen