web-dev-qa-db-fra.com

Alternative à intersection dans MySQL

J'ai besoin d'implémenter la requête suivante dans MySQL.

(select * from emovis_reporting where (id=3 and cut_name= '全プロセス' and cut_name='恐慌') ) 
intersect
( select * from emovis_reporting where (id=3) and ( cut_name='全プロセス' or cut_name='恐慌') )

Je sais que l'intersection n'est pas dans MySQL. Il me faut donc un autre moyen… .. S'il vous plaît, guide-moi.

58
Ankur Jariwala

La variable INTERSECT"de Microsoft SQL Server renvoie toutes les valeurs distinctes renvoyées par la requête située à gauche et à droite de l'opérande INTERSECT" Ceci est différent d'une requête standard INNER JOIN ou WHERE EXISTS.

Serveur SQL

CREATE TABLE table_a (
    id INT PRIMARY KEY,
    value VARCHAR(255)
);

CREATE TABLE table_b (
    id INT PRIMARY KEY,
    value VARCHAR(255)
);

INSERT INTO table_a VALUES (1, 'A'), (2, 'B'), (3, 'B');
INSERT INTO table_b VALUES (1, 'B');

SELECT value FROM table_a
INTERSECT
SELECT value FROM table_b

value
-----
B

(1 rows affected)

MySQL

CREATE TABLE `table_a` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `value` varchar(255),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE `table_b` LIKE `table_a`;

INSERT INTO table_a VALUES (1, 'A'), (2, 'B'), (3, 'B');
INSERT INTO table_b VALUES (1, 'B');

SELECT value FROM table_a
INNER JOIN table_b
USING (value);

+-------+
| value |
+-------+
| B     |
| B     |
+-------+
2 rows in set (0.00 sec)

SELECT value FROM table_a
WHERE (value) IN
(SELECT value FROM table_b);

+-------+
| value |
+-------+
| B     |
| B     |
+-------+

Avec cette question particulière, la colonne id est impliquée, ainsi les valeurs en double ne seront pas renvoyées. Toutefois, par souci d'exhaustivité, voici une alternative à MySQL utilisant INNER JOIN et DISTINCT:

SELECT DISTINCT value FROM table_a
INNER JOIN table_b
USING (value);

+-------+
| value |
+-------+
| B     |
+-------+

Et un autre exemple utilisant WHERE ... IN et DISTINCT:

SELECT DISTINCT value FROM table_a
WHERE (value) IN
(SELECT value FROM table_b);

+-------+
| value |
+-------+
| B     |
+-------+
53
Mike

Il existe un moyen plus efficace de générer une intersection en utilisant UNION ALL et GROUP BY. Les performances sont deux fois meilleures selon mes tests sur des jeux de données volumineux.

Exemple: 

SELECT t1.value from (
  (SELECT DISTINCT value FROM table_a)
  UNION ALL 
  (SELECT DISTINCT value FROM table_b)
) AS t1 GROUP BY value HAVING count(*) >= 2;

C’est plus efficace, car avec la solution INNER JOIN, MySQL recherchera les résultats de la première requête, puis pour chaque ligne, recherchera le résultat dans la seconde requête. Avec la solution UNION ALL-GROUP BY, il interroge les résultats de la première requête, les résultats de la seconde requête, puis les regroupe tous en même temps. 

37
FBB

Votre requête renverra toujours un jeu d'enregistrements vide, car cut_name= '全プロセス' and cut_name='恐慌' ne sera jamais évalué à true.

En général, INTERSECT dans MySQL devrait être imité comme ceci:

SELECT  *
FROM    mytable m
WHERE   EXISTS
        (
        SELECT  NULL
        FROM    othertable o
        WHERE   (o.col1 = m.col1 OR (m.col1 IS NULL AND o.col1 IS NULL))
                AND (o.col2 = m.col2 OR (m.col2 IS NULL AND o.col2 IS NULL))
                AND (o.col3 = m.col3 OR (m.col3 IS NULL AND o.col3 IS NULL))
        )

Si les colonnes de vos deux tables sont marquées NOT NULL, vous pouvez omettre les parties IS NULL et réécrire la requête avec une variable IN légèrement plus efficace:

SELECT  *
FROM    mytable m
WHERE   (col1, col2, col3) IN
        (
        SELECT  col1, col2, col3
        FROM    othertable o
        )
15
Quassnoi

Je viens de le vérifier dans MySQL 5.7 et je suis vraiment surpris de constater que personne ne propose une réponse simple: NATURAL JOIN

Lorsque les tables ou (sélectionnez le résultat) ont des colonnes IDENTICAL, vous pouvez utiliser NATURAL JOIN comme moyen de rechercher l'intersection:

 enter image description here

Par exemple:

Tableau 1:

identifiant, nom, jobid

'1', 'John', '1'

'2', 'Jack', '3'

'3', 'Adam', '2'

'4', 'Bill', '6'

Tableau 2:

identifiant, nom, jobid

'1', 'John', '1'

'2', 'Jack', '3'

'3', 'Adam', '2'

'4', 'Bill', '5'

'5', 'Max', '6'

Et voici la requête:

SELECT * FROM table1 NATURAL JOIN table2;

Résultat de la requête: identifiant, nom, jobid

'1', 'John', '1'

'2', 'Jack', '3'

'3', 'Adam', '2'

3
Payam

Pour compléter, voici une autre méthode pour émuler INTERSECT. Notez que le formulaire IN (SELECT ...) suggéré dans d'autres réponses est généralement plus efficace.

Généralement pour une table appelée mytable avec une clé primaire appelée id:

SELECT id
FROM mytable AS a
INNER JOIN mytable AS b ON a.id = b.id
WHERE
(a.col1 = "someval")
AND
(b.col1 = "someotherval")

(Notez que si vous utilisez SELECT * avec cette requête, vous obtiendrez deux fois plus de colonnes que celles définies dans mytable, car INNER JOIN génère un produit cartésien )

Le INNER JOIN ici génère chaque permutation de paires de lignes de votre table. Cela signifie que chaque combinaison de lignes est générée, dans chaque ordre possible. La clause WHERE filtre ensuite le côté a de la paire, puis le côté b. Le résultat est que seules les lignes satisfaisant les deux conditions sont renvoyées, exactement comme le feraient deux requêtes à l'intersection.

1
RobM

Brisez votre problème en 2 déclarations: premièrement, vous voulez tout sélectionner si

(id=3 and cut_name= '全プロセス' and cut_name='恐慌')

est vrai . Deuxièmement, vous voulez tout sélectionner si 

(id=3) and ( cut_name='全プロセス' or cut_name='恐慌')

est vrai. Nous allons donc rejoindre les deux par OR car nous souhaitons tout sélectionner si l’un d’eux est vrai. 

select * from emovis_reporting
    where (id=3 and cut_name= '全プロセス' and cut_name='恐慌') OR
        ( (id=3) and ( cut_name='全プロセス' or cut_name='恐慌') )
0
Nikhil Pareek