2010-10-28 2 views
1

J'utilise un curseur pour parcourir une assez grande table. Pour chaque ligne, je vérifie si la valeur d'une colonne existe dans l'autre.Curseur T-SQL et mise à jour

Si la valeur existe, je voudrais augmenter la colonne de valeur dans cette autre table. Sinon, je voudrais y insérer une nouvelle ligne avec la valeur à 1.

je vérifie « si elle existe » par:

IF (SELECT COUNT(*) FROM otherTabe WHERE... > 1) 
    BEGIN 
     ... 
    END 
ELSE 
    BEGIN 
     ... 
    END 

Je ne sais pas comment cette ligne qui a été trouvé et mettre à jour la valeur. Je ne veux pas faire un autre choix.

Comment puis-je le faire efficacement?

Je suppose que la méthode de vérification décrite ci-dessus n'est pas bonne dans ce cas.

+2

Postez votre code afin que nous puissions vous suggérer une façon de faire votre mise à jour plutôt qu'un curseur. – Brad

Répondre

4

en fonction de la taille de vos données et l'état réel, vous avez deux approches fondamentales:

1) utilisent MERGE

MERGE TOP (...) INTO table1 
USING table2 ON table1.column = table2.column 
WHEN MATCHED 
THEN UPDATE SET table1.counter += 1 
WHEN NOT MATCHED SOURCE 
THEN INSERT (...) VALUES (...); 

le TOP est nécessaire parce que quand vous faites une énorme mise à jour comme celui-ci (vous mentionnez la table est « grand », grand est relatif, mais laisse supposer vraiment grand, + 100MM lignes) vous devez lot les mises à jour, sinon vous surcharger le journal des transactions avec une seule transaction gigantesque.

2) utilisez un curseur, comme vous essayez.Votre question initiale peut être facilement résolu, simplement toujours mise à jour et vérifier le nombre de lignes mises à jour:

UPDATE table 
    SET column += 1 
WHERE ...; 
IF @@ROW_COUNT = 0 
BEGIN 
    -- no match, insert new value 
    INSERT INTO (...) VALUES (...); 
END 

Notez que cette approche est dangereuse mais en raison des conditions de course: il n'y a rien pour empêcher un autre thread d'insérer la valeur simultanément, de sorte que vous pouvez vous retrouver avec des doublons ou une erreur de violation de contrainte (de préférence le dernier ...).

1

Qu'en est-il de l'instruction de mise à jour avec jointure interne pour effectuer +1, et Insérer les lignes sélectionnées qui n'existent pas dans la première table.

Fournissez le schéma des tables et les colonnes que vous souhaitez vérifier et mettre à jour pour que je puisse vous aider.

Cordialement.

+0

J'ai posté un pseudo à cet effet. – Brad

2

Ceci est juste du code de psuedo parce que je n'ai aucune idée de votre structure de table mais je pense que vous comprendrez ... fondamentalement Mettez à jour les colonnes que vous voulez alors insérez les colonnes dont vous avez besoin. Une opération de curseur semble inutile.

Update OtherTable 
    Set ColumnToIncrease = ColumnToIncrease + 1 
FROM CurrentTable Where ColumnToCheckValue is not null 

Insert Into OtherTable (ColumnToIncrease, Field1, Field2,...) 
SELECT 
    1, 
    ? 
    ? 
FROM CurrentTable Where ColumnToCheckValue is not null 
+0

+1 J'aurais dû inventer des tables x y :) –

2

Sans un échantillon, je pense que c'est le meilleur que je peux faire. Bottom line: vous n'avez pas besoin d'un curseur. UPDATE lorsqu'une correspondance existe (INNER JOIN) et INSERT lorsqu'une correspondance n'existe pas.

UPDATE otherTable 
SET IncrementingColumn = IncrementingColumn + 1 
FROM thisTable INNER JOIN otherTable ON thisTable.ID = otherTable.ID 

INSERT INTO otherTable 
(
    ID 
    , IncrementingColumn 
) 
SELECT ID, 1 
FROM thisTable 
WHERE NOT EXISTS (SELECT * 
        FROM otherTable 
        WHERE thisTable.ID = otherTable.ID) 
2

Je pense you'd be better off using a view for this - alors il est toujours à ce jour, aucun risque de tort double/triple/comptage etc:

CREATE VIEW vw_value_count AS 
    SELECT st.value, 
     COUNT(*) AS numValue 
    FROM SOME_TABLE st 
GROUP BY st.value 

Mais si vous voulez continuer à utiliser l'INSERT/UPDATE approche:

IF EXISTS(SELECT NULL 
      FROM SOMETABLE WHERE ... > 1) 
BEGIN 
    UPDATE TABLE 
     SET count = count + 1 
    WHERE value = @value 
END 
ELSE 
BEGIN 
    INSERT INTO TABLE 
    (value, count) 
    VALUES 
    (@value, 1) 
END