Intersect MySQL

INTERSECT MySQL

Voici une petite astuce pour faire un INTERSECT sur une base de données MySQL.

Le contexte

Pour un de mes projets je devais attribuer des articles présents simultanément dans plusieurs sites à un nouveau site.

Pour schématiser la partie de la base de données qui nous intéresse cela donne ça :

Schéma de la base MySQL - IINTERSECT
Schéma de la base MySQL

Donc j’avais besoin d’attribuer à mon nouveau site tous les articles qui étaient déjà présent dans les sites dont l’identifiant était 1, 2, 3 et 4.

La théorie

Dans ma recherche constante d’en faire le moins possible, j’ai eu un flash mémoire me rappelant la commande SQL INTERSECT. Cette commande magique permet d’effectuer des opérations entre deux requêtes (ou plus) afin d’extraire les résultats qui sont présents dans les deux requêtes.

En pratique cela donne ça :

SELECT id_article FROM `site_has_article` WHERE id_site = 1
INTERSECT
SELECT id_article FROM `site_has_article` WHERE id_site = 2

Exemple de requête permettant d’avoir les id_article qui sont à la fois dans le site dont l’id = 1 et dans le site dont l’id = 3

Fier de moi je me dis que cette tâche va en faite me prendre 2min, pour m’assurer du résultat je saisi cette requête dans mon client MySQL avant d’envisager l’insertion en masse.

Et là mes espoirs s’écroule :

Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘SELECT id_article FROM `site_has_article` WHERE id_site = 2’ at line 2 ….. Bla bla bla…

 

Bref l’erreur qui ne veut rien dire mais qui dit quand même que ta requête elle ne marche pas.

Et ouais la commande INTERSECT n’est actuellement pas supportée par MySQL, c’est moche. Il va donc falloir faire autrement.

La pratique

L’astuce est un peu bateau, elle consiste à faire des conditions avec des sous-requêtes, en gros on vérifie que les identifiants (id_article) de nos articles sont bien dans le résultat des différentes sous requêtes :

SELECT id_article FROM `site_has_article` WHERE id_site = 1
AND id_article IN
(
SELECT id_article FROM `site_has_article` WHERE id_site = 2
)
AND id_article IN
(
SELECT id_article FROM `site_has_article` WHERE id_site = 3
)
AND id_article IN
(
SELECT id_article FROM `site_has_article` WHERE id_site = 4
)

Là ça marche un peu mieux, il me restait plus qu’à mettre un petit INSERT, modifié la requête de base pour y faire apparaître l’identifiant de mon nouveau site et le tour était joué :

INSERT INTO site_has_article
SELECT 5, id_article FROM `site_has_article` WHERE id_site = 1
AND id_article IN
(
SELECT id_article FROM `site_has_article` WHERE id_site = 2
)
AND id_article IN
(
SELECT id_article FROM `site_has_article` WHERE id_site = 3
)
AND id_article IN
(
SELECT id_article FROM `site_has_article` WHERE id_site = 4
)

Au final ça m’a pris 5 minutes au lieu de 2, et un petit peu plus pour l’expliquer ici mais c’est toujours bon à savoir.

Pour aller plus loin, je vous invite à consulter le site sql.sh qui regorge d’astuces SQL.