Cláusula "WITH" de MySQL

98

Estoy tratando de usar MySQL para crear una vista con la cláusula "WITH"

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

Pero no parece que MySQL lo admita.

Pensé que esto era bastante estándar y estoy seguro de que Oracle lo admite. ¿Hay alguna forma de obligar a MySQL a utilizar la cláusula "WITH"? Lo probé con el motor MyISAM e innoDB. Ambos no funcionan.

shA.t
fuente

Respuestas:

109

Actualización: MySQL 8.0 finalmente está obteniendo la característica de expresiones de tabla comunes, incluidas las CTE recursivas.

Aquí hay un blog que lo anuncia: http://mysqlserverteam.com/mysql-8-0-labs-recursive-common-table-expressions-in-mysql-ctes/

A continuación se muestra mi respuesta anterior, que escribí originalmente en 2008.


MySQL 5.x no admite consultas que utilicen la WITHsintaxis definida en SQL-99, también denominada Expresiones de tabla comunes.

Esta ha sido una solicitud de función para MySQL desde enero de 2006: http://bugs.mysql.com/bug.php?id=16244

Otros productos RDBMS que admiten expresiones de tabla comunes:

Bill Karwin
fuente
1
SQLite admite la cláusula WITH a partir de la versión 3.8.3 publicada el 03/02/2014.
Martijn
Agregué H2 y Firebird a la lista.
a_horse_with_no_name
2
@BillKarwin: No creo que MySQL alguna vez implemente ninguna característica moderna de DBMS (verifique restricciones, función de ventana, índice de expresiones, índice parcial, restricciones diferidas ...).
a_horse_with_no_name
2
@a_horse_with_no_name, parecen dar mucha más prioridad a la escalabilidad. Se han centrado durante mucho tiempo en hacer que sus componentes internos sean más escalables, para aprovechar el hardware moderno. Pero creo que han descuidado las funciones de SQL.
Bill Karwin
1
@BlakeMcBride, estás equivocado, tu comentario es FUD y no tiene base de hecho. Oracle también posee otros productos de base de datos que hacen cosas que Oracle DB no hace bien. Ejemplos: TimesTen, BerkeleyDB. Adquirieron esas bases de datos para expandir su mercado. MySQL es dominante en el mercado de aplicaciones web y Oracle DB no, por lo que adquirieron MySQL. No tiene sentido que Oracle paralice MySQL. Hablé con los desarrolladores de Oracle MySQL en la conferencia de abril y, de hecho, están trabajando en la implementación de WITH para MySQL.
Bill Karwin
17

Puede que te interese algo como este:

select * from (
    select * from table
) as Subquery
Mosty Mostacho
fuente
¿puede explicar la subconsulta por favor? ¿Podría haber seleccionado * de ((seleccionar * de la tabla1) UNION ALL (seleccionar * de la tabla2)) Agrupar por algo?
1
@Kathy Hola, Subqueryes el nombre que usé para la tabla derivada. Cuando lo usa from ( ... ), crea algo como una tabla temporal (una tabla derivada) y requiere un nombre. Por eso usé as Subquery. Respondiendo a su pregunta, sí, puede, pero tendrá que poner un nombre a la tabla derivada externa (justo antes de Group By). Espero que haya ayudado.
Mosty Mostacho
@MostyMostacho Hola, ¿podrías darme un poco de cuchara aquí? Estoy luchando por convertirlo a MySQL. ¿Puedes mirar esto? enlace o responder a mi pregunta aquí tal vez? enlace
Pranav
13

Tienes la sintaxis correcta:

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

Sin embargo, como han mencionado otros, MySQL no admite este comando. WITH se agregó en SQL: 1999; la versión más reciente del estándar SQL es SQL: 2008. Puede encontrar más información sobre las bases de datos que admiten las diversas funciones de SQL: 1999 en Wikipedia .

MySQL tradicionalmente se ha retrasado un poco en el soporte del estándar SQL, mientras que las bases de datos comerciales como Oracle, SQL Server (recientemente) y DB2 las han seguido un poco más de cerca. PostgreSQL también suele ser bastante compatible con los estándares.

Es posible que desee ver la hoja de ruta de MySQL; No estoy completamente seguro de cuándo se admitirá esta función, pero es excelente para crear consultas acumuladas legibles.

Ed Altorfer
fuente
9

Oracle es compatible con WITH.

Se vería así.

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

@ysth WITH es difícil de buscar en Google porque es una palabra común que normalmente se excluye de las búsquedas.

Le recomendamos que consulte los documentos SELECT para ver cómo funciona la factorización de subconsultas.

Sé que esto no responde al OP, pero estoy limpiando cualquier confusión que pueda haber comenzado.


fuente
No aclaró mi confusión de todos modos. ¿Estás diciendo que no hay una cláusula WITH pero hay una declaración WITH?
ysth
1
Ah, ya veo. Es una cláusula de una selección que precede a la selección. ¿Se puede utilizar también en CREATE VIEW? ¿En qué se diferencia de unirse a una subselección? No veo ejemplos en línea donde el nombre después de WITH tiene parámetros, ¿cómo funcionan?
ysth
1
Es muy diferente. Observe que la misma subqry se usa dos veces sin tener que definirla dos veces. Seguro que puede copiar / pegar esa misma consulta allí, pero este es un ejemplo simple. Imagínese si la cláusula WITH continuara para una página y se usara 4 veces en la consulta principal. lo apreciarás entonces.
Me vinculé a los documentos, eso debería explicar la sintaxis. En cuanto a la vista. Seguro que funciona ahí.
3

Sobre la base de la respuesta de @Mosty Mostacho, así es como puede hacer algo equivalente en MySQL, para un caso específico de determinar qué entradas no existen en una tabla y no están en ninguna otra base de datos.

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

Es posible que desee utilizar un editor de texto con capacidades de macro para convertir una lista de valores a la cláusula de unión selectiva citada.

Rubén
fuente
1
   WITH authorRating as (select aname, rating from book)
   SELECT aname, AVG(quantity)
   FROM authorRating
   GROUP BY aname
Mantas Dainys
fuente
0

¿Has probado alguna vez la mesa temporal? Esto resolvió mi 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);

Entonces puede usar esta tabla en cada selección en esta sesión:

select * from abc inner join users on ...;
Claus
fuente
1
Tengo que tener en cuenta: stackoverflow.com/questions/343402/… no puede abrir la Mesa dos veces :-(
Claus
My Sollution para pequeños conjuntos de datos en tablas: cree la tabla abc2 como abc; insertar en abc2 seleccionar * de abc;
Claus