web-dev-qa-db-fra.com

Équivalent MySQL de WITH dans oracle

Existe-t-il un équivalent MySQL de la clause WITH dans Oracle?

12
Neeru Sharma

Il n'y a pas. À moins que (jusqu'à ce que) on le développe (MySQL est open-source, tout le monde peut y contribuer.)

Le mot clé ANSI/ISO SQL WITH est utilisé pour définir les expressions de table communes (CTE) et simplifie les requêtes complexes avec une ou plusieurs références imbriquées. Il est disponible dans Oracle, Postgres, SQL-Server, DB2 mais pas dans MySQL.

La requête finale peut avoir des références (généralement dans la clause FROM mais elles peuvent être dans n'importe quelle autre partie) à n'importe laquelle des expressions de table communes, une ou plusieurs fois. La requête peut être écrite (sans CTE) dans MySQL en utilisant des tables dérivées mais les références doivent être faites à plusieurs reprises.

Exemple d'une requête idiote montrant toutes les personnes nées dans les années 50 et au mois de juillet et le nombre de toutes les personnes nées la même année:

WITH a AS
    ( SELECT name, birthdate, YEAR(birthdate) AS birthyear
      FROM persons
      WHERE birthdate >= '1950-01-01' AND birthdate < '1960-01-01' 
    ) 
, b AS
    ( SELECT birthyear, COUNT(*) AS cnt
      FROM a
      GROUP BY birthyear 
    ) 
SELECT a.name, a.birthdate, b.cnt AS number_of_births
FROM a JOIN b
  ON a.birthyear = b.birthyear 
WHERE MONTH(a.birthdate) = 7 ;

Dans MySQL, cela pourrait s'écrire:

SELECT a.name, a.birthdate, b.cnt AS number_of_births
FROM 
    ( SELECT name, birthdate, YEAR(birthdate) AS birthyear
      FROM persons
      WHERE birthdate >= '1950-01-01' AND birthdate < '1960-01-01' 
    ) AS a 
  JOIN 
    ( SELECT birthyear, COUNT(*) AS cnt
      FROM 
        ( SELECT name, birthdate, YEAR(birthdate) AS birthyear
          FROM persons
          WHERE birthdate >= '1950-01-01' AND birthdate < '1960-01-01' 
        ) AS aa
      GROUP BY birthyear
    ) AS b
  ON a.birthyear = b.birthyear 
WHERE MONTH(a.birthdate) = 7 ;

Notez la duplication de code pour la table dérivée a. Dans les requêtes plus complexes, le code devrait être écrit plusieurs fois.

16
ypercubeᵀᴹ

Cela fonctionnera mais c'est dommage que cela ne fournisse pas l'avantage d'utiliser la clause WITH, c'est-à-dire de ne pas exécuter la même requête plusieurs fois (avec des requêtes complexes, cela pourrait être vraiment lent et très exigeant pour le moteur de base de données; j'en ai souffert) .

Je suggérerais d'insérer chaque SELECT défini dans la clause WITH d'origine dans sa propre table temporaire, et de les utiliser dans la requête . Dans MySQL, la table temporaire se supprimera une fois la session utilisateur terminée.

ÉDITER:

Je viens de voir cette réponse dans un fil similaire qui expose clairement les 3 solutions de contournement avec MySQL :

  • Tables TEMPORAIRES
  • Tables dérivées
  • vues en ligne (ce que représente effectivement la clause WITH - elles sont interchangeables)

https://stackoverflow.com/a/1382618/290629

et un exemple de procédure MySQL qui crée et supprime les tables temporaires au cas où vous continueriez votre session et voudriez libérer ces ressources (je l'utiliserais juste comme exemple de syntaxe): https://stackoverflow.com/a/5553145/290629

2
Raúl Moreno