我有一个简单的用户首选项表,如下所示:
id | user_id | preference_name | preference_value
这个表的唯一性是,如果user_id字段为null,则表示它是该首选项的默认值。我正在尝试获取用户的所有首选项,并且只有在没有为该用户指定实际值时才使用默认值。
所以基本上我需要:
SELECT * FROM user_preferences WHERE user_id = {userIdVar} OR user_id IS NULL;
但是,如果结果集中的另一行具有相同的preference_name和user_id的值,我想抛出user_id为null的结果。
有没有办法用单个SQL查询执行此操作,还是应该在代码中执行此操作?
答案 0 :(得分:4)
使用NOT EXISTS
:
SELECT up1.*
FROM user_preferences up1
WHERE ( NOT EXISTS(SELECT 1
FROM user_preferences up2
WHERE user_id = {userIdVar})
AND user_id IS NULL )
OR ( user_id = {userIdVar} );
答案 1 :(得分:1)
您可以通过多种方式执行此操作,但如果所有首选项都有默认值,或者您在其他地方有完整的首选项列表,我会这样做:
select
default_preferences.preference_name,
coalesce(
real_user_preferences.preference_value,
default_preferences.preference_value) as preference_value
from
(select * from user_preferences where user_id is null)
as default_preferences
left join
(select * from user_preferences where user_id = @user_id)
as real_user_preferences
on
real_user_preferences.preference_name = default_preferences.preference_name
你已经在MySQL和SQL Server上标记了你的问题,我不知道你正在寻找哪种方言。我知道SQL Server接受这种语法,但可能需要对MySQL进行一些调整。
编辑:funkwurm指出子查询使得这可能在MySQL上表现不佳。如果结果是一个问题,可以在没有子查询的情况下重写它
select
default_preferences.preference_name,
coalesce(
real_user_preferences.preference_value,
default_preferences.preference_value) as preference_value
from
user_preferences as default_preferences
left join
user_preferences as real_user_preferences
on
real_user_preferences.preference_name = default_preferences.preference_name
and real_user_preferences.user_id = @user_id
where
default_preferences.user_id is null
编辑2 :如果首选项没有默认值,则可以修改第一个版本以使用full join
而不是left join
,然后执行{{ 1}}来自默认值或用户特定的首选项,就像preference_name
一样。但是,第二个版本不容易修改。
答案 2 :(得分:0)
COALESCE返回提供的参数的第一个非空值:http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_coalesce
因此,如果您获取一组默认首选项并使用用户首选项加入它们,则可以使用列中的COALESCE填充正确的值。
答案 3 :(得分:0)
这应该可以选择第一行为NULL或者设置user_id变量,如果两者都设置了user_id变量,那么只显示每个preference_name一次。
SELECT
*
FROM
(
SELECT
*
FROM
user_preferences
WHERE
user_id = {userIdVar} OR
user_id IS NULL
ORDER BY
CASE WHEN user_id IS NULL THEN 1 ELSE 0 END
) sub_query
GROUP BY
preference_name
<强> SQL FIDDLE 强>