2016-05-03 12 views
2

私は、ユーザーが持っているステッカーを保存しているプロジェクトを持っており、ユーザーと取引できる他のユーザーと照合したいと思っています。カーソルを使用しないでSQL Serverのコードを一致させる

私が持っているテーブルは以下のとおりです。

User 
-------------- 
UserId 


Sticker 
------------- 
Id 


UserStickers 
------------- 
UserId 
StickerId 
Count 

例データ:

User 
------------- 
'FFE16530-E42B-48F5-9CE2-A4D58E94C1D1' 
'F4EF0B59-81AB-41BF-8FB8-BE4E138D294B' 
'F1A2F44A-EFD3-4AA9-8210-D4977C68E4A5' 
'148CFBB4-94D5-4F85-A2BF-A155EC60DF18' 

Sticker 
------------- 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 

UserStickers 
------------- 
'FFE16530-E42B-48F5-9CE2-A4D58E94C1D1', 1, 2 
'FFE16530-E42B-48F5-9CE2-A4D58E94C1D1', 2, 1 
'FFE16530-E42B-48F5-9CE2-A4D58E94C1D1', 3, 3 
'F4EF0B59-81AB-41BF-8FB8-BE4E138D294B', 1, 3 
'F4EF0B59-81AB-41BF-8FB8-BE4E138D294B', 2, 1 
'F4EF0B59-81AB-41BF-8FB8-BE4E138D294B', 4, 3 
'F4EF0B59-81AB-41BF-8FB8-BE4E138D294B', 5, 2 
'F4EF0B59-81AB-41BF-8FB8-BE4E138D294B', 6, 1 
'F1A2F44A-EFD3-4AA9-8210-D4977C68E4A5', 1, 2 
'F1A2F44A-EFD3-4AA9-8210-D4977C68E4A5', 4, 3 
'F1A2F44A-EFD3-4AA9-8210-D4977C68E4A5', 8, 2 
'F1A2F44A-EFD3-4AA9-8210-D4977C68E4A5', 10, 3 
'148CFBB4-94D5-4F85-A2BF-A155EC60DF18', 1, 1 
'148CFBB4-94D5-4F85-A2BF-A155EC60DF18', 4, 5 
'148CFBB4-94D5-4F85-A2BF-A155EC60DF18', 7, 2 
'148CFBB4-94D5-4F85-A2BF-A155EC60DF18', 8, 2 
'148CFBB4-94D5-4F85-A2BF-A155EC60DF18', 9, 2 
'148CFBB4-94D5-4F85-A2BF-A155EC60DF18', 10, 2 

私は与えられたユーザのためのベストマッチを見つけるしたいと思います。 IEでは、他のユーザーはステッカーを持っていません。しかし、元のユーザーが他のユーザーに与えることができるステッカーを知る必要があります。私は今、私のマッチングコードを記述しようとしています、と私は良いトップ20ユーザーが元のユーザーにステッカーを与えるために得ることができます

CREATE FUNCTION StickerNeeds (@UserId UNIQUEIDENTIFIER) 
RETURNS @StickerNeeds TABLE 
    (
    StickerId  INT 
    ) 
AS 
BEGIN 
    DECLARE @SearchUsersStickers TABLE 
    (
     StickerId int 
    ); 

    INSERT INTO @SearchUsersStickers 
    SELECT StickerId 
    FROM UserStickers 
    WHERE UserId = @UserId; 

    INSERT @StickerNeeds 
     SELECT 
      S.Id 
     FROM 
      Stickers S 
     LEFT JOIN 
      @SearchUsersStickers SUS 
     ON 
      S.Id = SUS.StickerId 
     WHERE 
      SUS.StickerId IS NULL  
    RETURN 
END 

は私が機能 StickerNeedsを作成しました。しかし、ステッカーが必要なものの数を計算することは、ゆっくりと実行されるカーソルなしでは困難であることが証明されています。

ここに私が現在持っているものはありますが、返すステッカーを生成する最後のステートメントは何も返しません。

DECLARE @UserId UNIQUEIDENTIFIER = 'FFE16530-E42B-48F5-9CE2-A4D58E94C1D1' 

DECLARE @UserMatches TABLE 
(
UserId UNIQUEIDENTIFIER, 
StickerTake int, 
StickerGive int 
); 

INSERT INTO @UserMatches 
SELECT TOP 20 
    UserId, 
    Count(*), 
    NULL 
FROM 
    UserStickers US 
INNER JOIN 
    StickerNeeds(@UserId) SUN 
ON 
    US.StickerId = SUN.StickerId 
WHERE 
    US.[Count] > 1 
GROUP BY 
    UserId 
ORDER BY 
    Count(*) DESC 

-- Find Stickers to Give AND UPDATE @UserMatches 
SELECT 
    UM.UserId, 
    COUNT(*) As StickerCount 
FROM 
    (SELECT 
      US.StickerId AS StickerId 
     FROM 
      dbo.UserStickers US 
     WHERE 
      US.UserId = @UserId 
      AND US.[Count] > 1 
     ) STG -- StickerToGive 
LEFT JOIN 
    UserStickers US 
ON 
    US.StickerId = STG.StickerId 
LEFT JOIN 
    @UserMatches UM 
ON 
    US.UserId = UM.UserId 
WHERE 
    US.StickerId IS NULL 
GROUP BY 
    UM.UserId 


SELECT * FROM @UserMatches 

理想的@UserMatchesは、起点ユーザーが取ることができるステッカーの数と発信元ユーザが与えることができるステッカーの数を一致したユーザーが含まれます。私はカーソルを使用しないで与えることはできません。

+0

http://stackoverflow.com/help/how-to-ask – Chris

+0

こんにちはクリス・MayhemSoftware @、どのようなあなたは私の時に拡大したいと思いますか? –

+0

あなたの質問にいくつかのテスト(ダミー)データを追加する気がしますか? –

答えて

1

これはテストされていないため、調整が必要な場合があります。しかし、私はそれがすべて複数のサブクエリを持つ単一のクエリで返されると思います。

select top 20 UserId, 
    (select count(*) from UserStickers u3 where u3.UserId = u1.UserId and u3.count > 1 and u3.StickerId not in (select StickerId from UserStickers u4 where u4.UserId = <origin_User> and u4.count > 1)) as CountOriginCanTake, 
    (select count(*) from UserStickers u5 where u5.UserId = <origin_User> and u5.count > 1 and u5.StickerId not in (select StickerId from UserStickers u6 where u6.UserId = u1.UserId and u6.count > 1)) as CountOriginCanGive 
from UserStickers u1 
where u1.StickerId not in (select StickerId from UserStickers u2 where u2.UserId = <origin_User> and u2.count > 1) 
and u1.count > 1 
group by UserId 
order by 2 desc 

だけだな要件はかなり厳しいですorigin_User

+0

エラーが発生しました: 複数の部分の識別子「u2.userId」をバインドできませんでした。 –

+0

申し訳ありませんが、私は誤植を持っていました.U2.IserIdはu4.UserIdだったはずです。また、私はいくつかの場所で "カウント> 1"が必要になると思います。私は答えを更新しました。 – Chris

+0

Okこれは今実行されていますが、しばらくしてからこのエラーを返します。 UserIdはGUIDなのでと思う?エラー: nvarchar値 '003082F0-35B8-434B-9BBE-AF0388205DE9'をデータ型intに変換すると、変換に失敗しました。 –

0

あなたの代わりに、元のユーザーIDを貼り付け、私のクエリは、ステッカーを必要とする人にステッカーを与えることができ、ユーザーにマッチします。受信者に最も多くのステッカーを付けることができるユーザーとのマッチングを優先します。

;WITH UserNeeds 
AS 
(
    SELECT UserId, StickerId 
    FROM User U 
    CROSS APPLY Sticker S 
    EXCEPT 
    SELECT UserId, StickerId 
    FROM UserStickers 
), 
UserGives 
As 
(
    SELECT UserId, StickerId, Num - 1 As Num 
    FROM UserStickers 
    WHERE Num > 1 
), 
PossibleMatches 
As 
(
    SELECT UG.UserId GivingUser, UG.StickerId, UN.UserId ReceivingUser, UG.Num 
    From UserNeeds UN 
    INNER JOIN UserGives UG 
     ON UN.StickerId = UG.StickerId 
), 
BestMatches 
As 
(
    SELECT GivingUser, ReceivingUser, Count(*) as Matches, ROW_NUMBER() OVER (PARTITION BY GivingUser ORDER BY COUNT(*) DESC) AS RN 
    FROM PossibleMatches 
    GROUP BY GivingUser, ReceivingUser 
) 
SELECT PM.* 
FROM PossibleMatches PM 
INNER JOIN BestMatches BM 
    ON PM.GivingUSer = BM.GivingUser AND PM.ReceivingUser = BM.ReceivingUser 
WHERE RN = 1 
ORDER BY PM.GivingUser, PM.ReceivingUser 
+0

最初の行でエラーが発生しました:UNION、INTERSECTまたはEXCEPT演算子を使用して結合されたすべてのクエリは、ターゲットリストに同じ数の式を持つ必要があります。 –

+0

@ Tom.Bowen89クエリを更新しました。もう一度お試しください。 –

+0

実際のデータベースにはたくさんのデータがあります。私のカーソルで約1分で結果が得られました。しかし、あなたの質問では、私は実行を終了する前にそれは12分になった。それが助けになるならば、トップ20を返すことだけが必要です。 –

関連する問題