Klauzula MySQL „WITH”

98

Próbuję użyć MySQL, aby utworzyć widok z klauzulą ​​„WITH”

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

Ale wygląda na to, że MySQL nie obsługuje tego.

Myślałem, że to dość standardowe i jestem pewien, że Oracle to obsługuje. Czy mimo wszystko można zmusić MySQL do używania klauzuli „WITH”? Wypróbowałem to z silnikiem MyISAM i innoDB. Oba nie działają.

shA.t
źródło

Odpowiedzi:

109

Aktualizacja: MySQL 8.0 w końcu otrzymuje funkcję typowych wyrażeń tabel, w tym rekurencyjnych CTE.

Oto blog, który to ogłasza: http://mysqlserverteam.com/mysql-8-0-labs-recursive-common-table-expressions-in-mysql-ctes/

Poniżej znajduje się moja wcześniejsza odpowiedź, którą oryginalnie napisałem w 2008 roku.


MySQL 5.x nie obsługuje zapytań używających WITHskładni zdefiniowanej w SQL-99, zwanej także Common Table Expressions.

To była prośba o funkcję MySQL od stycznia 2006: http://bugs.mysql.com/bug.php?id=16244

Inne produkty RDBMS obsługujące typowe wyrażenia tabel:

Bill Karwin
źródło
1
SQLite obsługuje klauzulę WITH od wersji 3.8.3 wydanej 03.02.2014.
Martijn,
Dodałem do listy H2 i Firebird.
a_horse_with_no_name
2
@BillKarwin: Nie wierzę, że MySQL kiedykolwiek zaimplementuje jakąkolwiek nowoczesną funkcję DBMS (ograniczenia sprawdzające, funkcja okna, indeks wyrażeń, indeks częściowy, ograniczenia odroczone ...).
a_horse_with_no_name
2
@a_horse_with_no_name, wydają się przykładać znacznie wyższy priorytet do skalowalności. Przez długi czas koncentrowali się na zwiększeniu skalowalności swoich elementów wewnętrznych, aby wykorzystać nowoczesny sprzęt. Ale myślę, że zaniedbali funkcje SQL.
Bill Karwin
1
@BlakeMcBride, mylisz się, twój komentarz jest FUD i nie ma podstaw. Oracle jest również właścicielem innych produktów bazodanowych, które robią rzeczy, których Oracle DB nie robi dobrze. Przykłady: TimesTen, BerkeleyDB. Uzyskali te bazy danych, aby rozszerzyć swój rynek. MySQL dominuje na rynku aplikacji internetowych, a Oracle DB nie, więc przejęli MySQL. Nie ma sensu, aby Oracle hamował MySQL. Rozmawiałem z programistami Oracle MySQL na konferencji w kwietniu i faktycznie pracują nad wdrożeniem WITH dla MySQL.
Bill Karwin,
17

Może Cię zainteresuje coś takiego:

select * from (
    select * from table
) as Subquery
Mosty Mostacho
źródło
czy możesz wyjaśnić podzapytanie? czy mógłbym wybrać * z ((wybierz * z tabeli1) UNION ALL (wybierz * z tabeli2)) Group By coś?
1
@Kathy Cześć, Subqueryto nazwa, której użyłem dla samej tabeli pochodnej. Kiedy używasz from ( ... ), tworzysz coś w rodzaju tabeli tymczasowej (tabeli pochodnej) i wymaga ona nazwy. Dlatego użyłem as Subquery. Odpowiadając na twoje pytanie, tak, możesz, ale będziesz musiał umieścić nazwę w zewnętrznej tabeli pochodnej (tuż przed Group By). Mam nadzieję, że to pomogło.
Mosty Mostacho
@MostyMostacho Witam, czy mógłbyś mnie tu trochę nakarmić łyżką? Próbuję przekonwertować go do MySQL. Czy możesz na to spojrzeć? link lub odpowiedz na moje pytanie może tutaj? link
Pranav
13

Masz właściwą składnię:

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

Jednak, jak wspominali inni, MySQL nie obsługuje tego polecenia. Dzięki został dodany w SQL: 1999; najnowsza wersja standardu SQL to SQL: 2008. Więcej informacji na temat baz danych obsługujących różne funkcje SQL: 1999 można znaleźć w Wikipedii .

MySQL tradycyjnie ma nieco opóźnienia w obsłudze standardu SQL, podczas gdy komercyjne bazy danych, takie jak Oracle, SQL Server (ostatnio) i DB2, podążały za nimi nieco bliżej. PostgreSQL jest również zazwyczaj dość zgodny ze standardami.

Możesz spojrzeć na mapę drogową MySQL; Nie jestem do końca pewien, kiedy ta funkcja może być obsługiwana, ale świetnie nadaje się do tworzenia czytelnych zapytań zbiorczych.

Ed Altorfer
źródło
10

Oracle obsługuje dzięki.

Tak by wyglądało.

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

@ysth WITH jest trudne do wyszukania w Google, ponieważ jest to popularne słowo, które jest zwykle wykluczane z wyszukiwania.

Warto przyjrzeć się dokumentom SELECT, aby zobaczyć, jak działa faktoring podzapytań.

Wiem, że to nie odpowiada na OP, ale usuwam wszelkie zamieszanie, które mogło się rozpocząć.


źródło
I tak nie wyjaśniło mojego zamieszania. Mówisz, że nie ma klauzuli WITH, ale jest instrukcja WITH?
ysth
1
O, rozumiem. Jest to klauzula select, która poprzedza select. Czy można go również używać w CREATE VIEW? Czym się różni od dołączenia do podselekcji? Nie widzę przykładów online, gdzie nazwa po znaku Dzięki ma parametry - jak one działają?
ysth
1
To bardzo różne. Zauważ, że ten sam podzakres jest używany dwukrotnie bez konieczności jego dwukrotnego definiowania. Oczywiście, możesz skopiować / wkleić to samo zapytanie, ale to jest prosty przykład. Wyobraź sobie, że klauzula WITH dotyczyła strony i została użyta 4 razy w głównym zapytaniu. wtedy to docenisz.
Połączyłem się z dokumentami, które powinny wyjaśnić składnię. O ile w widoku. Jasne, że tam działa.
3

Opierając się na odpowiedzi z @Mosty Mostacho, oto jak możesz zrobić coś równoważnego w MySQL, dla konkretnego przypadku określenia, które wpisy nie istnieją w tabeli i nie znajdują się w żadnej innej bazie danych.

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

Możesz użyć edytora tekstu z funkcjami makr, aby przekonwertować listę wartości na cytowaną w cudzysłów klauzulę select union.

Reuben
źródło
1
   WITH authorRating as (select aname, rating from book)
   SELECT aname, AVG(quantity)
   FROM authorRating
   GROUP BY aname
Mantas Dainys
źródło
0

Czy kiedykolwiek próbowałeś stołu tymczasowego? To rozwiązało moją konwergencję:

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);

Następnie możesz użyć tej tabeli przy każdym wyborze w tej sesji:

select * from abc inner join users on ...;
Mikołaj
źródło
1
Muszę zauważyć: stackoverflow.com/questions/343402/ ... nie możesz otworzyć tabeli dwa razy :-(
Mikołaj
Moje rozwiązanie dla małych zestawów danych w tabelach: utwórz tabelę abc2 podobną do abc; wstaw do abc2 wybierz * z abc;
Mikołaj