web-dev-qa-db-fra.com

Comment puis-je afficher deux fois chaque ligne stockée sans utiliser UNION ALL ou une table temporaire?

La table appropriée, nommée emp, contient les données suivantes:

CREATE TEMPORARY TABLE emp AS
SELECT * FROM ( VALUES (1,'A'), (2,'B'), (3,'C') );

 ID  Name
 --  ----
 1    A
 2    B
 3    C

Et la sortie ou l'ensemble de résultats de l'opération de manipulation de données doit être comme indiqué ci-dessous:

 ID  Name 
 --  ----
 1    A
 1    A 
 2    B
 2    B
 3    C
 3    C

Exigences

La sortie doit être obtenue en respectant les conditions suivantes:

  • Aucune utilisation de l'opérateur UNION ALL en association avec les instructions SELECT utilisées
  • Pas d'utilisation de table (s) temporaire (s)
  • Pas d'utilisation d'une opération UPDATE sur la table existante

Remarque : Ce scénario m'a été présenté par un intervieweur.

7
Anup
SELECT ta.id, ta.name
FROM emp ta 
CROSS JOIN ( VALUES (1), (2) ) tb (id) ;
16
paparazzo

Une façon serait

SELECT COALESCE(a.id, b.id) AS id,
       COALESCE(a.name, b.name) AS name
FROM emp a 
     FULL OUTER JOIN emp b ON 1=0
ORDER BY id;
10
Martin Smith

Trois façons de plus.

Semblable à la réponse de Paparazzi, en utilisant qu'une jointure NATURAL devient une jointure CROSS lorsqu'il n'y a pas de colonne commune:

SELECT e.id, e.name
FROM emp AS e 
  NATURAL JOIN
    (VALUES (1), (2)) AS c (i) ;

Un autre qui utilise UNION DISTINCT et une colonne supplémentaire pour éviter la suppression des doublons:

SELECT id, name
FROM 
    ( SELECT id, name, 1 AS d
      FROM emp
      UNION 
      SELECT id, name, 2
      FROM emp
    ) AS t ; 

Abus GROUPING SETS. Il y a quelque chose d'inattendu et d'ironique dans cette méthode car elle utilise GROUP BY pour multiplier le nombre de lignes renvoyées:

SELECT id, name
FROM emp 
GROUP BY GROUPING SETS ((id, name), (id, name)) ;
9
ypercubeᵀᴹ

Une autre solution qui niquement fonctionne avec les données d'exemple fournies.

select e1.*
from emp e1
  join emp e2 on e1.id <> i2.id;

Si l'exigence ou les données d'exemple n'étaient que légèrement différentes, cela ne fonctionnerait pas. Mais l'exigence de doubler le nombre de lignes correspond aux exemples de données qui contiennent exactement deux ID différents pour chaque ID. S'il y avait 4 identifiants différents, cela ne fonctionnerait pas.

5

La seule chose dont vous avez vraiment besoin est une jointure croisée avec une table à deux lignes. Vous pouvez utiliser celui que vous avez déjà dedans.

select e1.*
from emp e1
  cross join (select 1 from emp limit 2) tmp;

http://sqlfiddle.com/#!9/15057/ - utilise une table temporaire implicite, elle pourrait donc également être interdite.

select e1.*
from emp e1
  join emp e2 on e2.id IN (1, 2)
order by e1.id;

http://sqlfiddle.com/#!9/15057/6 - vous choisissez simplement deux lignes en utilisant la condition IN () et les utilisez pour générer les doublons.

1
jkavalik

Si vous utilisez PostgreSQL, mettez un SET RETURN FUNCTION dans la clause ORDER BY.

CREATE TABLE foo AS
SELECT *
FROM ( VALUES (1,'A'),(2,'B'),(3,'C') ) AS x(id,name);

Et alors

SELECT id,name
FROM foo
ORDER BY 1, generate_series(1,2);

 id | name 
----+------
  1 | A
  1 | A
  2 | B
  2 | B
  3 | C
  3 | C

Il n'est pas nécessaire que ce soit generate_series, Vous pouvez également unnest('{1,2}'::int[]), et vous pouvez également le faire dans la liste de sélection (sauf que vous obtiendrez la série en sortie).

0
Evan Carroll