2012-04-13 5 views
2
でポイントを参加

Iこの参加テーブルがあります。Specifiy最小数はSQL

CREATE TABLE [TagMap](
[intItemId] [bigint] NOT NULL, 
[intTagId] [bigint] NOT NULL, 
CONSTRAINT [PK_TagMap_intItemId] PRIMARY KEY CLUSTERED 
(
[intItemId] ASC, 
[intTagId] ASC 
)) 

私SPROCがseedItemIdに関連付けられているタグを発見し、このように、これらのタグに関連付けられている他のintItemIdsを選択します: 10を言う - - 値が返されませんこれを下回る2 intItemIdsの間、私はにするために必要なもの

declare @baseTags table (intTagId bigint primary key clustered); 

INSERT INTO @baseTags (intTagId) 
SELECT TOP 20 t1.intTagId 
FROM TagMap t1 
WHERE t1.intItemId = 776 

SELECT TOP 500 t1.intItemId 
FROM TagMap t1 
     JOIN @baseTags t2 
     ON t1.intTagId = t2.intTagId 
GROUP BY t1.intItemId 
ORDER BY Count(*) DESC 

は、タグ団体の最小数を指定しています。言い換えれば、TagMapテーブルには、2つのintItemIdが共通する10個以上のintTagIdがあります。良いですが、それを選択します。それ以外の場合は無視します。

したがって、例えばこのデータ所与:

CREATE TABLE #TagMap(
[intItemId] [bigint] NOT NULL, 
[intTagId] [bigint] NOT NULL, 
CONSTRAINT [PK_TagMap_intItemId] PRIMARY KEY CLUSTERED 
(
[intItemId] ASC, 
[intTagId] ASC 
)) 

insert into #TagMap 
(intItemId, intTagId) 
values 
(1, 100),(1, 200),(1, 300), 
(2, 100),(2, 200),   (2, 500),(2, 600), 
(3, 100),     (3, 500),(3, 600) 

は、一致閾値が2であると仮定する。

シードがintItemId 1の場合、intItemId 2のみが返されます(2つの一致するタグID:100と200、intItemId 3には1:100があり、しきい値以下です)。

シードがintItemId 2の場合、intItemId 1とタグ3の両方が返されます(intItemId 1はタグId 100と200に一致し、intItemId 3はタグID 500と600に一致します)。

シードがintItemId 3の場合、intItemId 2のみが返されます(2つの一致するタグID:500と600、intItemIdは1未満です:100はしきい値未満です)。

どうすればいいですか?

乾杯、 マット

答えて

2
SELECT 
    [foreign].intItemID 
FROM 
    #TagMap AS [primary] 
INNER JOIN 
    #TagMap AS [foreign] 
    ON [foreign].intTagID = [primary].intTagID 
WHERE 
    [primary].intItemID = 1 
GROUP BY 
    [foreign].intItemID 
HAVING 
    COUNT(distinct [foreign].intTagID) >= @threshold 

これはかなりひどくスケールことに注意してください、、。用JOIN検索は「これらのタグの任意のを持っている」、とだけHAVING句で指定できるので、「これらのタグのすべてを持っています」。

私の経験からマイナーな最適化を行うことができますが、私が見つけた最も価値のあるアプローチは結果をより標準的なマッピングテーブルにキャッシュすることでした。必要に応じてそれらを更新する。 (非常に低い頻度で変更するタグデータの内容)

+0

パフォーマンスに関する警告をお寄せいただきありがとうございます。実際のデータでこれを使用すると、私を噛んでしまうかもしれません。 –

1

は、これは(1,2,3に@InterestItemを変え、そしてあなたが求めてきました結果を生成すると思われる)それを行うようだ:

declare @InterestItem int 
set @InterestItem = 1 
declare @Threshold int 
set @Threshold = 2 

select 
    tm2.intItemId, 
    COUNT(*) 
from 
    #TagMap tm1 
     inner join 
    #TagMap tm2 
     on 
      tm1.intTagId = tm2.intTagId and 
      tm2.intItemId <> tm1.intItemId 
where 
    tm1.intItemId = @InterestItem 
group by 
    tm2.intItemId 
having 
    COUNT(*) >= @Threshold 

現在、結果セットにCOUNTが含まれていますが、この作業を行う必要はありません。