Clause MySQL «WITH»

98

J'essaye d'utiliser MySQL pour créer une vue avec la clause "WITH"

WITH authorRating(aname, rating) AS
   SELECT aname, AVG(quantity)
   FROM book
   GROUP BY aname

Mais il ne semble pas que MySQL le prenne en charge.

Je pensais que c'était assez standard et je suis sûr qu'Oracle prend en charge cela. Est-il possible de forcer MySQL à utiliser la clause "WITH"? Je l'ai essayé avec le moteur MyISAM et innoDB. Les deux ne fonctionnent pas.

shA.t
la source

Réponses:

109

Mise à jour: MySQL 8.0 obtient enfin la fonctionnalité d'expressions de table courantes, y compris les CTE récursifs.

Voici un blog l'annonçant: http://mysqlserverteam.com/mysql-8-0-labs-recursive-common-table-expressions-in-mysql-ctes/

Voici ma réponse précédente, que j'ai écrite à l'origine en 2008.


MySQL 5.x ne prend pas en charge les requêtes utilisant la WITHsyntaxe définie dans SQL-99, également appelée Expressions de table communes.

Il s'agit d'une demande de fonctionnalité pour MySQL depuis janvier 2006: http://bugs.mysql.com/bug.php?id=16244

Autres produits SGBDR prenant en charge les expressions de table courantes:

Bill Karwin
la source
1
SQLite prend en charge la clause WITH à partir de la version 3.8.3 publiée le 03/02/2014.
Martijn le
J'ai ajouté H2 et Firebird à la liste.
a_horse_with_no_name
2
@BillKarwin: Je ne pense pas que MySQL implémentera jamais une fonctionnalité de SGBD moderne (vérifier les contraintes, la fonction de fenêtre, l'index sur les expressions, l'index partiel, les contraintes différées ...).
a_horse_with_no_name
2
@a_horse_with_no_name, ils semblent accorder une priorité beaucoup plus élevée à l'évolutivité. Ils se sont depuis longtemps attachés à rendre leurs internes plus évolutifs, pour tirer parti du matériel moderne. Mais je pense qu'ils ont négligé les fonctionnalités SQL.
Bill Karwin le
1
@BlakeMcBride, vous vous trompez, votre commentaire est FUD et n'a aucun fondement en fait. Oracle possède également d'autres produits de base de données qui font des choses qu'Oracle DB ne fait pas bien. Exemples: TimesTen, BerkeleyDB. Ils ont acquis ces bases de données pour élargir leur marché. MySQL est dominant sur le marché des applications Web, et Oracle DB ne l'est pas, ils ont donc acquis MySQL. Cela n'a aucun sens pour Oracle d'entraver MySQL. J'ai parlé aux développeurs Oracle MySQL lors de la conférence en avril, et ils travaillent en fait sur l'implémentation de WITH pour MySQL.
Bill Karwin le
17

Vous pourriez être intéressé par quelque chose comme ceci:

select * from (
    select * from table
) as Subquery
Mosty Mostacho
la source
pouvez-vous expliquer Subquery s'il vous plaît? aurais-je pu sélectionner * à partir de ((sélectionner * dans le tableau1) UNION ALL (sélectionner * dans le tableau2)) Grouper par quelque chose?
1
@Kathy Salut, Subqueryest le nom que j'ai utilisé pour la table dérivée elle-même. Lorsque vous utilisez, from ( ... )vous créez quelque chose comme une table temporaire (une table dérivée) et cela nécessite un nom. C'est pourquoi j'ai utilisé as Subquery. En réponse à votre question, oui, vous pouvez, mais vous devrez mettre un nom dans la table dérivée externe (juste avant le Group By). J'espère que cela a aidé.
Mosty Mostacho
@MostyMostacho Bonjour, pourriez-vous me nourrir un peu à la cuillère ici? J'ai du mal à le convertir en MySQL. Pouvez-vous y jeter un œil? lien ou répondre à ma question ici peut-être? lien
Pranav
13

Vous avez la bonne syntaxe:

WITH AuthorRating(AuthorName, AuthorRating) AS
   SELECT aname         AS AuthorName,
          AVG(quantity) AS AuthorRating
   FROM Book
   GROUP By Book.aname

Cependant, comme d'autres l'ont mentionné, MySQL ne prend pas en charge cette commande. WITH a été ajouté dans SQL: 1999; la dernière version de la norme SQL est SQL: 2008. Vous pouvez trouver des informations supplémentaires sur les bases de données prenant en charge les différentes fonctionnalités de SQL: 1999 sur Wikipedia .

MySQL a traditionnellement pris un peu de retard dans la prise en charge de la norme SQL, tandis que les bases de données commerciales comme Oracle, SQL Server (récemment) et DB2 les ont suivies d'un peu plus près. PostgreSQL est généralement assez conforme aux normes.

Vous voudrez peut-être consulter la feuille de route de MySQL; Je ne sais pas exactement quand cette fonctionnalité pourrait être prise en charge, mais elle est idéale pour créer des requêtes cumulatives lisibles.

Ed Altorfer
la source
9

Oracle prend en charge WITH.

Cela ressemblerait à ceci.

WITH emps as (SELECT * FROM Employees)
SELECT * FROM emps WHERE ID < 20
UNION ALL
SELECT * FROM emps where Sex = 'F'

@ysth WITH est difficile à rechercher sur Google car c'est un mot courant généralement exclu des recherches.

Vous voudrez consulter les documents SELECT pour voir comment fonctionne l'affacturage des sous-requêtes.

Je sais que cela ne répond pas à l'OP mais je nettoie toute confusion que vous avez peut-être commencée.


la source
N'a pas dissipé ma confusion de toute façon. Êtes-vous en train de dire qu'il n'y a pas de clause WITH mais qu'il y a une instruction WITH?
ysth
1
Ah, je vois. C'est une clause d'un select qui précède le select. Peut-il également être utilisé dans CREATE VIEW? En quoi est-ce différent de rejoindre une sous-sélection? Je ne vois pas d'exemples en ligne où le nom après le WITH a des paramètres - comment fonctionnent-ils?
ysth
1
C'est très différent. Notez que le même sous-ordre est utilisé deux fois sans avoir à le définir deux fois. Bien sûr, vous pouvez copier / coller cette même requête là-dedans, mais ceci est un exemple simple. Imaginez si la clause WITH a continué pour une page et a été utilisée 4 fois dans la requête principale. vous l'apprécierez alors.
J'ai lié aux documents, cela devrait expliquer la syntaxe. Autant que dans une vue. Bien sûr, cela fonctionne là-bas.
3

En vous basant sur la réponse de @Mosty Mostacho, voici comment vous pouvez faire quelque chose d'équivalent dans MySQL, pour un cas spécifique de détermination des entrées qui n'existent pas dans une table et ne se trouvent dans aucune autre base de données.

select col1 from (
   select 'value1' as col1 union
   select 'value2' as col1 union
   select 'value3' as col1
) as subquery
left join mytable as mytable.mycol = col1
where mytable.mycol is null
order by col1

Vous souhaiterez peut-être utiliser un éditeur de texte avec des capacités de macro pour convertir une liste de valeurs en clause select union entre guillemets.

Ruben
la source
1
   WITH authorRating as (select aname, rating from book)
   SELECT aname, AVG(quantity)
   FROM authorRating
   GROUP BY aname
Mantas Dainys
la source
0

Avez-vous déjà essayé la table temporaire? Cela a résolu mon convern:

create temporary table abc (
column1 varchar(255)
column2 decimal
);
insert into abc
select ...
or otherwise
insert into abc
values ('text', 5.5), ('text2', 0815.8);

Ensuite, vous pouvez utiliser ce tableau dans chaque sélection de cette session:

select * from abc inner join users on ...;
Claus
la source
1
Je dois noter: stackoverflow.com/questions/343402/ ... vous ne pouvez pas ouvrir la table deux fois :-(
Claus
Ma solution pour les petits ensembles de données dans les tables: créer la table abc2 comme abc; insérer dans abc2 sélectionner * à partir de abc;
Claus