4

インテリジェントなタグベース画像検索システムです。ユーザーは、そのようなテーブルに適切なタグを付けて画像を追加します。

image (id, title, ...)
tag (id, title) /* It doesn't matter who has created the tag*/
imagetag (image_id, tag_id) /* One image may have multiple tags */

ユーザーが画像を表示し、 *それらの画像のタグ*からの訪問がテーブルに記録されusertagviewます。(私はINSERT ON DUPLICATE UPDATEその目的のためにクエリを使用したことに注意してください。)

usertagview (user_id, tag_id, view_count)

ここで、次のタグが付いたいくつかの画像を検討してください。

  • riverday(晴れた日の川を写した写真です)
  • rivernight(真夜中の月の光に照らされたあの川)
  • treeday
  • treenight
  • flowerday
  • flowernight

ユーザーがタグを検索すると、riverriverというタグが付いた画像が表示されます。この場合、最初の画像(川の日でタグ付け)と2番目の画像(川の夜でタグ付け)が表示されます。ユーザーは2番目の画像(とでタグ付けされた)を表示し、それがテーブルに記録されていることを表示します。rivernightusertagview

次に、ユーザーはタグの新しい検索を試み、画像treeを表示しtree nightます。

ユーザーがを検索する場合はflower、よりflower nightも優先されるようにしflower dayます。つまりflower night、前に来る必要がありますflower day。言い換えれflowerば、ユーザーの以前のビューに従ってタグ付けされた画像を一覧表示するクエリが必要です。(flower night最初に、OTHERflowerが次に)。

失敗した私のクエリ:

SELECT

    DISTINCT (image.id) AS image_id,
    image.title AS image_title,
    SUM(usertagview.view_count) AS SUM_of_all_tag_views_for_each_image

FROM (image)

JOIN imagetag ON imagetag.image_id = image.id

**LEFT JOIN** usertagview ON
    usertagview.tag_id = imagetag.tag_id
    AND usertagview.user_id = {$user_id_from_php}

WHERE

    imagetag.tag_id IN ( {impolde(',', $array_of_id_of_tags_that_the_user_has_entered)} )
    AND
    usertagview.tag_id IN
        (SELECT tag_id FROM imagetag WHERE userimagetag.image_id = image.id)

ORDER BY SUM_of_all_tag_views_for_each_image DESC

問題

**LEFT JOIN**私のクエリのは通常のと違いがないということですINNER JOIN。どちらも同じ結果になります。使っRIGHT JOINても違いはありません。

4

3 に答える 3

4

left joinあなたがと同じように振る舞う理由は、あなたがあなたの条項にあなたinner joinのための追加の基準を持っているからです。これは本質的にあなたをに変えます。left joinwhereouter joininner join

これは、一致するレコードがない場合にusertagview.tag_id、句内のステートメントが値を持つ行を削除するためです。NULLINWHERENULL

これを修正するには、usertagview.tag_id IN ...チェックを結合のON句に移動します。

ただし、これは問題の半分にすぎません。ユーザーが入力した特定のタグのビューのみを確認していますが、実際の要件を理解している場合は、検索用語に一致するタグを持つ画像に関連付けられているタグのビューを確認する必要があります。

たとえば、ユーザーflowerが「」と入力すると、最初に、でタグ付けされた画像を検索しflower、次にその画像セットの他のすべてのタグのビューを確認する必要があります。

次のクエリでこれが達成されると思います。このSQLFiddleは、クエリの動作を示しています

SELECT
  i.id AS image_id,
  i.title AS image_title,
  IFNULL(SUM(utv.view_count), 0) AS associated_view_totals
FROM
  imagetag originalTag
  JOIN imagetag associatedTags 
    ON associatedTags.image_id = originalTag.image_id
  JOIN image i 
    ON i.id = associatedTags.image_id
  LEFT JOIN usertagview utv 
    ON utv.user_id = 1
    AND utv.tag_id = associatedTags.tag_id
WHERE
  -- User searches for flower tag (Let's assume 5 == flower)...
  originalTag.tag_id IN (5)
GROUP BY
  i.id,
  i.title
ORDER BY 
  associated_view_totals DESC
于 2012-05-03T22:28:40.913 に答える
3

これは一般的な問題です。そして幸いなことに、簡単に解決できます。

これを見ますか?

LEFT JOIN usertagview ON
    usertagview.tag_id = imagetag.tag_id -- see this?
    AND usertagview.user_id = {$user_id_from_php}  

WHERE

    imagetag.tag_id IN ( {impolde(',', $array_of_id_of_tags_that_the_user_has_entered)} )
    AND

この?

    usertagview.tag_id IN -- and this?
        (SELECT tag_id FROM imagetag WHERE userimagetag.image_id = image.id)

両方の条件は同じフィールドを共有しますusertagview.tag_id。そのusertagview.tag_id IN (SELECT tag_id FROM ...)ため、WHERE句では、基本的にLEFT JOIN、imagetagのingでusertagviewが成功した場合はキャンセルされます。

したがって、クエリを修正するには、INNER JOIN-y usertagviewをLEFT JOIN1に復元してから、代わりにusertagview条件をJOIN条件に移動します。

SELECT

    DISTINCT (image.id) AS image_id,
    image.title AS image_title,
    SUM(usertagview.view_count) AS SUM_of_all_tag_views_for_each_image

FROM (image)

JOIN imagetag ON imagetag.image_id = image.id

LEFT JOIN usertagview ON
    usertagview.tag_id = imagetag.tag_id
    AND usertagview.user_id = {$user_id_from_php}

    -- moved the WHERE condition here
    AND
    usertagview.tag_id IN
        (SELECT tag_id FROM imagetag WHERE userimagetag.image_id = image.id)


WHERE

    imagetag.tag_id IN ( {impolde(',', $array_of_id_of_tags_that_the_user_has_entered)} )

ORDER BY SUM_of_all_tag_views_for_each_image DESC

それはそれを修正するでしょう。そうでない場合(テーブル上で互いに1対多、または1対1であるかどうかは正確にはわかりません。したがって、この場合は、通常は機能するものをスローします。 )、をに変更してみてINNER JOIN imagetagくださいLEFT JOIN。また、imagetagWHERE句の条件は、条件の結果として生じる行をすべてキャンセルするため、その条件を句から同様LEFT JOINに移動します。imagetagWHERELEFT JOIN

SELECT

    DISTINCT (image.id) AS image_id,
    image.title AS image_title,
    SUM(usertagview.view_count) AS SUM_of_all_tag_views_for_each_image

FROM (image)

LEFT JOIN imagetag ON imagetag.image_id = image.id
    -- WHERE clause condition moved here.
    -- WHERE conditionXXX basically cancels out whatever rows
    -- obtained from `LEFT JOIN ON conditionXXX`, in which conditionXXX share
    -- the same field.  IN this case, it is imagetag.
    AND    
    imagetag.tag_id IN ( {impolde(',', $array_of_id_of_tags_that_the_user_has_entered)} )


LEFT JOIN usertagview ON
    usertagview.tag_id = imagetag.tag_id
    AND usertagview.user_id = {$user_id_from_php}

 -- moved here
    AND
    usertagview.tag_id IN
        (SELECT tag_id FROM imagetag WHERE userimagetag.image_id = image.id)



ORDER BY SUM_of_all_tag_views_for_each_image DESC

また、2番目の提案でも結果が得られない場合、クエリは現在、複数の1対多のテーブル関係を処理しています。クエリに複数の1対多のテーブルリレーションがある場合、SQLは意図を理解できません。この場合、正しい出力を得るには、結果をフラット化する必要があります。結果をフラット化する方法についての優れたウォークスルーは次のとおりです。http ://www.anicehumble.com/2012/05/sql-count-computer-program-does-what.html

于 2012-05-03T23:05:25.613 に答える
1

次/後に何に参加するかに関係なく、常にテーブル画像+INNERJOIN画像タグの結果を取得します。より多くの結果が必要な場合は、imagetagテーブルもLEFTJOINする必要があります。

于 2012-05-01T08:34:18.133 に答える