Équivalent MySQL de WITH dans oracle

12

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

Neeru Sharma
la source

Réponses:

16

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 WITHmot clé SQL ANSI / ISO 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 FROMclause mais elles peuvent se trouver dans n'importe quelle autre partie) à n'importe laquelle des expressions de table courantes, une ou plusieurs fois. La requête peut être écrite (sans CTE) dans MySQL à l'aide de 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.

ypercubeᵀᴹ
la source
Pour éviter la répétition (duplication de code), ne serait-il pas préférable d'utiliser des variables et des tables temporaires?
Pacerier
Je ne m'inquiéterais pas de la duplication de code mais certainement je considérerais et essayerais une version avec des tables temporaires, pour des raisons de performances.
ypercubeᵀᴹ
1
Pourquoi dites-vous que vous ne vous inquiétez pas de la duplication de code? C'est carrément désordonné et non  SEC .
Pacerier
1
@Pacerier DRY n'est pas toujours pertinent avec le code DB.
JNK
1
@Pacerier Je ne serais pas surpris si ce n'était pas le cas. Les moteurs de base de données doivent faire des suppositions éclairées sur ce qui fonctionnera le mieux tout en garantissant de retourner des résultats corrects. Les tables temporaires en général sont correctes, mais DRY entraîne des performances terribles dans les bases de données à d'autres égards, comme les fonctions définies par l'utilisateur.
JNK
2

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; je l'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)

/programming//a/1382618/2906290

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): /programming//a/ 5553145/2906290

Raúl Moreno
la source