我有一个项目,我存储用户拥有的贴纸,我希望将用户与他们可以交易的其他用户进行匹配。
我的表格是:
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,其他用户有什么贴纸他们没有。但我还需要知道原始用户可以给其他用户的贴纸。
我创建了一个函数StickerNeeds
:
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
我现在正在尝试编写我的匹配代码,我可以让前20位用户给原始用户贴纸。然而,如果没有光标运行缓慢,计算一个他们需要的贴纸的数量是很困难的。
这是我目前所拥有的,但是我生成贴纸的最终声明不会返回任何内容。
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 :(得分: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
只需粘贴原始用户ID代替origin_User
即可答案 1 :(得分:0)
您的要求非常严格,我的查询与能够为需要贴纸的人贴纸的用户匹配。它优先考虑与能够为接收者提供最多贴纸的用户的匹配。
;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