使用Oracle实体属性值(EAV)数据库表中的WHERE子句左侧连接列

Mik*_*ike 3 sql oracle join

我有一个像这样的USERS表

USERS

user_id | username
1         tom
2         sam
Run Code Online (Sandbox Code Playgroud)

我也有这样的USER_META表

USER_META

user_meta_id | user_id | meta_key | meta_value
1              1         active     1
2              1         car        dodge
3              2         active     0
4              2         car        honda
Run Code Online (Sandbox Code Playgroud)

我的问题是我需要选择meta_keys activecar,但仅限于活动值为1的用户,所以我的结果集应该是这样的

user_id | user_name | user_meta_id | meta_key | meta_value
1         tom         1              active     1
1         tom         2              car        dodge
Run Code Online (Sandbox Code Playgroud)

我尝试了一些东西,但我不能得到这种类型的结果集.这是我认为可行的

SELECT * FROM USERS
LEFT JOIN USER_META 
   ON USERS."user_id" = USER_META 
   AND (USER_META."meta_key" = 'active' OR USER_META."meta_key" = 'car') 
WHERE (USER_META."meta_key" = 'active' 
AND USER_META."meta_value" = 1)
Run Code Online (Sandbox Code Playgroud)

这个问题是我得到一个缺少汽车meta_key/meta_value的结果集

user_id | user_name | user_meta_id | meta_key | meta_value
1         tom         1              active     1
Run Code Online (Sandbox Code Playgroud)

如何修改查询以获取所有元信息?谢谢.

Jus*_*ave 9

首先,这种实体 - 属性 - 值数据模型通常是一个非常糟糕的想法.您基本上重新实现了关系数据库为您提供的开箱即用的功能,并且查询很快就变得非常笨拙.通常,您需要在USER_META表中加入N次,以便将N个属性作为列或者为了对数据设置N个谓词.

在数据建模方面,如果您避免创建区分大小写的列名,那么未来的开发人员通常会感激不尽,因此他们不必每次都对每个标识符进行双引号.

由于你需要两个键,你应该可以做这样的事情(我假设它meta_value总是存储为一个字符串,即使它代表一个数字或布尔值)

SELECT usr."user_id",
       usr."user_name",
       meta."user_meta_id",
       meta."meta_key",
       meta."meta_value"
  FROM users usr
       JOIN user_meta meta ON (usr."user_id" = meta."user_id")
 WHERE meta."meta_key" in ('active', 'car')
   AND usr."user_id" IN (SELECT active."user_id"
                           FROM user_meta active
                          WHERE active."meta_key" = 'active'
                            AND active."meta_value" = '1' )
Run Code Online (Sandbox Code Playgroud)

它返回您发布的数据的预期结果

SQL> ed
Wrote file afiedt.buf

  1  with users as (
  2    select 1 "user_id", 'tom' "user_name" from dual union all
  3    select 2, 'sam' from dual
  4  ),
  5  user_meta as (
  6    select 1 "user_meta_id",
  7           1 "user_id",
  8           'active' "meta_key",
  9           '1' "meta_value" from dual union all
 10    select 2, 1, 'car', 'dodge' from dual union all
 11    select 3, 2, 'active', '0' from dual  union all
 12    select 4, 2, 'car', 'honda' from dual
 13  )
 14  SELECT usr."user_id",
 15         usr."user_name",
 16         meta."user_meta_id",
 17         meta."meta_key",
 18         meta."meta_value"
 19    FROM users usr
 20         JOIN user_meta meta ON (usr."user_id" = meta."user_id")
 21   WHERE meta."meta_key" in ('active', 'car')
 22     AND usr."user_id" IN (SELECT active."user_id"
 23                             FROM user_meta active
 24                            WHERE active."meta_key" = 'active'
 25*                             AND active."meta_value" = '1' )
SQL> /

   user_id use user_meta_id meta_k meta_
---------- --- ------------ ------ -----
         1 tom            1 active 1
         1 tom            2 car    dodge
Run Code Online (Sandbox Code Playgroud)