SOL sadece ilk satıra katıl


138

Sol birleştirmenin yalnızca ilk satırını almayla ilgili birçok konu okudum, ancak bazı nedenlerden dolayı bu benim için çalışmıyor.

İşte benim yapım (elbette basitleştirilmiş)

Yemler

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

Sanatçılar

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

feeds_artists

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

Şimdi makaleleri almak ve sadece ilk Sanatçı katılmak istiyorum ve ben böyle bir şey düşündüm:

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'

feeds_artists öğesinin yalnızca ilk satırını almak için, ancak bu zaten çalışmıyor.

TOPVeritabanım nedeniyle kullanamıyorum ve ben feeds_artists.artist_idtarihe göre sıralamak gerekir gibi sonuçları gruplayamıyor (Ben onları bu şekilde gruplandırarak sonuçları var, ama en yeni değil nerede sonuçları)

OUTER UYGULAMA ile de bir şey denedim - başarı da yok. Dürüst olmak gerekirse ben gerçekten bu satırlarda neler olup bittiğini hayal edemiyorum - muhtemelen bu işe alamıyorum neden.

ÇÖZÜM:

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'



Çözümü bir cevap olarak koymalısınız, böylece oy verebiliriz ve gelecekteki ziyaretçiler için daha görünür olabilir
fguillen

Sanırım haklısın - bunu bir cevap olarak ekledim.
KddC

Yanıtlar:


97

Sanatçı kimliklerinin zamanla arttığını varsayabilirseniz MIN(artist_id), en erken olacak.

Öyleyse böyle bir şey deneyin (denenmemiş ...)

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

Hızlı yanıtın için teşekkürler. Bu kesin bir cevap değildi, ama beni tam olarak doğru yolda tuttu. Birini diğerinden bağımlı hale getirmek yerine her zaman aynı seviyede katılmaya çalıştım. Beni doğru yolda gösterdiğiniz için çok teşekkür ederim. İlk gönderi düzenlendi
KddC

4
Bu noktada basit bir alt sorgu daha iyi olmaz mıydı? Çünkü şimdi bir birleştirme ve bir alt sorgunuz var. Sadece soruyorum neden aynı soruna çözüm arıyorum :)
galdikas

2
alt sorgu çok yavaş.
Sinux

1
@Sinux "çok yavaş" tanımlıyor. Kayıt sayısına ve verilen gereksinimlere bağlıdır.
gözlemci

1
Bu işe yaramaz! Alt sorgu, üst sorgudan alanın geçmesine izin VERMEZ !!!
Şeyh

53

Alt seçimli olmayan sürüm:

   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
Bu ilk satır (ilk kimliği ya da başka bir şey ilk) olacağını sanmıyorum, sadece rastgele bir sol satırları arasında birini seçin.
Sinux

26
Bu sorgu yanlış. Setteki ilk sanatçıların adını değil, "en düşük" sanatçı adını seçecektir.
Glapa

5
Soru için yanlış… ama tam olarak istediğim şey. Benim durumumda, sadece katıldığım tablodaki ilk kimliği istiyorum.
Drew Stephens

2
Buradaki sorun, bir COUNT veya SUM yapmaya karar verirseniz verileri bozmuş olmanızdır. Subselect ile ilgili sorun, geçici bir tablo oluştururken veri almak için daha ağır olmasıdır ... Keşke MySql LEFT JOIN düzeyinde bir LIMIT olabilir.
Shadoweb

Bu çözümün performans sorunu var. Bunun yerine Min / Max çözümünü kullanın.
Sadegh PM

25

@Matt Dodges cevabı beni doğru yola koyuyor. Bu arada birçok insana yardımcı olan tüm cevaplar için tekrar teşekkürler. Bu şekilde çalıştım:

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'

Bu cevap sadece ilk satır için çalışıyor. Hiçbir f.idkoşul olmadığında kırılır.
Tajni

2

Başka bir şey kullandım (daha iyi düşünüyorum ...) ve paylaşmak istiyorum:

"Grup" yan tümcesi içeren bir GÖRÜNÜM oluşturdum

CREATE VIEW vCountries AS SELECT * PROVINCES GROUP BY country_code

SELECT * FROM client INNER JOIN vCountries on client_province = province_id

Henüz söylemek istiyorum ki, bu çözümü yapmamız gerektiğini düşünüyorum. ÇÜNKÜ ANALİZDE YANLIŞ BİR ŞEY YAPTIK ... en azından benim durumumda ... ama bazen her şeyi yeniden tasarlamak için bunu yapmak daha ucuz ...

Umut ediyorum bu yardım eder!


Her biri için birden fazla satır (il?) Olduğunu varsayarsak country_code, bu GROUP BYyanlıştır. Bkz ONLY_FULL_GROUP_BY.
Rick James

Yalnızca LEFT / INNER JOIN için kullanılacak bir görünüm oluşturmanıza gerek yok mu ?! Bir alt sorgu veya bir WITH x AS (yan tümce kullanabilir mi?
kiradotee

2

Burada birkaç cevaba dayanarak, benim için işe yarayan bir şey buldum ve neler olduğunu genelleştirmek ve açıklamak istedim.

dönüştürmek:

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

için:

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

t1 ve t2'yi bağlayan koşul, ONve iç sorguya taşınır WHERE. MIN(primary key)veya LIMIT 1markaları sadece 1 satır iç sorgu tarafından döndürülen emin.

belirli bir satırı seçtikten sonra ONhangi satır olduğunu söylememiz gerekir . bu yüzden ONbirleştirilmiş tablodaki birincil anahtarı karşılaştırır.

iç sorgu ile oynayabilirsiniz (yani sipariş + limit), ancak istenen satırın ONbirleştirilecek tam satırı söyleyecek bir birincil anahtar döndürmesi gerekir .


notlar: sadece LIMITveya sadece ile çalışır MIN. ONperformans etkisini önlemek için koşulun birleştirilmiş tablo birincil anahtarında olması gerekir.
oriadam

1

Daha genel bir cevap vermek istiyorum . Bir LEFT JOIN içindeki sadece ilk öğeyi seçmek istediğinizde, her durumu işleyecek olan .

GROUP_CONCATS adlı bir alt sorguyu istediğiniz gibi sıralayabilirsiniz (sıralanır!), Sonra GROUP_CONCAT'd sonucunu bölebilir ve yalnızca ilk öğesini alabilirsiniz ...

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

Elimizdeki bu yana DESC bizim kadar SİPARİŞ BY opsiyonumuz bu, "Zack" gibi biri için bir Kişi kimliği döndürecektir. Biz "Andy" gibi adıyla birini istiyordu, biz değiştirecek SİPARİŞ İLE Ad DESC için SİPARİŞ İLE Ad ASC .

Bu, çeviktir, çünkü bu, sipariş etme gücünü tamamen sizin elinizde tutar. Ancak, çok fazla testten sonra, çok sayıda kullanıcı ve çok fazla veri içeren bir durumda iyi ölçeklenmeyecektir .

Ancak, yönetici için veri yoğun raporlar çalıştırırken yararlıdır.


GROUP_CONCATDeğerlerin sayısı sınırlıdır sürece kadar hile iyidir. Varsayılan sınır 1024 karakterdir.
Rick James
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.