我需要一个根据他所关注的电视节目为用户查找推荐电视节目的查询。 对此我有以下表格:
包含显示用户关注的表Progress
以及所见剧集的百分比(为了解决此问题,我们可以假设我在数据库中只有一个用户)
包含Suggested
,_id1
和_id2
的表格value
(值是展示次数为_id1
的广告连接的强度}和id = _id2
的节目:value
越多越好,节目的共同点就越多。
请注意,此表中应用了可转换属性,因此id1
和_id2
之间的连接强度与_id1
和_id2
相同。此外,没有两行,如ROW1._id1 = ROW2._id2 AND ROW1._id2 = ROW2._id1
包含有关电视节目详情的表格ShowCache
,例如姓名等。
以下查询是我正在尝试做的,但结果是一个空集:
SET @a = 0; //In other tests this line seem to be necessary
SELECT `ShowCache`.*,
(SUM(value) * (Progress.progress)) as priority
FROM `Suggested`,`ShowCache`, Progress
WHERE
((_id2 = Progress.id AND _id1 NOT IN (SELECT id FROM Progress) AND @a:=_id1)//There is a best way to set a variable here?
OR
(_id1 = Progress.id AND _id2 NOT IN (SELECT id FROM Progress) AND @a:=_id2))
AND `ShowCache`._id = @a //I think that the query fails here
GROUP BY `ShowCache`._id
ORDER BY priority DESC
LIMIT 0,20
我知道问题与变量的使用有关,但我无法解决。任何帮助都非常感谢。
PS:主要问题是(由于可交换的适当性),没有变量我需要两个查询,大约需要3秒才能开始执行(查询比上面的更复杂) 。我真的想做一个单一的查询来完成这个任务
PPS:我还与XOR操作绑定,导致无限循环?!?!?这是我试过的WHERE子句:
((_id2=Progress.id AND @a:=_id1) XOR (_id1=Progress.id AND @a:=_id2)) AND `ShowCache`._id = @a
编辑: 我在没有使用任何变量的情况下想出了这个WHERE条件:
(_id2 = Progress.id OR _id1 = Progress.id)
AND `ShowCache`._id = IF(_id2 = Progress.id, _id1,_id2)
AND `ShowCache`._id NOT IN (SELECT id FROM Progress)
它有效,但速度很慢。
答案 0 :(得分:1)
您尝试使用xor很聪明。如果你想获得不匹配的值,你想使用按位XOR,即^
Progress.id ^ _id1 ^ _id2
3 ^ 2 ^ 3 = 2
2 ^ 2 ^ 3 = 3
您可以使用此技巧来设置连接并真正简化您的查询(消除OR和NOT IN并在没有变量的一个查询中执行此操作。)
select users.name as username, showcache.name as show_name,
sum(progress * value) as priority from users
inner join progress on users.id = progress.user_id
inner join suggested on progress.show_id in (suggested.id_1, suggested.id_2)
inner join showcache on showcache.id =
(suggested.id_1 ^ suggested.id_2 ^ progress.show_id)
where showcache.id not in
(select show_id from progress where user_id = users.id)
group by showcache.id
order by priority desc;
我还设置了一个小提琴来演示它: http://sqlfiddle.com/#!2/2dcd8/24
要打破它。我用一个用户创建了一个用户表(但该解决方案适用于多个用户。)
选择和加入进展非常简单。建议的连接使用IN作为用OR
编写它的替代方法showcache的连接是按位XOR发生的地方。其中一个id链接到progress.show_id,我们想要使用另一个。
它确实包含一个不排除已从结果中观看的节目。我本可以把它改成不存在?但这种方式似乎更清晰。
答案 1 :(得分:0)
你在where子句中设置了两次@ a的值,这意味着查询实际上已经沸腾为:
...
WHERE ... AND `ShowCache`._id = _id2
MySQL以第一次遇到的顺序评估变量赋值,所以你应该保持@a常量直到子句的END,然后分配一个新值,例如
mysql> set @a=5;
mysql> select @a, @a+1, @a*5, @a := @a + 1, @a;
+------+------+------+--------------+------+
| @a | @a+1 | @a*5 | @a := @a + 1 | @a |
+------+------+------+--------------+------+
| 0 | 1 | 0 | 1 | 1 |
| 1 | 2 | 5 | 2 | 2 |
| 2 | 3 | 10 | 3 | 3 |
+------+------+------+--------------+------+
请注意,前3列中的@ a值保持不变,UNTIL mysql到达@a := @a +1
,之后@a有新值
所以也许你的查询应该是
set @a = 0;
select @temp := @a, ..., @a := _id2
where
((_id2 = Progress.id AND _id1 NOT IN (SELECT id FROM Progress) AND @temp =_id1)
...
etc...