3

次のようなデータベーステーブルがあります。

╔═════════════════╦════════════╗
║ ADVERTISEMENTID ║ CATEGORYID ║
╠═════════════════╬════════════╣
║               1 ║ A          ║
║               1 ║ C          ║
║               2 ║ A          ║
╚═════════════════╩════════════╝

これは基本的に次のことを意味します。

  • 広告#1は、 ACの2 つのカテゴリに属します。
  • 広告#2は 1 つのカテゴリAに属します。

ユーザーが ( A,B,C ) の可能なカテゴリのパラメーターを渡すとします。ここでは、可能なカテゴリのセットに広告#1のカテゴリがすべて含まれ、可能なカテゴリのセットに広告#2のカテゴリがすべて含まれているため、両方の広告が一致します。

ただし、ユーザーがパラメーターとして ( A,D ) などの別の可能なカテゴリのセットを渡す場合。ここでは、広告#2のみが一致し、広告#1は一致しません。これは、考えられるカテゴリのセットに#1のすべてのカテゴリが含まれているわけではないためです。

これを SQL で表現する方法がわかりません。つまり、考えられるカテゴリ ID のパラメータを指定して、テーブルから個別の広告 ID を取得する SQL クエリを作成します。

誰でも助けてもらえますか?

4

3 に答える 3

3

この問題には多くの解決策がありますが、私が使用しているのは、HAVING句で結果をフィルタリングすることです。

SELECT  advertisementID
FROM    TableName
GROUP   BY advertisementID
HAVING  SUM(CASE WHEN CategoryID IN ('A','B','C') THEN 1 ELSE 0 END) > 0 AND
        SUM(CASE WHEN CategoryID NOT IN ('A','B','C') THEN 1 ELSE 0 END) = 0

簡単な説明、

SUM(CASE WHEN CategoryID IN ('A','B','C') THEN 1 ELSE 0 END) > 0

それが行うことは、指定されたリストに一致するものをカウントすることです。CategoryIDリストから少なくとも 1 つの一致が必要です。別のもの、

SUM(CASE WHEN CategoryID NOT IN ('A','B','C') THEN 1 ELSE 0 END) = 0

CategoryID指定されたリストで一致しないものをすべてカウントします。今回は、結果をフィルタリングするために、値をゼロにする必要があります。

于 2013-03-29T11:47:58.033 に答える
2

これが集合内集合問題と呼ばれるものです。カテゴリのいずれかで一致を見つける最良の方法は、次のアプローチだと思います。

select ADVERTISEMENTID
from t
group by ADVERTISEMENTID
having sum(case when categoryid = 'A' then 1 else 0 end) > 0 or
       sum(case when categoryid = 'B' then 1 else 0 end) > 0 or
       sum(case when categoryid = 'C' then 1 else 0 end) > 0

つまり、これはadvertisementid各カテゴリ値を個別に比較して集計しています。ステートメントは、sum()それが存在する数を数えています。はor、これらのいずれかが真でなければならないと言っています。

サブセット関係の場合、一致しないものをカウントするための句をもう 1 つ追加します。

select ADVERTISEMENTID
from t
group by ADVERTISEMENTID
having (sum(case when categoryid = 'A' then 1 else 0 end) > 0 or
        sum(case when categoryid = 'B' then 1 else 0 end) > 0 or
        sum(case when categoryid = 'C' then 1 else 0 end) > 0
       ) and
       sum(case when categoryid in ('A', 'B', 'C') then 0 else 1 end) = 0

私がこの方法を好む理由は、非常に表現力があるからです。を に変更するorand、3 つのカテゴリすべてを要求することになります。

select ADVERTISEMENTID
from t
group by ADVERTISEMENTID
having sum(case when categoryid = 'A' then 1 else 0 end) > 0 and
       sum(case when categoryid = 'B' then 1 else 0 end) > 0 and
       sum(case when categoryid = 'C' then 1 else 0 end) > 0

セットから少なくとも 2 つの一致が必要な場合は、次を追加できcount(distinct)ます。

select ADVERTISEMENTID
from t
group by ADVERTISEMENTID
having (sum(case when categoryid = 'A' then 1 else 0 end) > 0 or
        sum(case when categoryid = 'B' then 1 else 0 end) > 0 or
        sum(case when categoryid = 'C' then 1 else 0 end) > 0
       ) and
       count(distinct categoryid) >= 2

等々。

于 2013-03-29T12:29:41.043 に答える
1

sqlfiddle で @JW のスキーマを使用する別の解決策は次のとおりです。

SELECT matchacat.advertisementID
FROM   (select distinct advertisementID
        from   TableName
        where  CategoryID in ('A', 'D')) AS matchacat
LEFT JOIN
      (select distinct advertisementID
      from   TableName
      where  not CategoryID in ('A', 'D'))AS notmatch
ON    (matchacat.advertisementID = notmatch.advertisementID)
WHERE notmatch.advertisementID is null

したがって、少なくとも 1 つの猫に一致する広告のセットを取得してから、一致しない猫を含む広告のセットを取得し、外部結合を使用して最初のセットから 2 番目のセットを削除します。

于 2013-03-29T12:08:17.400 に答える