KIRI GABUNG saja baris pertama

138

Saya membaca banyak utas tentang mendapatkan hanya baris pertama dari gabungan kiri, tetapi, untuk beberapa alasan, ini tidak berfungsi untuk saya.

Ini struktur saya (tentu saja disederhanakan)

Feed

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

Artis

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

feeds_artists

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

Sekarang saya ingin mendapatkan artikel dan hanya bergabung dengan Artis pertama dan saya memikirkan sesuatu seperti ini:

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'

hanya untuk mendapatkan hanya baris pertama dari feeds_artists, tetapi sudah ini tidak berfungsi.

Saya tidak dapat menggunakan TOPkarena basis data saya dan saya tidak dapat mengelompokkan hasil feeds_artists.artist_idkarena saya perlu mengurutkannya berdasarkan tanggal (saya mendapat hasil dengan mengelompokkannya dengan cara ini, tetapi hasil di mana bukan yang terbaru)

Mencoba sesuatu dengan OUTER BERLAKU juga - tidak berhasil juga. Sejujurnya saya tidak bisa membayangkan apa yang terjadi di baris itu - mungkin alasan terbesar mengapa saya tidak bisa mendapatkan ini berfungsi.

LARUTAN:

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'
KddC
sumber
di sini adalah solusi stackoverflow.com/a/7588442/612987
Wasim A.
Anda harus meletakkan solusi sebagai jawaban agar kami dapat memilihnya dan itu dapat lebih terlihat bagi pengunjung masa depan
fguillen
Saya kira Anda benar - saya juga menambahkannya sebagai jawaban.
KddC

Jawaban:

97

Jika Anda dapat mengasumsikan bahwa kenaikan ID artis dari waktu ke waktu, maka yang MIN(artist_id)akan paling awal.

Jadi cobalah sesuatu seperti ini (belum diuji ...)

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
Matt Dodge
sumber
Terima kasih atas tanggapan cepat Anda. Ini bukan jawaban yang tepat, tetapi benar-benar membuat saya berada di jalan yang benar. Saya selalu mencoba untuk bergabung dengan keduanya pada level yang sama daripada membuat yang satu tergantung dari yang lain. Terima kasih banyak telah membimbing saya di jalur yang benar.
Mengedit
4
Bukankah pada saat ini sub-permintaan sederhana lebih baik? Karena sekarang Anda memiliki gabungan, dan sub-kueri. Hanya meminta sebab saya mencari solusi untuk masalah yang sama :)
galdikas
2
subquery terlalu lambat.
Sinux
1
@Sinux mendefinisikan "terlalu lambat". Itu tergantung pada jumlah catatan dan persyaratan yang diberikan.
pengamat
1
Ini tidak akan berhasil! Sub-permintaan TIDAK mengizinkan untuk meneruskan bidang dari permintaan orang tua !!!
Thư Sinh
53

Versi tanpa 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
Denis Khvorostin
sumber
2
saya tidak berpikir ini akan menjadi baris pertama (id pertama atau yang pertama dari yang lain), hanya saja secara acak memilih satu di antara baris gabung kiri.
Sinux
26
Kueri ini salah. Ini akan memilih nama artis "terendah" bukan nama artis pertama di set.
Glapa
5
Salah untuk pertanyaan ... tetapi persis apa yang saya inginkan. Dalam kasus saya, saya hanya ingin ID pertama dari tabel tempat saya bergabung.
Drew Stephens
2
Masalahnya di sini adalah bahwa jika Anda memutuskan untuk melakukan COUNT atau SUM Anda akan mengacaukan data. Masalah dengan Subselect adalah lebih berat untuk mendapatkan data karena ia membuat tabel sementara ... Saya berharap MySql dapat memiliki LIMIT pada tingkat LEFT JOIN.
Shadoweb
Solusi ini memiliki masalah kinerja. Gunakan solusi Min / Max sebagai gantinya.
Sadegh PM
25

@Matt Dodges menjawab menempatkan saya di jalur yang benar. Terima kasih sekali lagi untuk semua jawaban, yang membantu banyak pria dalam waktu yang bersamaan. Mengerjakannya seperti ini:

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'
KddC
sumber
Ini adalah jawaban yang hanya berfungsi untuk baris pertama. Hancur ketika tidak ada f.idkondisi.
Tajni
2

Saya telah menggunakan sesuatu yang lain (saya pikir lebih baik ...) dan ingin membagikannya:

Saya membuat VIEW yang memiliki klausa "grup"

CREATE VIEW vCountries AS SELECT * PROVINCES GROUP BY country_code

SELECT * FROM client INNER JOIN vCountries on client_province = province_id

Saya ingin mengatakan, bahwa saya pikir kita perlu melakukan solusi ini KARENA KITA MELAKUKAN SESUATU YANG SALAH DALAM ANALISIS ... setidaknya dalam kasus saya ... tapi kadang-kadang lebih murah untuk melakukan ini untuk mendesain ulang semuanya ...

Saya harap ini membantu!

Ari Waisberg
sumber
Dengan asumsi ada beberapa baris (provinsi?) Untuk masing-masing country_code, itu GROUP BYtidak tepat. Lihat ONLY_FULL_GROUP_BY.
Rick James
Anda tidak harus membuat tampilan untuk digunakan semata-mata untuk KIRI / GABUNGAN DALAM ?! Bisakah menggunakan subquery atau WITH x AS (klausa?
Kiradotee
2

berdasarkan beberapa jawaban di sini, saya menemukan sesuatu yang bekerja untuk saya dan saya ingin menggeneralisasi dan menjelaskan apa yang terjadi.

mengubah:

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

untuk:

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

kondisi yang menghubungkan t1 dan t2 dipindahkan dari ONdan ke permintaan dalam WHERE. yang MIN(primary key)atau LIMIT 1merek yakin bahwa hanya 1 baris dikembalikan oleh query batin.

setelah memilih satu baris tertentu, kita perlu memberi tahu ONbaris yang mana. itu sebabnya ONadalah membandingkan kunci utama dari tabel yang bergabung.

Anda dapat bermain dengan kueri dalam (yaitu urutan + batas) tetapi harus mengembalikan satu kunci utama dari baris yang diinginkan yang akan memberi tahu ONbaris yang tepat untuk bergabung.

oriadam
sumber
catatan: ini juga hanya akan bekerja dengan LIMITatau hanya MIN. yang ONkondisi harus di meja bergabung kunci utama untuk dampak kinerja menghindari.
oriadam
1

Saya ingin memberikan jawaban yang lebih umum . Satu yang akan menangani kasus apa pun ketika Anda ingin memilih hanya item pertama dalam KIRI BERGABUNG .

Anda dapat menggunakan subquery yang GROUP_CONCATS apa yang Anda inginkan (diurutkan, juga!), Kemudian hanya membagi hasil GROUP_CONCAT dan hanya mengambil item pertama, seperti begitu ...

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

Karena kami memiliki DESC sebagai opsi ORDER BY kami , ini akan mengembalikan id Orang untuk seseorang seperti "Zack". Jika kami menginginkan seseorang dengan nama seperti "Andy", kami akan mengubah ORDER BY FirstName DESC menjadi ORDER BY FirstName ASC .

Ini gesit, karena ini menempatkan kekuatan pemesanan sepenuhnya di tangan Anda. Tetapi, setelah banyak pengujian, itu tidak akan skala baik dalam situasi dengan banyak pengguna dan banyak data.

Namun, ini berguna dalam menjalankan laporan intensif data untuk admin.

HoldOffHunger
sumber
The GROUP_CONCATtrick baik selama jumlah nilai terbatas. Batas default adalah 1024 karakter.
Rick James