web-dev-qa-db-fra.com

Insertion via Oracle via la sélection dans plusieurs tables où une table peut ne pas avoir de ligne

J'ai un certain nombre de tables de valeurs de code qui contiennent un code et une description avec un long identifiant.

Je veux maintenant créer une entrée pour un type de compte qui fait référence à un certain nombre de codes, j'ai donc quelque chose comme ceci:

insert into account_type_standard (account_type_Standard_id,
tax_status_id, recipient_id)
( select account_type_standard_seq.nextval,
ts.tax_status_id, r.recipient_id
from tax_status ts, recipient r
where ts.tax_status_code = ?
and r.recipient_code = ?)

Cela récupère les valeurs appropriées des tables tax_status et destinataire si une correspondance est trouvée pour leurs codes respectifs. Malheureusement, recipient_code est nullable, et donc le? la valeur de substitution peut être nulle. Bien sûr, la jointure implicite ne renvoie pas de ligne, donc aucune ligne n'est insérée dans ma table.

J'ai essayé d'utiliser NVL sur le? et sur le r.recipient_id.

J'ai essayé de forcer une jointure externe sur le r.recipient_code =? en ajoutant (+), mais ce n'est pas une jointure explicite, Oracle n'a donc toujours pas ajouté de ligne.

Quelqu'un sait-il comment faire cela?

Je peux évidemment modifier l'instruction pour que je fasse la recherche de l'ID_cipient en externe, et avoir un? au lieu de r.recipient_id, et ne sélectionnez pas du tout dans la table des destinataires, mais je préférerais faire tout cela en 1 instruction SQL.

12
Mikezx6r

Les jointures externes ne fonctionnent pas "comme prévu" dans ce cas, car vous avez explicitement indiqué à Oracle que vous ne voulez des données que si les critères de cette table correspondent. Dans ce scénario, la jointure externe est rendue inutile.

Une solution de rechange

INSERT INTO account_type_standard 
  (account_type_Standard_id, tax_status_id, recipient_id) 
VALUES( 
  (SELECT account_type_standard_seq.nextval FROM DUAL),
  (SELECT tax_status_id FROM tax_status WHERE tax_status_code = ?), 
  (SELECT recipient_id FROM recipient WHERE recipient_code = ?)
)

[Modifier] Si vous vous attendez à plusieurs lignes d'une sous-sélection, vous pouvez ajouter ROWNUM = 1 à chaque clause where OR utilisez un agrégat tel que MAX ou MIN. Ce n'est bien sûr pas le meilleure solution pour tous les cas.

[Modifier] Par commentaire,

  (SELECT account_type_standard_seq.nextval FROM DUAL),

peut être juste

  account_type_standard_seq.nextval,
23
Greg Ogle

Une version légèrement simplifiée de la solution d'Oglester (la séquence ne nécessite pas de sélection parmi DUAL:

INSERT INTO account_type_standard   
  (account_type_Standard_id, tax_status_id, recipient_id) 
VALUES(   
  account_type_standard_seq.nextval,
  (SELECT tax_status_id FROM tax_status WHERE tax_status_code = ?),
  (SELECT recipient_id FROM recipient WHERE recipient_code = ?)
)
7
Tony Andrews

Essayer:

insert into account_type_standard (account_type_Standard_id, tax_status_id, recipient_id)
select account_type_standard_seq.nextval,
       ts.tax_status_id, 
       ( select r.recipient_id
         from recipient r
         where r.recipient_code = ?
       )
from tax_status ts
where ts.tax_status_code = ?
3
Tony Andrews

Il n'était pas clair pour moi dans la question si ts.tax_status_code est une clé primaire ou alternative ou non. Même chose avec recipient_code. Ce serait utile de savoir.

Vous pouvez gérer la possibilité que votre variable de liaison soit nulle en utilisant un OR comme suit. Vous lieriez la même chose aux deux premières variables de liaison.

Si vous êtes préoccupé par les performances, vous feriez mieux de vérifier si les valeurs que vous souhaitez lier sont nulles ou non, puis émettez une instruction SQL différente pour éviter le OU.

insert into account_type_standard 
(account_type_Standard_id, tax_status_id, recipient_id)
(
select 
   account_type_standard_seq.nextval,
   ts.tax_status_id, 
   r.recipient_id
from tax_status ts, recipient r
where (ts.tax_status_code = ? OR (ts.tax_status_code IS NULL and ? IS NULL))
and (r.recipient_code = ? OR (r.recipient_code IS NULL and ? IS NULL))
3
WW.
insert into account_type_standard (account_type_Standard_id, tax_status_id, recipient_id)
select account_type_standard_seq.nextval,
   ts.tax_status_id, 
   ( select r.recipient_id
     from recipient r
     where r.recipient_code = ?
   )
from tax_status ts
where ts.tax_status_code = ?
1
paparao