2010-09-30 8 views
1

J'essaie de prendre en charge plusieurs bases de données pour une application que j'écris. L'application utilise principalement Hibernate, mais il est incroyablement inefficace d'itérer sur des millions de lignes et de les traiter individuellement lorsqu'une instruction DML peut les traiter en une fraction du temps. Par conséquent, pour certaines opérations, j'ai besoin de travailler sur le SQL. Je suis plus un mec MySQL, mais j'ai l'application qui fonctionne avec SQL Server et MySQL jusqu'ici. Il y a une opération qui m'a bloqué, et je n'arrive pas à comprendre comment construire certaines des requêtes de mise à jour pour Oracle. Je suis conscient que c'est probablement une question de débutant en ce qui concerne Oracle, mais j'ai dû manquer les réponses évidentes quand j'ai regardé ....Oracle: mise à jour d'une colonne de la table a à partir des valeurs d'autres tables

Voici comment j'écris ce type de requête pour MySQL:

mise à jour table1 t1, t2 = table2 fixé t1.colA t2.colA où t1.colB = t2.colB et t1.colC = t2.colC

MySQL a une belle construction où vous pouvez simplement spécifier toutes les tables avant l'instruction 'set' avec des alias, ce qui simplifie grandement le reste de l'instruction. Dans SQL Server, j'utilise update ... join pour faire la même chose.

Dans Oracle, j'ai essayé d'utiliser la syntaxe 'mise à jour table1 set colA = (select ....) où existe (select ....) syntaxe, mais cela ne fonctionne pas - il retourne un' retours de sous-requête erreur de plus d'une ligne. J'ai également essayé d'utiliser la syntaxe ... en utilisant ... sur la syntaxe, mais les erreurs avec "impossible d'obtenir un ensemble stable de lignes à partir des tables sources". Pour expliquer davantage ce que j'essaye d'accomplir, j'ai un certain nombre de requêtes à effectuer, certains d'entre eux utilisant 2 tables, certains utilisant 3 tables. Le plus complexe doit faire ceci:

mettre à jour la tableA.colB avec la valeur dans tableC.colC où tableA.colA = tableB.colA et tableB.colB = tableC.colB pour toutes les lignes correspondantes. En termes de données, cela ressemble à ceci (avant et après):

Before: 

Table A 
------- 
colA  colB 
1  NULL 
2  NULL 
3  NULL 
4  NULL 

Table B 
------- 
colA  colB 
1  A 
2  A 
3  B 
4  B 

Table C 
------- 
colB  colC 
A  15 
B  20 

After: 

Table A 
------- 
colA  colB 
1  15 
2  15 
3  20 
4  20 

J'espère que c'est assez clair. Quelqu'un peut-il expliquer comment écrire ce genre de requête DML pour Oracle? Pour les points bonus, sera-t-il le même pour PostgreSQL? :)

Répondre

2

Vous pouvez utiliser distinct ignorer plusieurs copies de la même valeur:

update TableA 
set  ColB = 
     (
     select distinct ColC 
     from TableC C 
     join TableB B 
     on  C.ColB = B.ColB 
     where B.ColA = TableA.ColA 
     ) 

Cela donne encore une erreur si plus d'une valeur appropriée se trouve.

+0

Ouais, ce n'est pas ce que je cherche, car la sous-requête * retournera plus d'une ligne. Je ne veux pas avoir à exécuter une mise à jour pour chaque valeur TableC.colC distincte. Dans Oracle et SQL Server, je peux y parvenir en une seule opération DML. Je suppose que je dis 'mise à jour TableA set colB = TableC.colB * pour chaque cas * où tableA.colA = tableB.colA et tableB.colB = tableC.colA'. –

+0

@Mick Sear: La sous-requête s'exécute pour chaque ligne de la TableA. Si elle renvoie plus d'une valeur, laquelle devrait-elle choisir de mettre à jour ColB? – Andomar

+0

OK, je le vois maintenant, après avoir exécuté la sous-sélection de manière indépendante. Merci beaucoup –

2

avant

SQL> select * from A 
     2/

      COLA  COLC 
    ---------- ---------- 
      1 
      2 
      3 
      4 

    SQL> select * from B 
     2/

      COLA C 
    ---------- - 
      1 A 
      2 A 
      3 B 
      4 B 

    SQL> select * from C 
     2/

    C  COLC 
    - ---------- 
    A   15 
    B   20 

    SQL> 

La requête

SQL> update A 
     2 set colc = (select c.colc 
     3    from c 
     4      join b on (c.colB = b.colB) 
     5    where 
     6     b.colA = A.colA) 
     7 where exists 
     8  (select null 
     9    from c 
    10      join b on (c.colB = b.colB) 
    11    where 
    12     b.colA = A.colA) 
    13/

    4 rows updated. 

    SQL> 

Après

SQL> select * from A 
     2/

      COLA  COLC 
    ---------- ---------- 
      1   15 
      2   15 
      3   20 
      4   20 

    SQL> 

Il est évident que vous avez simplifié s Quelque chose dans votre cas de test n'est donc pas représentatif de votre situation actuelle. L'élément clé est que ma requête fonctionne parce que la sous-requête renvoie une seule ligne pour chaque valeur de A.colA. Vous devez revoir vos données et établir les critères nécessaires. C'est un problème de données/logique métier, pas un problème de syntaxe.

+0

Correct. Merci pour votre réponse. Il est maintenant résolu en utilisant 'distinct' dans la sous-sélection selon la réponse d'andomar, en attendant d'autres tests. –

0

les opérations suivantes:

UPDATE table_a a 
    SET col_b = (SELECT col_c 
       FROM table_b b, 
         table_c c 
       WHERE b.col_a = a.col_a AND 
         c.col_b = b.col_b); 

Je ne disposeriez pas Postgresql sur cette machine ne peut donc pas commenter.

Partagez et appréciez.

+0

Oui, j'ai essayé cela en cours de route. Le problème est clairement avec mes données. Résolu avec l'aide d'Andomar. –

Questions connexes