115

I'm trying to use MySQL to create a view with the "WITH" clause

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

But it doesn't seem like MySQL supports this.

I thought this was pretty standard and I'm sure Oracle supports this. Is there anyway to force MySQL to use the "WITH" clause? I've tried it with the MyISAM and innoDB engine. Both of these don't work.

shA.t
  • 16,580
  • 5
  • 54
  • 111

8 Answers8

123

Update: MySQL 8.0 is finally getting the feature of common table expressions, including recursive CTEs.

Here's a blog announcing it: http://mysqlserverteam.com/mysql-8-0-labs-recursive-common-table-expressions-in-mysql-ctes/

Below is my earlier answer, which I originally wrote in 2008.


MySQL 5.x does not support queries using the WITH syntax defined in SQL-99, also called Common Table Expressions.

This has been a feature request for MySQL since January 2006: http://bugs.mysql.com/bug.php?id=16244

Other RDBMS products that support common table expressions:

Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • 1
    SQLite supports the [WITH clause](https://www.sqlite.org/lang_with.html) as of [version 3.8.3](http://www.sqlite.org/changes.html#version_3_8_3) released on 2014-02-03. – Martijn Feb 04 '14 at 16:40
  • I added H2 and Firebird to the list. –  Feb 04 '14 at 18:14
  • @a_horse_with_no_name, thanks for the additions. Maybe we can shame MySQL into raising the priority for this old feature request! – Bill Karwin Feb 04 '14 at 18:19
  • 3
    @BillKarwin: I don't believe MySQL will ever implement *any* modern DBMS feature (check constraints, window function, index on expressions, partial index, deferred constraints...). –  Feb 04 '14 at 18:21
  • 2
    @a_horse_with_no_name, they seem to place a much higher priority on scalability. They have focused for a long time on making their internals more scalable, to take advantage of modern hardware. But I think they have neglected SQL features. – Bill Karwin Feb 04 '14 at 18:25
  • @a_horse_with_no_name, MySQL 5.7 now supports indexes on "virtual columns" which gives you a solution for expression indexes. Just wait another ten years for the other features you mentioned. :-) – Bill Karwin May 26 '15 at 23:39
  • MySQL is now owned by Oracle. Why would Oracle want to make MySQL equivalent to the Oracle DB? They want to keep MySQL restricted to small projects so that the large projects will have to utilize the Oracle DB. – Blake McBride Jun 06 '16 at 16:33
  • 1
    @BlakeMcBride, You're wrong, your comment is FUD and has no basis in fact. Oracle also owns other database products that do things that Oracle DB doesn't do well. Examples: TimesTen, BerkeleyDB. They acquired those databases to expand their market. MySQL is dominant in the web application market, and Oracle DB is not, so they acquired MySQL. It makes no sense for Oracle to hamstring MySQL. I talked to the Oracle MySQL developers at the conference in April, and they are in fact working on implementing WITH for MySQL. – Bill Karwin Jun 06 '16 at 16:57
  • @BillKarwin, I'm sorry. I got part of my information from BillKarwin who said they'd never implement modern DB features. I noticed you are now an Oracle Ace. Hmmm. – Blake McBride Jun 07 '16 at 14:51
  • @BlakeMcBride, I have written in the past that MySQL seemed too focused on internal scalability enhancements, at the cost of stagnation in SQL language features. That was true then, but since the acquisition by Oracle, they have gotten more engineering resources, so they are able to do both now. – Bill Karwin Jun 07 '16 at 16:29
  • @BillKarwin, I hope you're right, but Oracle has owned MySQL for quite sometime now and it seems like things like CTEs and Window functions are long overdue. Therefore, it's hard not to assume that Oracle is not really motivated to put SQL back in MySQL. – Mark Jul 29 '16 at 16:49
  • @Mark, I attended a panel of MySQL engineers at the conference in April 2016, and they said they're now working on CTE functions for MySQL 8. – Bill Karwin Jul 29 '16 at 17:02
  • MySQL is not at all neglected and/or restricted by Oracle. MySQL is more OLTP-performance oriented and is used by many AAA enterprises for that, but lacks analytical capabilities. It is clear that Oracle tries to differentiate its products while adding features in MySQL when they feel it is lagging from outer open source competitors such as PostgreS – rpd Feb 03 '17 at 10:10
  • Updated the answer above with Informix 14.10, which added support in 2019. – Bill Karwin Jul 28 '20 at 19:18
22

You might be interested in something like this:

select * from (
    select * from table
) as Subquery
questionto42
  • 7,175
  • 4
  • 57
  • 90
Mosty Mostacho
  • 42,742
  • 16
  • 96
  • 123
  • can you explain Subquery please? could I have select * from ( (select * from table1) UNION ALL (select * from table2) ) Group By something? –  Jun 05 '12 at 20:54
  • 1
    @Kathy Hi, `Subquery` is the name I used for the derived table itself. When you use `from ( ... )` you create something like a temporary table (a derived table) and it requires a name. That's why I used `as Subquery`. Answering your question, yes, you can, but you'll have to put a name to the outer derived table (just before the `Group By`). Hope that helped. – Mosty Mostacho Jun 06 '12 at 03:02
  • @MostyMostacho Hello, could please spoon-feed me a little here? I'm struggling to convert it to MySQL. Can you take a look at it? [link](http://pastebin.com/raw.php?i=2TixfDCJ) or answer my question here maybe? [link](http://stackoverflow.com/questions/31211081/how-to-merge-data-from-multiple-columns-into-one-adjacency-list-model-query/31211742#31211742) – Pranav Jul 03 '15 at 20:05
13

You've got the syntax right:

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

However, as others have mentioned, MySQL does not support this command. WITH was added in SQL:1999; the newest version of the SQL standard is SQL:2008. You can find some more information about databases that support SQL:1999's various features on Wikipedia.

MySQL has traditionally lagged a bit in support for the SQL standard, whereas commercial databases like Oracle, SQL Server (recently), and DB2 have followed them a bit more closely. PostgreSQL is typically pretty standards compliant as well.

You may want to look at MySQL's roadmap; I'm not completely sure when this feature might be supported, but it's great for creating readable roll-up queries.

Ed Altorfer
  • 4,373
  • 1
  • 24
  • 27
10

Oracle does support WITH.

It would look like this.

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

@ysth WITH is hard to google because it's a common word typically excluded from searches.

You'd want to look at the SELECT docs to see how subquery factoring works.

I know this doesn't answer the OP but I'm cleaning up any confusion ysth may have started.

  • Didn't clear up my confusion anyway. Are you saying there's not a WITH clause but there is a WITH statement? – ysth Nov 28 '08 at 02:38
  • 1
    Ah, I see. It's a clause of a select that precedes the select. Can it be used in CREATE VIEW as well? How is it different from joining a subselect? I don't see examples online where the name after the WITH has parameters - how do those work? – ysth Nov 28 '08 at 02:46
  • 1
    It's very different. Notice that the same subqry is used twice without having to define it twice. Sure you could copy/paste that same query in there but this is a simple example. Imagine if the WITH clause went on for a page and was used 4 times in the main query. you'll appreciate it then. –  Dec 02 '08 at 15:28
  • I linked to the docs, that should explain the syntax. As far as in a view. Sure it works there. –  Dec 02 '08 at 15:30
6

Building on the answer from @Mosty Mostacho, here's how you might do something equivalent in MySQL,for a specific case of determining what entries don't exist in a table, and are not in any other database.

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

You may want to use a text editor with macro capabilities to convert a list of values to the quoted select union clause.

Reuben
  • 4,136
  • 2
  • 48
  • 57
2

MariaDB is now supporting WITH. MySQL for now is not. https://mariadb.com/kb/en/mariadb/with/

Moshe L
  • 1,797
  • 14
  • 19
1

Have you ever tried Temporary Table? This solved my 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);

Then you can use this table in every select in this session:

select * from abc inner join users on ...;
Claus
  • 19
  • 1
  • 1
    I have to note: http://stackoverflow.com/questions/343402/getting-around-mysql-cant-reopen-table-error you cannot open Table twice :-( – Claus Feb 26 '13 at 09:02
  • My Sollution for small data sets in tables: create table abc2 like abc; insert into abc2 select * from abc; – Claus Feb 26 '13 at 09:05
1
   WITH authorRating as (select aname, rating from book)
   SELECT aname, AVG(quantity)
   FROM authorRating
   GROUP BY aname
adiga
  • 34,372
  • 9
  • 61
  • 83