2

私は有名人の写真のウェブサイトを持っています。と呼ばれる各写真のすべての検索可能なデータを保持する 1 つのテーブルがあり、データの完全なセットは、photoSearch、 、 という名前の多くのテーブル (正規化) に分散されます。photosphotoPeoplepeople

テーブルには写真 ID と人物 ID が含まれphotoPeoplepeopleテーブルには人物 ID と人物の名前が含まれます。表には、photosキャプション、見出し、高さ、幅、ファイル サイズ、販売コードなどが含まれます。

これは、良い結果を生み出す現在のスクリプトです。

SELECT 
     p.photoID, 
     p.setID, 
     p.headline, 
     p.caption,
     GROUP_CONCAT(pe.people ORDER BY pe.people ASC SEPARATOR ';') AS people
FROM 
     photos p
INNER JOIN
     (
        SELECT photoID 
        FROM photoSearch 
        WHERE MATCH (allKeywords, shortCaption)
        AGAINST ('+red +dress +claridges +hotel' IN BOOLEAN MODE) 
        LIMIT 50
     ) pids ON p.photoID = pids.photoID
***********
LEFT JOIN
     photoPeople pp ON p.photoID = pp.photoID
LEFT JOIN
     people pe ON pp.peopleID = pe.peopleID
***********
GROUP BY p.photoID

問題は、有名人の名前を選択して結果に表示するのではなく、1 人以上の有名人の名前を検索して結果を変更したいということです。

同じ列に 2 つ以上の where 句 (where pe.people = 'angelina jolie' および pe.people = 'brad pitt') を追加することはできないと確信しているので、そうする必要があると確信しています。 JOINSを使用して行われます。

これは私を少し混乱させました。だから私はここSOで質問して、これを達成する方法を見つけ、誰かがこれをアドバイスしました:

「'photoPeople' テーブルと 'people' テーブルにn回参加します。ここで、nは検索する人の数です。」

これを達成するためにさまざまな方法を試しましたが、これまでのところ失敗しています。彼が言ったことには、2行のアスタリスク(上記のコード)の間の結合を削除し、それらをpeople テーブルへのn個の結合に置き換えることが含まれていることを知っていますが、私はそれを理解できません.

私はこれを試しましたが、phpMyAdmin はこの 10 分間ずっと考えていました!:

********
JOIN ( photoPeople AS pp1 JOIN people AS p1 ON pp1.peopleID = p1.peopleID) 
ON p1.people = 'Brad Pitt'
JOIN ( photoPeople AS pp2 JOIN people AS p2 ON pp2.peopleID = p2.peopleID) 
ON p2.people = 'Angelina Jolie'
********

FOREVER を取る上記の試みに加えて、GROUP_CONCAT 関数を変更して複数の結合/エイリアス (p1、p2、p3 など) から結果を取得する方法を理解するのにも苦労しています!

これを正しく機能させるためのアドバイスをお願いします。


テストシナリオ

クエリをそのまま実行すると、次のように表示されます。

Photo:    120030
Set:      8803
Headline: Brad and Angelina arrive at film premiere.
People:   Brad Pitt; Angelina Jolie

Photo:    120031
Set:      8803
Headline: Brad and Angelina arrive at film premiere.
People:   Angelina Jolie

Photo:    120032
Set:      8803
Headline: Brad and Angelina arrive at film premiere.
People:   Brad Pitt

新しいクエリで名前を検索したいので、Angeline Jolie と Brad Pitt を検索すると、次のように表示されます。

Photo:    120030
Set:      8803
Headline: Brad and Angelina arrive at film premiere.
People:   Brad Pitt; Angelina Jolie

新しい試み:

エラーはありませんが、0 件の結果が返されました。「フランス」の「ブラッド ピット」と「アンジェリーナ ジョリー」の結果は 1000 件あるはずです。

SELECT 
     p.photoID, 
     p.setID, 
     p.headline, 
     p.caption,
     GROUP_CONCAT(pe.people ORDER BY pe.people ASC SEPARATOR ';') AS people
FROM 
     photos p
INNER JOIN
     (
        SELECT photoID 
        FROM photoSearch 
        WHERE MATCH (allKeywords, shortCaption)
        AGAINST ('+France' IN BOOLEAN MODE) 
        LIMIT 50
     ) pids ON p.photoID = pids.photoID
LEFT JOIN
     photoPeople pp ON p.photoID = pp.photoID
JOIN
     people pe ON pp.peopleID = pe.peopleID
     AND (pe.people = 'Angelina Jolie' OR pe.people = 'Brad Pitt')
GROUP BY p.photoID

INNER JOIN セクションを削除してこれを実行すると、Brad と Angelina が一緒にいるかどうかに関係なく、すべての写真が返されますが、これは正しくありません。一緒に必要なだけです。も削除するとOR pe.people = 'Brad Pitt'、アンジェリーナの写真が正しく返されますが、すべてをリンクすることはできません!

4

2 に答える 2

2

リストからすべての人物が写っている写真を検索するには、次を使用します。

SELECT 
     p.photoID, 
     p.setID, 
     p.headline, 
     p.caption,
     GROUP_CONCAT(pe.people ORDER BY pe.people ASC SEPARATOR ';') AS people
FROM 
     photos p
INNER JOIN
     (
        SELECT photoID 
        FROM photoSearch 
        WHERE MATCH (allKeywords, shortCaption)
        AGAINST ('+red +dress +claridges +hotel' IN BOOLEAN MODE) 
        LIMIT 50
     ) pids 
   ON p.photoID = pids.photoID

INNER JOIN
     photoPeople pp ON p.photoID = pp.photoID
INNER JOIN
     people pe ON pp.peopleID = pe.peopleID
-- List of people
WHERE pe.People in ('Angelina Jolie', 'Brad Pit')
GROUP BY p.photoID
-- "2" must match number o people in the list
-- If you add third name, change this to 3
HAVING count(distinct pe.People) = 2

左の結合を内部に変更したのは、whereそれらをそのように扱うため (null は何とも比較されないため)、一致しない写真が受け入れられた場合、その質問は意味をなさないと感じたためです。

PS すべての Angelinas をすべての写真に結合し、すべての Brads をすべての写真に結合して膨大な数のレコードを生成したため、あなたの試みはうまくいきませんでした。上記のクエリと同じ結果を生成するために PhotoID で 2 つの派生テーブルを結合した可能性がありますが、3 番目の名前を追加するには別の派生テーブルが必要になります。

SELECT photos1.PhotoID
FROM
(
  SELECT pp1.PhotoID
    FROM photoPeople AS pp1 
    JOIN people AS p1 ON pp1.peopleID = p1.peopleID
   WHERE p1.people = 'Brad Pitt'
) photos1
JOIN 
(
  SELECT pp2.PhotoID
    FROM photoPeople AS pp2
    JOIN people AS p2 ON pp2.peopleID = p2.peopleID
   WHERE p2.people = 'Angelina Jolie'
) photos2
  ON photos1.PhotoID = photos2.PhotoID

UPDATE : 条件を組み合わせてlimit 50不一致の可能性を回避します。

SELECT 
     p.photoID, 
     p.setID, 
     p.headline, 
     p.caption,
     GROUP_CONCAT(pe.people ORDER BY pe.people ASC SEPARATOR ';') AS people
FROM 
     photos p
INNER JOIN
     (
        SELECT distinct ps.photoID 
        FROM photoSearch ps
        INNER JOIN
             photoPeople pp ON ps.photoID = pp.photoID
        INNER JOIN
             people pe ON pp.peopleID = pe.peopleID
     -- List of people
        WHERE pe.People in ('Angelina Jolie', 'Brad Pit')
          AND MATCH (allKeywords, shortCaption)
              AGAINST ('+red +dress +claridges +hotel' IN BOOLEAN MODE) 
        GROUP BY ps.photoID
     -- "2" must match number o people in the list
     -- If you add third name, change this to 3
        HAVING count(distinct pe.People) = 2
        LIMIT 50
     ) pids 
   ON p.photoID = pids.photoID
INNER JOIN
     photoPeople pp ON p.photoID = pp.photoID
INNER JOIN
     people pe ON pp.peopleID = pe.peopleID
GROUP BY p.photoID

再編集:メイン クエリに人関連の結合を残すのを忘れていたことに気付きました。

于 2012-09-10T23:37:53.757 に答える
1

photoPeople がない写真はありますか? それとも人がいない写真の人?そうでない場合は、左結合ではなく通常の結合を使用してください。その後、そのクエリに追加の where 句を追加できます

where (people = "Brad Pitt" or people = "Angelina Jolie")

左結合を維持する必要がある場合は、ON にさらに条件を追加できます。

... ON pp.peopleID = pe.peopleID and (people = "Brad Pitt" or people = "Angelina Jolie")

アップデート:

私の脳は、ニコラの結合ではなく、自己結合バージョンを見ていました。

select pp1.photoId
from photoPeople pp1, people p1, photoPeople pp2, people p2
where pp1.peopleID = p1.peopleID
and p1.people = "angelina"
and pp2.peopleID = p2.peopleID
and pp1.photoId = pp2.photoId
and p2.people = "brad"

しかし、それは私が構築した、一致数に基づいてランクが必要なシステムを思い出しました。UNIONS の方が簡単です。

 SELECT photoID, count(*) as rank
 from (
  SELECT pp.PhotoID
    FROM photoPeople AS pp 
    JOIN people AS p ON pp.peopleID = p.peopleID
    WHERE p.people = 'Brad Pitt'
  UNION
  SELECT pp.PhotoID
    FROM photoPeople AS pp 
    JOIN people AS p ON pp.peopleID = p.peopleID
    WHERE p.people = 'Angelina Jolie'
 ) foo
 group by photoID
 order by rank desc

私はニコラに賛成票を投じます:)

于 2012-09-10T23:31:32.787 に答える