LEFT JOIN最初の行のみ


138

左結合の最初の行のみを取得することについて多くのスレッドを読みましたが、何らかの理由で、これは私にとっては機能しません。

これが私の構造です(もちろん簡略化されています)

フィード

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

アーティスト

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

feeds_artists

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

今、私は記事を手に入れて最初のアーティストだけに参加したいのですが、私はこのようなことを考えました:

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の最初の行のみを取得するだけですが、すでにこれは機能しません。

TOPデータベースが原因で使用できずfeeds_artists.artist_id、日付で並べ替える必要があるため、結果をグループ化できません(このようにグループ化して結果を得ましたが、最新の結果ではありません)

OUTER APPLYでも何かを試しましたが、成功しませんでした。正直に言うと、それらの行で何が起こっているのか本当に想像することはできません。おそらく、これを機能させることができない最大の理由です。

解決:

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'


ここソリューションですstackoverflow.com/a/7588442/612987は
Wasim A.

私たちはそれを投票し、将来の訪問者にとってより見やすくなるように、ソリューションを回答として置く必要があります
fguillen

私はあなたが正しいと思います-私はそれも答えとして追加しました。
KddC

回答:


97

時間の経過とともにアーティストIDが増加すると想定できる場合は、MIN(artist_id)が最も早くなります。

だからこのようなものを試してください(試されていない...)

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

迅速な対応ありがとうございます。これは正確な答えではありませんでしたが、完全に私を正しい方向に導きました。私は常に、一方を他方に依存させるのではなく、両方を同じレベルで結合しようとしました。私を正しい軌道に乗せてくれてありがとうございます。最初の投稿を編集
KddC 2013年

4
この時点で、単純なサブクエリの方が良いでしょうか?これで、結合とサブクエリができました。原因を尋ねるだけで私は同じ問題の解決策を探しています:)
galdikas

2
サブクエリが遅すぎます。
Sinux

1
@Sinuxは「遅すぎる」と定義しています。これは、レコードの数と所定の要件によって異なります。
オブザーバー

1
これは動作しません!サブクエリでは、親クエリからフィールドを渡すことができません!!!
トーシン

53

副選択なしのバージョン:

   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
私はこれが最初の行(最初のIDまたは他の最初の行)になるとは思いません。左側の結合行から1つをランダムに選択するだけです。
2016年

26
このクエリは間違っています。セット内の最初のアーティストの名前ではなく、「最も低い」アーティスト名を選択します。
Glapa

5
質問は間違っていますが、まさに私が欲しいものです。私の場合、私はちょうど私が参加してるのテーブルからの最初のIDをしたい。
ドリュースティーブンス

2
ここでの問題は、COUNTまたはSUMを実行することにした場合、データが台無しになることです。Subselectの問題は、一時テーブルを作成するときにデータを取得するのが重いことです... MySqlにLEFT JOINレベルの制限があることを望みます。
Shadoweb 2017

このソリューションにはパフォーマンスの問題があります。代わりに最小/最大ソリューションを使用してください。
Sadegh PM

25

@マット・ダッジズの答えは私を正しい軌道に乗せました。すべての回答をありがとうございました。その間、多くの人を助けました。次のように機能します:

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'

これは、最初の行でのみ機能する回答です。f.id条件が無いと壊れます。
Tajni

2

私は他のものを使用しました(私はより良いと思います...)、それを共有したいと思います:

「グループ」句を含むビューを作成しました

CREATE VIEW vCountries AS SELECT * PROVINCES GROUP BY country_code

SELECT * FROM client INNER JOIN vCountries on client_province = province_id

まだ言いたいのですが、分析では間違っていたため、このソリューションを実行する必要があると思います。

お役に立てば幸いです。


それぞれに複数の行(州?)があるとするとcountry_code、それGROUP BYは不適切です。を参照してくださいONLY_FULL_GROUP_BY
リックジェームズ

LEFT / INNER JOIN専用に使用するビューを作成する必要はありませんか?!サブクエリまたはWITH x AS (句を使用できますか?
kiradotee

2

ここでのいくつかの回答に基づいて、私はうまくいく何かを見つけました、そして私は何が起こっているのかを一般化して説明したいと思いました。

変換:

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

に:

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

t1とt2を接続する条件は、からON内部クエリに移動されますWHEREMIN(primary key)またはLIMIT 1唯一の1行は、内部クエリによって返されることを確認します。

特定の行を1つ選択した後、ONそれがどの行かを通知する必要があります。これONが、結合されたテーブルの主キーを比較する理由です。

内部クエリ(つまり、order + limit)で遊ぶことができますがON、結合する正確な行を指示する目的の行の1つの主キーを返す必要があります。


注:LIMITまたはのみで動作しMINます。ONパフォーマンスへの影響を回避するには、条件が結合テーブルの主キーにある必要があります。
oriadam

1

より一般的な答えを出したいと思いますLEFT JOINの最初のアイテムのみを選択したい場合に、すべてのケースを処理するもの。

GROUP_CONCATSが必要なサブクエリを使用して(並べ替えもできます!)、GROUP_CONCATの結果を分割して、最初の項目のみを取得することができます。

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

ORDER BYオプションとしてDESCがあるため、これは「Zack」のような人物の個人IDを返します。「Andy」のような名前の人が必要な場合は、ORDER BY FirstName DESCORDER BY FirstName ASCに変更します。

これは機敏で、注文の力を完全にあなたの手に委ねます。しかし、多くのテストを行った結果、ユーザー数が多くデータ量が多い状況ではうまく拡張できなくなりました。

ただし、管理者向けのデータ集約型レポートの実行には役立ちます。


GROUP_CONCATトリックは限り値の数が限られていると良いです。デフォルトの制限は1024文字です。
リックジェームズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.