Giá trị tối đa từ nhiều bảng


7

Hãy xem xét tình huống sau: chúng ta có các bảng T1, T2, & T3 trong đó đã lưu idpricecác sản phẩm. Bây giờ chúng ta cần tìm các idsản phẩm có tối đa pricecả 3 bảng. Tôi có giải pháp này:

select id
from T1
where price in(
   select max(price)
   from( 
      select max(price) as price
      from T1

      union

      select max(price) as price
      from T2

      union

      select max(price) as price
      from T3
   ) temp
)   

union 

select id
from T2
where price in(
   select max(price)
   from( 
      select max(price) as price
      from T1

      union

      select max(price) as price
      from T2

      union

      select max(price) as price
      from T3
   ) temp
)   

union

....    same for T3 table.

Là nó sở hữu để tối ưu hóa truy vấn này?

mysql 

Câu hỏi đặt ra là mơ hồ - khoảng, nó là mơ hồ giữa hai giải thích trong hai câu trả lời MộtB . Bạn đang tìm kiếm một id duy nhất của mặt hàng với giá tối đa toàn cầu, hay bạn đang tìm kiếm (tối đa) ba id của các mặt hàng đắt nhất theo từng bảng trong ba bảng.
Jonathan Leffler

Điều này gây ấn tượng với tôi như là một vấn đề logic với lược đồ DBMS của bạn. Bạn có thể muốn hợp nhất cả 3 bảng thành một hoặc (nếu bạn có nhiều mã phụ thuộc vào sự sắp xếp hiện tại) tạo ra một khung nhìn hợp nhất cả 3 bảng thành một.

Câu hỏi này là lập trình SQL thuần túy và thuộc về StackOverflow nơi nó được hỏi ban đầu. Di chuyển nó sang DBA chỉ đơn giản là làm giảm số lượng người sẽ được hưởng lợi từ nó ,.
Jonathan Leffler

@JonathanLeffler: đồng ý trong trường hợp này, nhưng dba.se không chỉ dành cho khỉ sao lưu / khôi phục. Xem meta.dba.stackexchange.com/questions/564/ , và meta.dba.stackexchange.com/questions/495/ trộm
gbn

3
@JonathanLeffler: "DBA" dành cho quản trị viên DB, BI, SQL nâng cao, thiết kế cơ sở dữ liệu, v.v. meta.dba.stackexchange.com/questions/503/ Khăn Tại đây, bạn sẽ nhận được nhiều nhãn cầu từ các loại cơ sở dữ liệu hơn trên SO. Đồng thời xem meta.dba.stackexchange.com/questions/535/ từ
gbn

Câu trả lời:


3

Tôi giả sử rằng bạn muốn nói rằng bạn muốn idmón đồ đắt nhất dựa trên dữ liệu từ cả ba bảng. Đối với mỗi bảng, bạn cần idvà giá của (các) mặt hàng với giá tối đa trong bảng đó. Đối với một bảng, đó là:

SELECT id, price FROM Tn WHERE price = (SELECT MAX(price) FROM Tn)

Vì vậy, có một truy vấn phụ:

SELECT id, price FROM T1 WHERE price = (SELECT MAX(price) FROM T1)
UNION
SELECT id, price FROM T2 WHERE price = (SELECT MAX(price) FROM T2)
UNION
SELECT id, price FROM T3 WHERE price = (SELECT MAX(price) FROM T3)

Và, bạn cần tìm một trong các idgiá trị với giá tối đa từ truy vấn phụ đó:

SELECT id
  FROM (SELECT id, price FROM T1 WHERE price = (SELECT MAX(price) FROM T1)
        UNION
        SELECT id, price FROM T2 WHERE price = (SELECT MAX(price) FROM T2)
        UNION
        SELECT id, price FROM T3 WHERE price = (SELECT MAX(price) FROM T3)
       ) AS M
 ORDER BY price DESC
 LIMIT 1

Lưu ý rằng nếu có hai mục đắt tiền như nhau được liệt kê trong bất kỳ một trong các bảng, truy vấn UNION sẽ trả về hơn 3 hàng. Nếu có hai hoặc nhiều mặt hàng đắt tiền như nhau, truy vấn với GIỚI HẠN sẽ chọn một mặt hàng và bạn không thể dự đoán được mặt hàng nào. Nếu bạn cần xem tất cả các idgiá trị của các mặt hàng đắt tiền tương đương có giá cao nhất, thì bạn cần chơi một trò chơi tương tự bằng các truy vấn lồng nhau. Điều này thổi vào tâm trí của tôi, nhưng nên hoạt động:

SELECT id, price
  FROM (SELECT id, price FROM T1 WHERE price = (SELECT MAX(price) FROM T1)
        UNION
        SELECT id, price FROM T2 WHERE price = (SELECT MAX(price) FROM T2)
        UNION
        SELECT id, price FROM T3 WHERE price = (SELECT MAX(price) FROM T3)
       ) AS M
 WHERE price =
       (SELECT MAX(Price)
          FROM (SELECT id, price FROM T1 WHERE price = (SELECT MAX(price) FROM T1)
                UNION
                SELECT id, price FROM T2 WHERE price = (SELECT MAX(price) FROM T2)
                UNION
                SELECT id, price FROM T3 WHERE price = (SELECT MAX(price) FROM T3)
               ) AS M2
       );

Điều này sẽ dễ dàng hơn khi sử dụng mệnh đề VỚI:

WITH MaxPrices AS
     (SELECT id, price FROM T1 WHERE price = (SELECT MAX(price) FROM T1)
      UNION
      SELECT id, price FROM T2 WHERE price = (SELECT MAX(price) FROM T2)
      UNION
      SELECT id, price FROM T3 WHERE price = (SELECT MAX(price) FROM T3)
     )
SELECT id, price
  FROM M
 WHERE price = (SELECT MAX(Price) FROM M);

Không phải mọi DBMS đều hỗ trợ mệnh đề VỚI như thế này và tôi tin rằng MySQL là một trong những DBMS trong danh mục không bao gồm hỗ trợ đó.


Nhưng nếu có nhiều hơn một sản phẩm có giá tối đa

@Ashot: Tôi đã sửa nó với bản cập nhật của tôi, được viết trong khi bạn hỏi câu hỏi phụ trợ của bạn. Khi bạn đang xử lý một truy vấn phức tạp, hãy xây dựng từng mảnh một, như tôi đã trình bày (và như tôi đã chỉ ra trong nhiều câu trả lời khác cho các câu hỏi SQL). Cố gắng làm tất cả cùng một lúc chỉ khiến tâm trí bị rối loạn, và truy vấn bị phá vỡ, và sau đó bạn phải tách nó ra và kiểm tra các mảnh thành phần để xem nó đang sai ở đâu, vì vậy việc xây dựng nó từ đâu sẽ dễ dàng hơn kiểm tra các thành phần hơn để làm, hoàn tác và làm lại.
Jonathan Leffler

1
create temporary table allthree as
select * from t1
union
select * from t2
union
select * from t3;

select id, max(price) from allthree;

Nếu bạn cần lấy tất cả các ID có cùng giá trong trường hợp hòa (hoặc bạn cần nghiêm ngặt hơn vì những lý do khác), hãy sử dụng cách sau

select id from allthree where price=(select max(price) from allthree);

Trong một số trường hợp, có thể giúp tạo một chỉ mục trên pricecột sau khi tạo bảng tạm thời.


+1 cho bảng tạm thời, có lẽ không đáng để tạo lại tất cả các cột:create temporary table allthree as SELECT id, price FROM T1 WHERE price = (SELECT MAX(price) FROM T1) ...

@Bruno: ý kiến ​​hay. Gửi nó như là một câu trả lời và tôi sẽ nâng cao bạn. (Trên thực tế, một khi bạn đã đi xa đến mức tạo một bảng tạm thời có quá ít dữ liệu trong đó, có lẽ bạn nên hoàn thành truy vấn ở phía máy khách.)

@KenBloom Đăng câu trả lời của tôi.

1

Phiên bản tối ưu hóa:

create temporary table allthree as
SELECT id, price FROM T1 WHERE price = (SELECT MAX(price) FROM T1)
UNION ALL
SELECT id, price FROM T2 WHERE price = (SELECT MAX(price) FROM T2)
UNION ALL
SELECT id, price FROM T3 WHERE price = (SELECT MAX(price) FROM T3);

select id from allthree where price=(select max(price) from allthree);

0

Tôi không chắc là tôi có hiểu câu hỏi của bạn không nhưng điều này không đủ:

select id, max(price) as price
from T1
union all
select id, max(price) as price
from T2
union all
select id, max(price) as price
from T3

Điều này sẽ nhận được các giá trị tối đa cho mỗi bảng.


Bạn tìm id của sản phẩm có giá tối đa trong bảng của mình. Tôi cần id của các sản phẩm có giá tối đa từ cả 3 bảng

2
Nói đúng ra, select by id, max(price)không được phép trong SQL, tuy nhiên MySQL cho phép nó như một phần mở rộng - nó sẽ chọn bất kỳ id nào thuận tiện.

0

Tôi hy vọng cú pháp của tôi hoạt động vì tôi không phải là người MySql thường.

SELECT *
FROM (
   SELECT 'T1' AS TableName, * FROM Table1
   UNION ALL SELECT 'T2', * FROM Table2
   UNION ALL SELECT 'T3', * FROM Table3
) AS X
WHERE
   price = (
      SELECT Max(price)
      FROM (
         SELECT price FROM Table1
         UNION ALL SELECT price FROM Table2
         UNION ALL SELECT price FROM Table3
      ) AS X
   )

Nếu MySql có các chức năng cửa sổ hoặc CTE hoặc CROSS ỨNG DỤNG hoặc các kỹ thuật khác mà tôi không biết để giúp chọn toàn bộ các hàng đáp ứng một số điều kiện tổng hợp, truy vấn của tôi có thể được cải thiện hoặc đơn giản hóa.


0

CTE để giải cứu!

Truy vấn này cũng lấy ra một dấu hiệu của bảng nơi tìm thấy max.

WITH three AS (
        SELECT 1::INTEGER AS num, id, zdate FROM table1
        UNION ALL
        SELECT 2::INTEGER AS num, id, zdate FROM table2
        UNION ALL
        SELECT 3::INTEGER AS num, id, zdate FROM table3
        )
SELECT * FROM three tt
WHERE NOT EXISTS (
        SELECT * FROM three nx
        WHERE nx.zdate > tt.zdate
        );

Tin xấu là: Trình tối ưu hóa truy vấn của Postgres không "nhìn thấy" các chỉ mục (trên zdate) bên trong các hiệp hội và không kéo chúng vào truy vấn chính. Kế hoạch truy vấn bao gồm các lần quét liên tiếp lồng nhau.

 Nested Loop Anti Join  (cost=297.82..315505.01 rows=3055 width=16) (actual time=633.593..633.594 rows=1 loops=1)
   Join Filter: (nx.zdate > tt.zdate)
   CTE three
     ->  Result  (cost=0.00..297.82 rows=4582 width=16) (actual time=0.013..2.623 rows=4582 loops=1)
           ->  Append  (cost=0.00..297.82 rows=4582 width=16) (actual time=0.011..2.143 rows=4582 loops=1)
                 ->  Seq Scan on table1  (cost=0.00..99.19 rows=1519 width=16) (actual time=0.011..0.884 rows=1519 loops=1)
                 ->  Seq Scan on table2  (cost=0.00..99.12 rows=1512 width=16) (actual time=0.006..0.449 rows=1512 loops=1)
                 ->  Seq Scan on table3  (cost=0.00..99.51 rows=1551 width=16) (actual time=0.003..0.450 rows=1551 loops=1)
   ->  CTE Scan on three tt  (cost=0.00..91.64 rows=4582 width=16) (actual time=0.021..0.630 rows=4582 loops=1)
   ->  CTE Scan on three nx  (cost=0.00..91.64 rows=4582 width=8) (actual time=0.000..0.069 rows=757 loops=4582)
 Total runtime: 633.820 ms
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.