Chỉ tham gia hàng đầu tiên


137

Tôi đã đọc nhiều chủ đề về việc chỉ nhận được hàng đầu tiên của một liên kết bên trái, nhưng, vì một số lý do, điều này không hiệu quả với tôi.

Đây là cấu trúc của tôi (tất nhiên đơn giản hóa)

Thức ăn

id |  title | content
----------------------
1  | Feed 1 | ...

Nghệ sĩ

artist_id | artist_name
-----------------------
1         | Artist 1
2         | Artist 2

feed_artists

rel_id | artist_id | feed_id
----------------------------
1      |     1     |    1 
2      |     2     |    1 
...

Bây giờ tôi muốn nhận các bài viết và chỉ tham gia Nghệ sĩ đầu tiên và tôi nghĩ về một cái gì đó như thế này:

SELECT *
    FROM feeds 
    LEFT JOIN feeds_artists ON wp_feeds.id = (
        SELECT feeds_artists.feed_id FROM feeds_artists
        WHERE feeds_artists.feed_id = feeds.id 
    LIMIT 1
    )
WHERE feeds.id = '13815'

chỉ để nhận hàng đầu tiên của feed_artists, nhưng điều này đã không hoạt động.

Tôi không thể sử dụng TOPvì cơ sở dữ liệu của mình và tôi không thể nhóm các kết quả theo feeds_artists.artist_idnhư tôi cần sắp xếp chúng theo ngày (tôi đã nhận được kết quả bằng cách nhóm chúng theo cách này, nhưng kết quả không phải là mới nhất)

Đã thử một cái gì đó với ỨNG DỤNG NGOÀI là tốt - cũng không thành công. Thành thật mà nói tôi không thể tưởng tượng được những gì đang diễn ra trong những hàng đó - có lẽ là lý do lớn nhất khiến tôi không thể làm việc này.

GIẢI PHÁP:

SELECT *
FROM feeds f
LEFT JOIN artists a ON a.artist_id = (
    SELECT artist_id
    FROM feeds_artists fa 
    WHERE fa.feed_id = f.id
    LIMIT 1
)
WHERE f.id = '13815'



Bạn nên đặt giải pháp làm câu trả lời để chúng tôi có thể bình chọn và giải pháp có thể thấy rõ hơn đối với khách truy cập trong tương lai
fguillen

Tôi đoán bạn đúng - tôi cũng đã thêm nó như một câu trả lời.
KddC

Câu trả lời:


97

Nếu bạn có thể cho rằng ID nghệ sĩ tăng dần theo thời gian, thì đó MIN(artist_id)sẽ là sớm nhất.

Vì vậy, hãy thử một cái gì đó như thế này (chưa được kiểm tra ...)

SELECT *
  FROM feeds f
  LEFT JOIN artists a ON a.artist_id = (
    SELECT
      MIN(fa.artist_id) a_id
    FROM feeds_artists fa 
    WHERE fa.feed_id = f.feed_id
  ) a

Cảm ơn phản hồi nhanh chóng của bạn. Đây không phải là câu trả lời chính xác, nhưng hoàn toàn đưa tôi đi đúng hướng. Tôi luôn cố gắng tham gia cả hai ở cùng cấp độ thay vì làm cho người này phụ thuộc vào người khác. Cảm ơn bạn rất nhiều vì đã dẫn dắt tôi đi đúng hướng. Đã chỉnh sửa bài đăng đầu tiên
KddC

@KddC thay vì sửa đổi câu hỏi để thêm câu trả lời, hãy chỉnh sửa câu trả lời này hoặc tự trả lời.
PhoneixS

4
Tại thời điểm này, một truy vấn phụ đơn giản sẽ tốt hơn? Vì bây giờ bạn có một tham gia và một truy vấn phụ. Chỉ cần hỏi nguyên nhân tôi đang tìm giải pháp cho cùng một vấn đề :)
galdikas

2
truy vấn quá chậm.
Sinux

1
@Sinux định nghĩa "quá chậm". Nó phụ thuộc vào số lượng hồ sơ và các yêu cầu nhất định.
người quan sát

53

Phiên bản không có subselect:

   SELECT f.title,
          f.content,
          MIN(a.artist_name) artist_name
     FROM feeds f
LEFT JOIN feeds_artists fa ON fa.feed_id = f.id
LEFT JOIN artists a ON fa.artist_id = a.artist_id
 GROUP BY f.id

2
Tôi không nghĩ đây sẽ là hàng đầu tiên (id đầu tiên hoặc đầu tiên của một thứ khác), nó chỉ chọn ngẫu nhiên một trong số các hàng tham gia bên trái.
Sinux

26
Truy vấn này là sai. Nó sẽ chọn tên nghệ sĩ "thấp nhất" không phải tên của các nghệ sĩ đầu tiên trong bộ.
Glapa

5
Sai cho câu hỏi nhưng chính xác là những gì tôi muốn. Trong trường hợp của tôi, tôi chỉ muốn ID đầu tiên từ bảng mà tôi tham gia.
Drew Stephens

2
Vấn đề ở đây là nếu bạn quyết định thực hiện COUNT hoặc SUM, bạn sẽ làm hỏng dữ liệu. Vấn đề với Subselect là việc lấy dữ liệu sẽ nặng hơn khi nó tạo một bảng tạm thời ... Tôi ước MySql có thể có GIỚI HẠN ở cấp độ TRÁI PHIẾU.
Shadoweb

Giải pháp này có vấn đề về hiệu suất. Sử dụng giải pháp Min / Max thay thế.
Sadegh PM

25

@Matt Dodges trả lời đưa tôi đi đúng hướng. Cảm ơn một lần nữa cho tất cả các câu trả lời, đã giúp rất nhiều chàng trai trong thời gian đó. Nó hoạt động như thế này:

SELECT *
FROM feeds f
LEFT JOIN artists a ON a.artist_id = (
    SELECT artist_id
    FROM feeds_artists fa 
    WHERE fa.feed_id = f.id
    LIMIT 1
)
WHERE f.id = '13815'

Đây là câu trả lời chỉ làm việc cho hàng đầu tiên. Nghỉ khi không có f.idđiều kiện.
Tajni

2

Tôi đã sử dụng một cái gì đó khác (tôi nghĩ tốt hơn ...) và muốn chia sẻ nó:

Tôi đã tạo một VIEW có mệnh đề "nhóm"

CREATE VIEW vCountries AS SELECT * PROVINCES GROUP BY country_code

SELECT * FROM client INNER JOIN vCountries on client_province = province_id

Tôi muốn nói rằng, tôi nghĩ rằng chúng ta cần phải thực hiện giải pháp này VÌ CHÚNG TÔI ĐÃ BẮT ĐẦU SAU KHI PHÂN TÍCH ... ít nhất là trong trường hợp của tôi ... nhưng đôi khi nó rẻ hơn khi làm điều đó để thiết kế lại mọi thứ ...

Tôi hy vọng nó sẽ giúp!


Giả sử có nhiều hàng (tỉnh?) Cho mỗi hàng country_code, điều đó GROUP BYlà không đúng. Xem ONLY_FULL_GROUP_BY.
Rick James

Bạn không phải tạo chế độ xem chỉ được sử dụng cho THAM GIA TRÁI / INNER?! Có thể sử dụng một truy vấn con hoặc một WITH x AS (mệnh đề?
kiradotee

2

dựa trên một số câu trả lời ở đây, tôi đã tìm thấy một cái gì đó phù hợp với tôi và tôi muốn khái quát hóa và giải thích những gì đang xảy ra.

đổi:

LEFT JOIN table2 t2 ON (t2.thing = t1.thing)

đến:

LEFT JOIN table2 t2 ON (t2.p_key = (SELECT MIN(t2_.p_key) 
    FROM table2 t2_ WHERE (t2_.thing = t1.thing) LIMIT 1))

điều kiện kết nối t1 và t2 được chuyển từ ONvà vào truy vấn bên trong WHERE. các MIN(primary key)hoặc LIMIT 1làm cho chắc chắn rằng chỉ có 1 hàng được trả về bởi truy vấn bên trong.

sau khi chọn một hàng cụ thể, chúng ta cần cho biết ONđó là hàng nào. đó là lý do tại sao việc ONso sánh khóa chính của tab được nối.

bạn có thể chơi với truy vấn bên trong (tức là thứ tự + giới hạn) nhưng nó phải trả về một khóa chính của hàng mong muốn sẽ cho biết ONhàng chính xác sẽ tham gia.


ghi chú: nó cũng sẽ làm việc với chỉ LIMIThoặc duy nhất MIN. các ONđiều kiện phải trên khóa chính bảng tham gia để tác động hiệu quả tránh.
oriadam

1

Tôi muốn đưa ra một câu trả lời khái quát hơn . Một trường hợp sẽ xử lý bất kỳ trường hợp nào khi bạn muốn chỉ chọn mục đầu tiên trong THAM GIA TRÁI PHIẾU .

Bạn có thể sử dụng truy vấn con GROUP_CONCATS những gì bạn muốn (cũng được sắp xếp!), Sau đó chỉ cần tách kết quả GROUP_CONCAT'd và chỉ lấy mục đầu tiên của nó, như vậy ...

LEFT JOIN Person ON Person.id = (
    SELECT SUBSTRING_INDEX(
        GROUP_CONCAT(FirstName ORDER BY FirstName DESC SEPARATOR "_" ), '_', 1)
    ) FROM Person
);

Vì chúng tôi có DESC làm tùy chọn ĐẶT HÀNG B BYNG , điều này sẽ trả về id người cho một người như "Zack". Nếu chúng tôi muốn ai đó có tên như "Andy", chúng tôi sẽ thay đổi ĐẶT HÀNG B FirstNG FirstName DESC thành ĐẶT HÀNG B FirstNG FirstName ASC .

Điều này là nhanh nhẹn, vì điều này đặt sức mạnh của trật tự hoàn toàn trong tay của bạn. Nhưng, sau nhiều thử nghiệm, nó sẽ không mở rộng tốt trong tình huống có nhiều người dùng và nhiều dữ liệu.

Tuy nhiên, nó rất hữu ích trong việc chạy các báo cáo chuyên sâu về dữ liệu cho quản trị viên.


Thủ GROUP_CONCATthuật là tốt miễn là số lượng giá trị bị hạn chế. Giới hạn mặc định là 1024 ký tự.
Rick James
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.