4

这个标题很残酷,但我不知道该怎么说。

我有一个与 user_id 相关联的键值表,该表在整个站点中存储用户首选项。如果用户没有进入并更新他们的任何设置,那么任何时候我要求一个键(比如“FAVORITE_COLOR”它将为空,所以我需要拉出我绑定到默认用户的默认设置,用户 ID = 0。

我正在考虑将 user_id = 0 结果 UNION 到查询的底部,但这只会导致重复。我不确定这是否可能,但我希望能够说些什么:

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 对,并且在执行可能的重复过滤客户端时我没有问题。

4

4 回答 4

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 为空,则 NVL 返回 expr2。如果 expr1 不为空,则 NVL 返回 expr1。

于 2010-07-21T17:02:52.120 回答
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 语法,但您可能可以将“left outer on 1 = 1”连接替换为某种交叉连接。

于 2010-07-21T17:05:04.490 回答
2

我会做这样的事情:

SELECT k_v.v FROM k_v WHERE userid IN (:userid, 0) ORDER BY userid DESC

并且只使用返回的第一行。

于 2010-07-21T17:35:55.057 回答
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
于 2010-07-21T17:03:18.170 回答