2009-11-19 5 views
10

Tôi đang thiết kế giỏ hàng. Để phá vỡ vấn đề hóa đơn cũ cho thấy giá không chính xác sau khi giá của sản phẩm bị thay đổi, tôi đã di chuyển trường giá từ bảng Product thành bảng ProductPrice bao gồm 3 trường, pid, date và price. pid và ngày tạo thành khóa chính cho bảng. Dưới đây là một ví dụ về những gì bàn trông giống như:Vấn đề SQL "GROUP BY"

pid date  price 
1  1/1/09 50 
1  2/1/09 55 
1  3/1/09 54 

Sử dụng SELECTGROUP BY để tìm ra giá mới nhất của từng sản phẩm, tôi đã đưa ra:

SELECT pid, price, max(date) FROM ProductPrice GROUP BY pid 

Ngày và PID trở là chính xác. Tôi nhận được chính xác 1 mục nhập cho mỗi pid duy nhất và ngày kèm theo đó là ngày mới nhất cho pid đó. Tuy nhiên, điều ngạc nhiên là giá đã quay trở lại. Nó trả lại giá hàng đầu tiên phù hợp với pid, mà trong trường hợp này là 50.

Sau khi làm lại tuyên bố của tôi, tôi đã đưa ra với điều này:

SELECT pp.pid, pp.price, pp.date FROM ProductPrice AS pp 
INNER JOIN (
    SELECT pid AS lastPid, max(date) AS lastDate FROM ProductPrice GROUP BY pid 
) AS m 
ON pp.pid = lastPid AND pp.date = lastDate 

Trong khi tuyên bố làm lại tại mang lại giá đúng (54), có vẻ như không thể tin được rằng một truy vấn âm thanh đơn giản như vậy sẽ đòi hỏi một sự tham gia bên trong để thực thi. Câu hỏi của tôi là, câu nói thứ hai của tôi là cách dễ nhất để hoàn thành những gì tôi cần làm? Hay tôi đang thiếu thứ gì đó ở đây? Cảm ơn trước!

James

+0

đơn giản hơn, mặc dù chỉ trên Postgresql: CHỌN DIỆT TRÊN (pid) pid, ngày, giá FROM ProductPrice ORDER BY pid, ngày DESC –

Trả lời

9

Lý do bạn nhận được giá tùy ý là mysql không thể biết cột nào cần chọn nếu bạn GROUP BY điều gì đó. Nó biết cần giámột ngày mỗi pid mới có thể tìm nạp ngày mới nhất theo yêu cầu của bạn với max(date) nhưng chọn trả về mức giá hiệu quả nhất để truy xuất - bạn không cung cấp aggregate function cho điều đó (truy vấn đầu tiên của bạn không phải là SQL hợp lệ, thực sự.)

truy vấn thứ hai của bạn trông OK, nhưng đây là một sự thay thế ngắn hơn:

SELECT pid, price, date 
FROM ProductPrice p 
WHERE date = (SELECT MAX(date) FROM ProductPrice tmp WHERE tmp.pid = p.pid) 

Nhưng nếu bạn truy cập vào giá mới nhất rất nhiều (mà tôi nghĩ rằng bạn làm), tôi sẽ khuyên bạn nên thêm cột cũ trở lại vào bảng ban đầu của bạn để giữ giá trị mới nhất, nếu bạn có tùy chọn thay đổi cấu trúc cơ sở dữ liệu một lần nữa.

+0

DBMS khác sẽ khiếu nại rằng giá không được bao gồm dưới dạng tổng hợp hoặc nhóm. –

+0

Tôi phải đồng ý điều này là sạch hơn nhiều. – Zaid

1

Bạn có thể muốn thử điều này:

SELECT pid, price, date FROM ProductPrice GROUP BY pid ORDER BY date DESC 

Nhóm có một số chức năng che khuất, tôi quá luôn không chắc chắn nếu đó là lĩnh vực đúng ... nhưng nó nên là người đầu tiên trong resultset.

+0

Điều này sẽ không hoạt động. Nó yêu cầu bảng kết quả theo ngày giảm dần, không phải bảng gốc, do đó giá mới nhất sẽ không được chọn. – Zaid

3

Tôi nghĩ bạn đã phá vỡ lược đồ cơ sở dữ liệu của mình.

Để tránh sự cố của hóa đơn cũ cho thấy giá không chính xác sau khi giá của sản phẩm bị thay đổi, tôi đã di chuyển trường giá từ bảng Product thành bảng ProductPrice bao gồm 3 trường, pid, date và price. pid và ngày tạo thành khóa chính cho bảng.

Như bạn đã chỉ ra rằng bạn cần giữ lại lịch sử thay đổi về giá. Nhưng bạn vẫn có thể giữ giá hiện tại trong bảng sản phẩm ngoài bảng mới đó. Điều đó sẽ làm cho cuộc sống của bạn dễ dàng hơn nhiều (và các truy vấn của bạn nhanh hơn).

0

Dưới đây là một -possibly inefficient- một:

SELECT pid, substring_index(group_concat(price order by date desc), ',', 1) , max(date) 
    FROM ProductPrice 
GROUP BY pid 
0

Tôi nghĩ rằng chìa khóa ở đây là đơn giản nghe truy vấn - bạn có thể xem những gì bạn muốn nhưng máy tính không phải là con người và do đó để sản xuất kết quả mong muốn từ các hoạt động dựa trên thiết lập mà bạn phải rõ ràng như trong truy vấn thứ hai.

Truy vấn bên trong xác định giá cuối cùng cho mỗi sản phẩm, khi đó truy vấn bên ngoài cho phép bạn nhận giá trị cho giá cuối cùng - điều đó đơn giản như nó có thể nhận được. Ngoài ra, nếu bạn có hệ thống lập hóa đơn, bạn thực sự phải lưu giá cho sản phẩm (và thuế suất cũng như "mã") với hóa đơn tức là bảng hóa đơn phải chứa tất cả những gì cần thiết thông tin tài chính để tái tạo hóa đơn. Nói chung, bạn không muốn dựa vào việc có thể tra cứu giá (hoặc thuế suất) trong bảng có thể thay đổi được ngay cả khi cho phép hệ thống được giới thiệu như trên. Bất kể điều này có lịch sử định giá có giá trị riêng của nó.

1

Bạn không thể giải quyết vấn đề của mình với mệnh đề GROUP BY, bởi vì đối với mỗi nhóm pid MySQL sẽ đơn giản tìm nạp pid đầu tiên, ngày tối đa và giá đầu tiên được tìm thấy (không phải là thứ bạn cần).

Bạn có thể có thể sử dụng một subquery (có thể không hiệu quả):

SELECT pid, date, price 
FROM ProductPrice p1 
WHERE date = (SELECT MAX(p2.date) 
       FROM ProductPrice p2 
       WHERE p1.pid = p2.pid) 

hoặc bạn chỉ có thể tham gia vào bảng với chính nó:

SELECT p1.pid, p1.date, p1.price 
FROM  ProductPrice p1 
LEFT JOIN ProductPrice p2 ON p1.pid = p2.pid 
      AND p1.date < p2.date 
WHERE  p2.pid IS NULL 

Hãy xem this section của tài liệu MySQL.

0

Tôi phải đối mặt với cùng một vấn đề trong một dự án của tôi, tôi đã sử dụng truy vấn phụ để tìm nạp ngày và sau đó so sánh nó nhưng nó làm cho hệ thống chậm khi dữ liệu tăng lên. do đó, tốt hơn hết là nên lưu giá mới nhất trong bảng Sản phẩm của bạn ngoài bảng mới mà bạn đã tạo để giữ lịch sử thay đổi giá.

bạn luôn có thể sử dụng bất kỳ ppl truy vấn nào được đề xuất để nhận giá sản phẩm mới nhất vào ngày cụ thể. nhưng bạn cũng có thể thêm một trường trong cùng một bảng là nó mới nhất. vì vậy trong một ngày, bạn có thể tạo cờ đúng một lần. và bạn luôn có thể tìm giá mới nhất của sản phẩm cho ngày cụ thể bằng một truy vấn đơn giản.