Mệnh đề MySQL "WITH"


98

Tôi đang cố gắng sử dụng MySQL để tạo chế độ xem với mệnh đề "VỚI"

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

Nhưng có vẻ như MySQL không hỗ trợ điều này.

Tôi nghĩ rằng điều này là khá chuẩn và tôi chắc chắn rằng Oracle hỗ trợ điều này. Có cách nào để buộc MySQL sử dụng mệnh đề "VỚI" không? Tôi đã thử nó với MyISAM và công cụ innoDB. Cả hai đều không hoạt động.

Câu trả lời:


109

Cập nhật: MySQL 8.0 cuối cùng cũng nhận được tính năng của các biểu thức bảng phổ biến, bao gồm cả CTE đệ quy.

Đây là blog thông báo về nó: http://mysqlserverteam.com/mysql-8-0-labs-recursive-common-table-expressions-in-mysql-ctes/

Dưới đây là câu trả lời trước đây của tôi, mà tôi đã viết ban đầu vào năm 2008.


MySQL 5.x không hỗ trợ các truy vấn sử dụng WITHcú pháp được định nghĩa trong SQL-99, còn được gọi là Biểu thức bảng chung.

Đây là một yêu cầu tính năng cho MySQL kể từ tháng 1 năm 2006: http://bugs.mysql.com/bug.php?id=16244

Các sản phẩm RDBMS khác hỗ trợ các biểu thức bảng phổ biến:


1
SQLite hỗ trợ mệnh đề WITH kể từ phiên bản 3.8.3 được phát hành vào ngày 2014-02-03.
Martijn

Tôi đã thêm H2 và Firebird vào danh sách.
a_horse_with_no_name

2
@BillKarwin: Tôi không tin MySQL sẽ triển khai bất kỳ tính năng DBMS hiện đại nào (kiểm tra các ràng buộc, hàm cửa sổ, chỉ mục trên biểu thức, chỉ mục một phần, ràng buộc trì hoãn ...).
a_horse_with_no_name

2
@a_horse_with_no_name, họ dường như đặt ưu tiên cao hơn nhiều về khả năng mở rộng. Từ lâu, họ đã tập trung vào việc làm cho nội bộ của họ có thể mở rộng hơn, để tận dụng lợi thế của phần cứng hiện đại. Nhưng tôi nghĩ rằng họ đã bỏ qua các tính năng SQL.
Bill Karwin

1
@BlakeMcBride, Bạn nhầm rồi, nhận xét của bạn là FUD và không có cơ sở trên thực tế. Oracle cũng sở hữu các sản phẩm cơ sở dữ liệu khác làm được những điều mà Oracle DB không làm tốt. Ví dụ: TimesTen, BerkeleyDB. Họ mua lại những cơ sở dữ liệu đó để mở rộng thị trường. MySQL đang chiếm ưu thế trong thị trường ứng dụng web, còn Oracle DB thì không, vì vậy họ đã mua lại MySQL. Không có ý nghĩa gì đối với Oracle khi làm phiền MySQL. Tôi đã nói chuyện với các nhà phát triển Oracle MySQL tại hội nghị vào tháng 4 và trên thực tế họ đang làm việc để triển khai WITH cho MySQL.
Bill Karwin

17

Bạn có thể quan tâm đến somethinkg như thế này:

select * from (
    select * from table
) as Subquery

bạn có thể giải thích Subquery được không? tôi có thể chọn * từ ((chọn * từ bảng1) ĐOÀN KẾT TẤT CẢ (chọn * từ bảng 2)) Nhóm Theo thứ gì đó?

1
@Kathy Xin chào, Subquerylà tên tôi đã sử dụng cho chính bảng dẫn xuất. Khi bạn sử dụng, from ( ... )bạn tạo một cái gì đó giống như một bảng tạm thời (một bảng dẫn xuất) và nó yêu cầu một tên. Đó là lý do tại sao tôi đã sử dụng as Subquery. Trả lời câu hỏi của bạn, có, bạn có thể, nhưng bạn sẽ phải đặt tên cho bảng dẫn xuất bên ngoài (ngay trước dấu Group By). Hy vọng rằng đã giúp.
Mosty Mostacho

@MostyMostacho Xin chào, bạn có thể đút thìa cho tôi một chút ở đây được không? Tôi đang đấu tranh để chuyển đổi nó sang MySQL. Bạn có thể nhìn vào nó? liên kết hoặc trả lời câu hỏi của tôi ở đây có thể? liên kết
Pranav

13

Bạn đã viết đúng cú pháp:

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

Tuy nhiên, như những người khác đã đề cập, MySQL không hỗ trợ lệnh này. WITH đã được thêm vào SQL: 1999; phiên bản mới nhất của tiêu chuẩn SQL là SQL: 2008. Bạn có thể tìm thêm một số thông tin về cơ sở dữ liệu hỗ trợ các tính năng khác nhau của SQL: 1999 trên Wikipedia .

MySQL theo truyền thống đã tụt hậu một chút trong việc hỗ trợ tiêu chuẩn SQL, trong khi các cơ sở dữ liệu thương mại như Oracle, SQL Server (gần đây) và DB2 đã theo sát chúng hơn một chút. PostgreSQL thường tuân thủ các tiêu chuẩn khá tốt.

Bạn có thể muốn xem lộ trình của MySQL; Tôi không hoàn toàn chắc chắn khi nào tính năng này có thể được hỗ trợ, nhưng nó rất tốt để tạo các truy vấn cuộn lên có thể đọc được.


9

Oracle không hỗ trợ WITH.

Nó sẽ trông như thế này.

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

@ysth WITH rất khó để google vì đây là một từ phổ biến thường bị loại trừ khỏi các tìm kiếm.

Bạn muốn xem tài liệu CHỌN để xem cách hoạt động của bao thanh toán truy vấn con.

Tôi biết điều này không trả lời OP nhưng tôi đang dọn dẹp mọi nhầm lẫn mà bạn có thể đã bắt đầu.


Dù sao cũng không giải tỏa được sự nhầm lẫn của tôi. Bạn đang nói rằng không có mệnh đề WITH nhưng có một câu lệnh WITH?
ysth

1
Ah tôi thấy. Đó là một mệnh đề của một lựa chọn đứng trước lựa chọn. Nó cũng có thể được sử dụng trong CREATE VIEW? Nó khác với việc tham gia một lựa chọn phụ như thế nào? Tôi không thấy các ví dụ trực tuyến nơi tên sau WITH có các tham số - chúng hoạt động như thế nào?
ysth

1
Nó rất khác. Lưu ý rằng cùng một quy tắc con được sử dụng hai lần mà không cần phải định nghĩa nó hai lần. Chắc chắn bạn có thể sao chép / dán cùng một truy vấn vào đó nhưng đây là một ví dụ đơn giản. Hãy tưởng tượng nếu mệnh đề WITH tiếp tục cho một trang và được sử dụng 4 lần trong truy vấn chính. bạn sẽ đánh giá cao nó.

Tôi đã liên kết với tài liệu, điều đó sẽ giải thích cú pháp. Theo một góc nhìn. Chắc chắn nó hoạt động ở đó.

3

Dựa trên câu trả lời từ @Mosty Mostacho, đây là cách bạn có thể làm điều gì đó tương đương trong MySQL, cho một trường hợp cụ thể xác định mục nhập nào không tồn tại trong bảng và không có trong bất kỳ cơ sở dữ liệu nào khác.

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

Bạn có thể muốn sử dụng một trình soạn thảo văn bản có khả năng macro để chuyển đổi danh sách các giá trị thành mệnh đề liên hiệp chọn được trích dẫn.



1
   WITH authorRating as (select aname, rating from book)
   SELECT aname, AVG(quantity)
   FROM authorRating
   GROUP BY aname

0

Bạn đã bao giờ thử Temporary Table chưa? Điều này đã giải quyết được quán rượu của tôi:

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

Sau đó, bạn có thể sử dụng bảng này trong mọi lựa chọn trong phiên này:

select * from abc inner join users on ...;

1
Tôi phải lưu ý: stackoverflow.com/questions/343402/… bạn không thể mở Bảng hai lần :-(
Claus

Sollution của tôi cho các tập dữ liệu nhỏ trong bảng: tạo bảng abc2 như abc; insert vào abc2 select * from abc;
Claus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.