1
votes

Oracle SQL - UNION ALL renvoie des lignes même si elles n'existent pas

J'ai la requête suivante qui unit deux requêtes plus petites:

type      |      somefield     |     some_id
---------------------------------------------
Static 1  |                    |      1
Static 2  |                    |      1

Si la requête renvoie une ligne et que la requête 2 retourne une ligne, j'aurai deux lignes comme celle-ci:

type      |      somefield     |     some_id
---------------------------------------------
Static 1  |       somevalue    |      1
Static 2  |       somevalue    |      1

Quelle est la sortie que je veux. Si l'une de ces deux requêtes ne renvoie pas de ligne (ou même si les deux ne renvoient pas de ligne), aucune ligne ne sera renvoyée. Ce n'est pas ce que je veux. Je veux toujours que le 'type' et le 'some_id' reviennent même s'il n'y a pas de données. Donc, si ces deux requêtes ne contenaient aucune donnée, mon résultat attendu serait:

SELECT 'Static 1' type, somefield, some_id   
      FROM (SELECT some_id, somefield
               FROM sometable
                WHERE someothercolumn = 'Static 1'
                and someid = :id)
     UNION ALL
     SELECT 'Static 1' type, somefield, some_id   
      FROM (SELECT some_id, somefield
               FROM sometable
                WHERE someothercolumn = 'Static 2'
                and someid = :id)

J'ai essayé de UNION ALL chaque requête avec un NOT EXISTS mais de cette façon le ' some_id 'devrait être une valeur arbitraire codée en dur. Ce que je veux, c'est qu'il affiche toujours la variable de liaison passée, :id.


2 commentaires

Montrez-nous quelques exemples de données de table et le résultat attendu. (Jetez un œil à l ' exemple reproductible minimal .)


utilisez IS NULL si rien n'est renvoyé, ou une expression pour le forcer.


3 Réponses :


1
votes

Une option consiste à sélectionner la ligne factice d'en-tête avec le NOT EXISTS pour décider de la retourner (oui, si la ligne réelle du tableau n'existe pas; non, si la ligne existe).

Regardez l'exemple: voir la ligne # 4 qui est commentée pour le moment ce qui signifie que votre table ne contient pas de ligne qui satisfait à cette condition, donc un en-tête factice / em> sera affiché:

SQL> with test (type, some_id) as
  2    (select 'Static 99', 44 from dual union all
  3     select 'Static 2' , 57 from dual
  4     union all select 'Static 1', 66 from dual   -- toggle to see the difference
  5    )
  6  -- This is a header which won't be displayed if table contains
  7  -- type = 'Static 1' and some_id = 66
  8  select 'Static 1' type, 1 some_id
  9  from dual
 10  where not exists (select null
 11                    from test
 12                    where type = 'Static 1'
 13                      and some_id = 66
 14                   )
 15  union all
 16  -- This returns actual rows (if they exist)
 17  select 'Static 1' type, some_id
 18  from (select some_id
 19        from test
 20        where type = 'Static 1'
 21          and some_id = 66
 22       );

TYPE        SOME_ID
-------- ----------
Static 1         66

SQL>

Cependant, s'il existe (ligne n ° 4 non commentée), alors les données réelles sont affichées, sans cette ligne d'en-tête factice: p >

SQL> with test (type, some_id) as
  2    (select 'Static 99', 44 from dual union all
  3     select 'Static 2' , 57 from dual
  4     --union all select 'Static 1', 66 from dual   -- toggle to see the difference
  5    )
  6  -- This is a header which won't be displayed if table contains
  7  -- type = 'Static 1' and some_id = 66
  8  select 'Static 1' type, 1 some_id
  9  from dual
 10  where not exists (select null
 11                    from test
 12                    where type = 'Static 1'
 13                      and some_id = 66
 14                   )
 15  union all
 16  -- This returns actual rows (if they exist)
 17  select 'Static 1' type, some_id
 18  from (select some_id
 19        from test
 20        where type = 'Static 1'
 21          and some_id = 66
 22       );

TYPE        SOME_ID
-------- ----------
Static 1          1

SQL>

Si cela fait ce que vous voulez, appliquez le même principe à la deuxième sélection que vous utilisez (à Statique 2 ) .


0 commentaires

1
votes

Peut-être quelque chose comme:

WITH a AS (/* subquery 1 */),
     b AS (/* subquery 2 */)
SELECT (SELECT a.col1 FROM a),
       (SELECT a.col2 FROM a),
       ...
       FROM dual
UNION ALL
SELECT (SELECT b.col1 FROM b),
       (SELECT b.col2 FROM b),
       ...
       FROM dual


2 commentaires

J'obtiens que VALUES (1) n'est pas une table valide


Oh, vous utilisez Oracle, qui n'implémente pas la norme là-bas. Utilisez alors dual , comme dans ma réponse mise à jour.



1
votes

Créez un CTE pour votre requête et un autre CTE pour les 2 lignes supplémentaires et utilisez UNION ALL et NOT EXISTS comme ceci:

WITH 
  cte1 AS (
    <your query here>
  ),
  cte2 AS (
    SELECT 'Static 1' type, null somefield, :id FROM dual
    UNION ALL
    SELECT 'Static 2' type, null somefield, :id FROM dual 
  )
SELECT * FROM cte1
UNION ALL
SELECT * FROM cte2
WHERE NOT EXISTS (SELECT 1 FROM cte1)


2 commentaires

J'ai essayé cette approche. Cela semble toujours être exactement le même que j'avais auparavant. Qu'il ne renvoie pas les 2 lignes attendues lorsqu'une ou les deux requêtes ne retourne aucune ligne. Donc, si une requête retourne une ligne, elle retournera cela, si aucune ne retourne, elle ne retournera aucune ligne au lieu des 2 lignes voulues.


Ce code renverra ces 2 lignes uniquement si vos deux requêtes ne renvoient aucune ligne. Si vous pouviez créer un violon avec des exemples de données, je peux le tester.