2010-11-19 25 views
2

J'ai deux tables.T Boucle SQL sur l'insertion ou la mise à jour

Tableau A et Tableau B. Les colonnes sont identiques.

create table TableA (
    id int 
    , name varchar 
    , last datetime 
) 

create table TableB (
    id int 
    , name varchar 
    , last datetime 
) 

I m remplir la table A avec des données de masse. et je voudrais soit insérer ou mettre à jour les données dans le tableau A dans la table B.

Je voudrais prendre les données de la table A et soit insérer dans la table B si id et le nom doenst correspond ou mettre à jour si l'id et le nom correspond.

J'ai essayé un outil ETL mais le résultat était très lent. J'ai indexé sur l'identification et le nom, je voulais essayer ceci avec SQL.

je les suivantes, mais ne fonctionne pas correctement:

SELECT  @id = ID, 
     @name = name, 
     @LSDATE = LastSeen_DateTime 
      FROM DBO.A 
IF EXISTS (SELECT ID, name FROM DBO.A 
WHERE @ID = ID AND @name = Name) 

commencent - mise à jour fin autre commencer --insert fin

je suppose que je dois mettre cela dans un boucle et pas tout à fait sûr comment je peux faire cette course.

Merci.

+0

la question est de remplir le tableau A à la table B, toutes les lignes de A à B. pas une seule ligne. ça devrait être en boucle. pour chaque ligne de A, insérez-la dans B ou mettez à jour une ligne dans B. – DarthVader

Répondre

6

Son probablement plus rapide pour le faire deux déclarations une mise à jour et un insert plutôt qu'une boucle

Cette instruction met à jour toutes les lignes B en utilisant les données de A où l'ID est le même, mais le nom est différent

Mise à jour

Update 
    tableB 
SET 
    name = a.Name 
From 
    tableB a 
    INNER JOIN tableA a 
    on b.ID = a.ID 
     and A.Name <> b.Name 

Cette instruction insère toutes les lignes B dans A où l'identification n'existe pas dans un

INSERT

INSERT INTO 
    tableB 
( ID, 
    Name 
) 
SELECT 
    a.ID 
    a.Name 
FROM 
    tableA b 
WHERE 
    not exists (Select A.ID From tableB a WHERE a.ID = b.ID) 

Mise à jour (inversé à partir de A en B plutôt que B en A)

+0

la question est de remplir le tableau A à la table B, toutes les lignes de A à B. pas une seule ligne. ça devrait être en boucle. – DarthVader

+1

+1 2 instructions en vrac est la façon dont j'irais au lieu de boucle inutile et plus lent. Bien que cela ressemble à des lignes devraient être appariés sur je et nom, au lieu de simplement l'ID – AdaTheDev

+0

@ user177883 désolé, je l'ai fait inverser B en A. J'ai corrigé cela, mais ces instructions SQL font toutes les lignes pas un. –

2
DECLARE @id int 
DECLARE @name nvarchar 
DECLARE @last datetime 
DECLARE TableA_Cursor CURSOR FOR 
    select id 
      , name 
      , last 
     from TableA; 

OPEN TableA_Cursor; 

FETCH NEXT from TableA_Cursor 
INTO @id, @name, @last; 

WHILE @@FETCH_STATUS = 0 
    BEGIN 
     IF (EXISTS select 1 from TableB b where b.Id = @id) 
      update TableB 
       set Name = @name 
        , Last = @last 
     ELSE 
      insert into TableB (Id, Name, Last) 
       values (@id, @name, @last) 

     FETCH NEXT from TableA_Cursor 
     INTO @id, @name, @last 
    END 

CLOSE TableA_Cursor; 

DEALLOCATE TableA_Cursor; 

Il peut y avoir une erreur de syntaxe, en particulier autour de la condition IF, mais vous pouvez obtenir le point.

+0

+1 pour fournir une boucle même si ce n'est probablement pas le chemin à parcourir –

+0

Il ne s'agit pas d'une tâche dans laquelle vous devriez envisager d'utiliser un curseur. – HLGEM

+0

@Conrad Frix: Personnellement, si je devais faire ce que le PO demande, je serais sûr d'aller avec deux déclarations distinctes comme vous l'avez suggéré. En fait, c'est ce que j'écrivais quand j'ai reçu la nouvelle mise à jour. Après avoir vu ce que vous avez suggéré, je n'ai pas pu suivre ma solution car cela aurait été une "copie", si vous voyez ce que je veux dire. Donc, j'ai trouvé un autre avec une boucle. –

6

Si vous utilisiez SQL Server 2008 (ou Oracle ou DB2), vous pouvez utiliser une instruction de fusion.

MERGE B 
USING A AS source 
ON (B.ID = source.ID and B.Name = source.Name) 
WHEN MATCHED THEN 
    UPDATE SET Last = source.Last 
WHEN NOT MATCHED BY TARGET THEN 
    INSERT (ID, Name, Last) VALUES (source.ID, source.Name, source.Last) 

    -- the following is optional, if you remove it, add a semicolon to the end of the above line. 
    OUTPUT $action, 
    inserted.ID AS SourceID, inserted.Name AS SourceName, 
    inserted.Last AS SourceLast, 
    deleted.ID AS TargetID, deleted.Name AS TargetName, 
    deleted.Last AS TargetLast ; 

Le bit avec la « sortie $ action » affiche ce que les lignes sont mises à jour et se sont ce que les lignes se mis à jour. Mots weasel: Je reconnais que ce n'est pas exactement ce que vous cherchiez, mais puisque d'autres peuvent rechercher ce sujet, il peut être utile pour d'autres dans le futur.

+0

+1 Très agréable. Une idée de ce qu'est la perf? –

+0

@Conrad, je n'ai aucune idée de la performance. Nous utilisons 2008 dans le développement avec 2005 dans le contrôle qualité et la production, donc le code que je dois avoir la production fonctionne parfois ressemble à votre réponse et parfois comme la réponse de Will. Les serveurs de production se trouvent dans un centre de données à environ 2 km de distance et sont gérés par des gens plutôt hostiles, et ils doivent comprendre tout ce que je leur envoie avant de l'exécuter. Aucun de nos serveurs de développement et d'assurance qualité n'a de disque dur suffisamment grand pour montrer une réelle différence. – Tangurena