CHỌN * TỪ nhiều bảng. MySQL


76

SELECT name, price, photo FROM drinks, drinks_photos WHERE drinks.id = drinks_id

yeilds 5 hàng (5 mảng), photolà trường duy nhất duy nhất trong một hàng. name, priceđược lặp lại ( ở đây, fanta- name, price lặp lại 3 lần. ) Làm cách nào để loại bỏ các bản sao này?

Chỉnh sửa: Tôi muốn name, pricevà tất cả photocho mỗi đồ uống.

 id      name      price
  1.    fanta        5
  2.     dew         4


 id      photo                   drinks_id
  1.     ./images/fanta-1.jpg      1
  2.     ./images/fanta-2.jpg      1  
  3.     ./images/fanta-3.jpg      1 
  4.     ./images/dew-1.jpg        2
  5.     ./images/dew-2.jpg        2

5
Vâng, bạn đã có 5 hàng phù hợp, vì bạn đã có một số hàng có cùng đồ uống_id. Bạn mong đợi điều gì sẽ xảy ra? Bạn muốn giữ bức ảnh nào?
Jon Skeet

Câu trả lời:


108

Những gì bạn làm ở đây được gọi là a JOIN(mặc dù bạn làm điều đó một cách ngầm định vì bạn chọn từ nhiều bảng). Điều này có nghĩa là, nếu bạn không đặt bất kỳ điều kiện nào trong mệnh đề WHERE của mình, bạn có tất cả các kết hợp của các bảng đó. Chỉ với tình trạng của bạn, bạn mới hạn chế tham gia vào những hàng có id đồ uống phù hợp.

Nhưng vẫn có X nhiều hàng trong kết quả cho mỗi đồ uống, nếu có X ảnh với đồ uống cụ thể này. Tuyên bố của bạn không hạn chế ảnh (s) bạn muốn có!

Nếu bạn chỉ muốn một hàng cho mỗi đồ uống, bạn phải cho SQL biết bạn muốn làm gì nếu có nhiều hàng với một đồ uống cụ thể. Đối với điều này, bạn cần nhóm và một chức năng tổng hợp . Bạn cho SQL biết mục nhập nào bạn muốn nhóm lại với nhau (ví dụ: tất cả các loại đồ uống bằng nhau) và trong SELECT, bạn phải cho biết mục nhập nào trong số các mục nhập riêng biệt cho mỗi hàng kết quả được nhóm lại. Đối với số, đây có thể là trung bình, tối thiểu, tối đa (để đặt tên cho một số).

Trong trường hợp của bạn, tôi không thể truy vấn ảnh đồ uống nếu bạn chỉ muốn một hàng. Bạn có thể nghĩ rằng bạn có thể có một loạt các bức ảnh trong kết quả của bạn cho mỗi đồ uống, nhưng SQL không thể làm điều này. Nếu bạn chỉ muốn bất kỳ bức ảnh nào và bạn không quan tâm bạn sẽ nhận được cái nào, chỉ cần nhóm theo đồ uống_id (để chỉ nhận được một hàng cho mỗi đồ uống):

SELECT name, price, photo
FROM drinks, drinks_photos
WHERE drinks.id = drinks_id 
GROUP BY drinks_id

name     price   photo
fanta    5       ./images/fanta-1.jpg
dew      4       ./images/dew-1.jpg

Trong MySQL, chúng ta cũng có GROUP_CONCAT , nếu bạn muốn các tên tệp được nối với một chuỗi duy nhất:

SELECT name, price, GROUP_CONCAT(photo, ',')
FROM drinks, drinks_photos
WHERE drinks.id = drinks_id 
GROUP BY drinks_id

name     price   photo
fanta    5       ./images/fanta-1.jpg,./images/fanta-2.jpg,./images/fanta-3.jpg
dew      4       ./images/dew-1.jpg,./images/dew-2.jpg

Tuy nhiên, điều này có thể trở nên nguy hiểm nếu bạn có ,các giá trị trong trường, vì rất có thể bạn muốn tách lại giá trị này ở phía máy khách. Nó cũng không phải là một hàm tổng hợp SQL tiêu chuẩn.


Đúng là tôi muốn tên, giá cả và một loạt các hình ảnh cho mỗi loại đồ uống.
NestedWeb

3
Bạn viết mã chương trình của mình bằng ngôn ngữ nào để thực hiện các truy vấn đó? Bởi vì MySQL không hỗ trợ mảng dưới dạng kiểu trường. Bạn phải làm một số thủ thuật chuỗi như với GROUP_CONCATvà tách nó một lần nữa. Người ta thường không làm điều này trong cơ sở dữ liệu quan hệ. Bạn nên thực hiện nhóm trong chương trình, không phải trong SQL (phát hiện các ID trùng lặp và xây dựng các mảng đó trong chương trình của bạn).
leemes

@NestedWeb Vui lòng xem thêm tại stackoverflow.com/questions/9024248/…
leemes

@NestedWeb Nếu bạn muốn tất cả các hình ảnh, sẽ tốt hơn (nhanh hơn) không sử dụng GROUP BYGROUP_CONTACThãy tiếp tục như bạn đã làm nhưng đặt hàng trước drinks.id. Bằng cách đó, bạn sẽ có thể lặp qua tập kết quả và thu thập hình ảnh thành các mảng ở phía máy khách.
bhovhannes

Nó tương đương với INNER JOIN.
Sławomir Lenart 28/09/16

3

Bạn sẽ có các giá trị trùng lặp cho tên và giá ở đây. Và id bị trùng lặp trong bảng drink_photos, không có cách nào bạn có thể tránh được chúng. Ngoài ra, bạn muốn kết quả chính xác là gì?


2

Để loại bỏ các bản sao, bạn có thể nhóm theo drinks.id. Nhưng theo cách đó, bạn sẽ chỉ nhận được một ảnh cho mỗi drinks.id(ảnh nào bạn sẽ nhận được phụ thuộc vào việc triển khai nội bộ cơ sở dữ liệu).

Mặc dù nó không được ghi lại, nhưng trong trường hợp của MySQL, bạn sẽ nhận được bức ảnh với mức thấp nhất id(theo kinh nghiệm của tôi, tôi chưa từng thấy hành vi nào khác).

SELECT name, price, photo 
FROM drinks, drinks_photos 
WHERE drinks.id = drinks_id
GROUP BY drinks.id

1
Tốt hơn bạn nên nhóm theo id. Luôn nhóm theo trường duy nhất của bạn để có các hàng riêng biệt của bảng nguồn. Trong trường hợp của bạn, nếu hai đồ uống có cùng tên (nhưng ở các hàng khác nhau trong bảng), bạn cũng nên nhóm chúng lại với nhau.
leemes

cảm ơn bạn leemes, tôi đã không nhận thấy rằng có trường id duy nhất. Tôi đã chỉnh sửa câu trả lời của mình. Tất nhiên sử dụng id của nó tốt hơn. @ypercube, bạn có thực sự nghĩ rằng bình luận của bạn bổ sung điều gì đó thông thường để đăng không?
bhovhannes

@bhovhannes: Không, bạn nói đúng, xin lỗi. Bình luận hỗn loạn không bổ sung bất cứ điều gì hữu ích. Câu trả lời đã sửa là tốt hơn - mặc dù tôi vẫn không đồng ý với việc sử dụng GROUP BY(đó không phải là chuẩn SQL) mà không có lời giải thích tại sao nó hoạt động và cách nó sẽ trả về một nửa ngẫu nhiên photocho mỗi đồ uống. ( "Đầu tiên" trong cụm từ "bạn sẽ nhận được bức ảnh đầu tiên" chỉ là sai).
ypercubeᵀᴹ

@ypercube, vâng, sử dụng GROUP BY để lọc các hàng (chẳng hạn như trong trường hợp này) không phải là tiêu chuẩn SQL. Nhưng điều đó chắc chắn hoạt động với MySQL, nhanh và trả về photovới id thấp nhất. Tôi chưa bao giờ thấy một hành vi nào khác trong MySQL (mặc dù nó không được ghi lại). Tôi đã thêm một lưu ý cho bài viết của tôi
bhovhannes
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.