这个头衔是残酷的,但我不知道怎么说。
我有一个绑定到user_id的键值表,用于存储整个站点的用户首选项。如果用户没有进入并更新他们的任何设置,那么每当我要求一个密钥时(比如说“FAVORITE_COLOR”它将为null,所以我需要拉出我与默认用户绑定的默认设置, user_id = 0.
我正在考虑UNION的行,将user_id = 0的结果放到查询的底部,但这只会导致重复。我不确定它是否可能,但我还是喜欢能够说出类似的内容:
SELECT val FROM k_v WHERE user_id = 123 AND k = 'FAVORITE_COLOR'
UNION IF val IS NULL
SELECT val FROM k_v WHERE user_id = 0 AND k = 'FAVORITE_COLOR';
有什么好方法吗?
编辑:感谢您提供的所有帮助。如果你的用例只是抓住这个问题的单个值,那么来自dual的NVL正是你想要的,但是如果你打算在同一个查询中返回多个对,那么看一下其他的一些答案,因为他们可能实际上更有意义的实施。
我结束了ZeissS的建议,因为它很简单,仍然只有一个查询,可以使用多个k,v对,并且我在执行可能的重复过滤客户端方面没有问题。
答案 0 :(得分:6)
使用此,
select
nvl(
(SELECT val FROM k_v WHERE user_id = 123 AND k = 'FAVORITE_COLOR'),
(SELECT val FROM k_v WHERE user_id = 0 AND k = 'FAVORITE_COLOR')
) val
from dual
;
来自Oracle文档,
NVL(expr1,expr2) : NVL允许您使用查询结果中的字符串替换null(作为空白返回)。如果 expr1为null,然后NVL返回expr2。如果expr1不为null,则NVL返回expr1。
答案 1 :(得分:2)
您可以离开加入,然后选择最合适的一个:
SELECT
NVL(best.val, fallback.val) as val
FROM
(SELECT val FROM k_v WHERE user_id = 0 AND k = 'FAVORITE_COLOR') as fallback
left outer join (SELECT val FROM k_v WHERE user_id = 123 AND k = 'FAVORITE_COLOR') as best on 1 = 1
不确定oracle语法,但您可以替换“左外1 = 1”连接 某种交叉连接。
答案 2 :(得分:2)
我会做这样的事情:
SELECT k_v.v FROM k_v WHERE userid IN (:userid, 0) ORDER BY userid DESC
并且仅使用返回的第一行。
答案 3 :(得分:0)
SELECT nvl(k.k,kd.k) as k,
nvl(k.val, kd.val) as val
FROM (select * from k_v where user_id = 0) kd
full outer join
(select * from k_v where user_id = 123) k
on kd.k = k.k
WHERE 'FAVORITE_COLOR' in (k.k,kd.k)
我建议进行完全外连接,因为如果没有默认值或者没有特定于用户的结果,它将保证结果。如果不可能缺少默认值,则可以简化查询:
SELECT nvl(k_v.k,kd.k) as k,
nvl(k_v.val, kd.val) as val
FROM k_v kd
left outer join k_v
on kd.k = k_v.k
and k_v.user_id = 123
WHERE kd.k = 'FAVORITE_COLOR'
and kd.user_id = 0