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

时间:2011-11-28 21:21:33

标签: sql oracle join

我有像这样的USERS表

用户

user_id | username
1         tom
2         sam

我也有像这样的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

我的问题是我需要选择meta_keys active car ,但仅适用于有效值为1的用户所以我的结果集应该是这样的

user_id | user_name | user_meta_id | meta_key | meta_value
1         tom         1              active     1
1         tom         2              car        dodge

我尝试过一些东西,但是我无法得到这种结果集。这是我认为可行的方法

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)

问题在于我得到的结果集缺少汽车meta_key / meta_value

user_id | user_name | user_meta_id | meta_key | meta_value
1         tom         1              active     1

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

4 个答案:

答案 0 :(得分: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' )

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

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

答案 1 :(得分:3)

SELECT * FROM USERS
    LEFT JOIN USER_META ON 
        (USERS."user_id" = USER_META.”user_id” 
         AND (USER_META."meta_key" in ('active', 'car') 
WHERE USERS."user_id" IN (select USER_META."user_id" from USER_META 
                          where USER_META."meta_key" = 'active' 
                          AND USER_META."meta_value" = 1
                         )

答案 2 :(得分:0)

由于我没有要测试的Oracle实例,所以这是我的头脑,但是这些内容是:

SELECT  T1.user_ID, T1.user_name, T2.user_meta_id, T2.meta_key, T2.meta_value
FROM    USERS T1 JOIN USER_META T2 ON T1.user_id = T2.user_id
        AND ((T2.meta_key = 'active' AND meta_value = 1) OR (T2.meta_key = 'car')) 

答案 3 :(得分:0)

试试这个:

SELECT 
    um1.user_id, um1.user_name, um.user_meta_id, 
    um.meta_key, um.meta_value 
FROM 
    USER_META um, 
    (
        SELECT 
            um0.*, u0.user_name 
        FROM
            USER_META um0, USERS u0
        WHERE 
                u0.user_id = um0.user_id 
            and um0.meta_key = 'active' 
            and um0.meta_value= '1'
    ) um1
WHERE
    um.meta_key in ('active','car') 
    and um.user_id = um1.user_id