0

我有下表

user table
USER_ID    USER_NAME
1          smith
2          clark
3          scott
4          chris
5          john

property table
P_ID    PROPERTY
1       first_name
2       last_name
3       age
4       skill

user_property table
PV_ID    USER_ID    P_ID VALUE
1        1          1    Smith
2        1          2    A
3        1          3    34
4        1          4    Java
5        1          4    DB
6        2          1    Clark
7        2          2    B
8        2          3    39
9        2          4    Java
10       2          4    net
11       2          4    linux
12       3          1    Scott
13       3          2    C
14       3          3    31

我想编写一个查询,它将从上面的所有表中获取数据,如下所示:(如果可用,技能将是该用户的第一个技能,否则为空)

USER_ID USER_NAME FIRST_NAME LAST_NAME SKILL
1       smith     Smith      A         Java
2       clark     Clark      B         Java
3       scott     Scott      C         null

我已经尝试如下但遇到性能问题:

SELECT
  u.user_id,
  u.user_name,
  MAX(DECODE(p.property, 'first_name', text_value)) firstName,
  MAX(DECODE(p.property, 'last_name', text_value)) lastName,
  MAX(DECODE(p.property, 'age', text_value)) age,
  MAX(DECODE(p.property, 'skill', text_value)) skill
FROM user u,
  property p,
  user_property up,
WHERE u.user_id    = up.user_id
AND p.p_id = up.p_id
GROUP BY u.user_id,
  u.user_name;

我怎么能把它写成 Oracle 11g 的优化查询。

4

2 回答 2

0

我尝试了以下查询,但是得到了笛卡尔积。

with t as (
select u.user_id, u.user_name, up.p_id, up.value
from user_property up
join user u on u.user_id = up.user_id
where u.user_name = 'smith'
)
select u.user_id, u.user_name,
t_first_name.value first_name,
t_last_name.value last_name,
(select min(value) from t where t.user_id = u.user_id and t.p_id = 4) skill
from user u
left join t t_first_name on t_first_name.user_id = u.user_id and t_first_name.p_id = 1
left join t t_last_name on t_last_name.user_id = u.user_id and t_last_name.p_id = 2;

如果我执行下面的查询,我会得到 5,如我上面的例子中提到的(因为在我的 user_property 表中有 5 行 user_id 1 在示例中)

select count(u.user_id)
from user_property up
join user u on u.user_id = up.user_id
where u.user_name = 'smith'

因此,如果我执行下面的查询,我得到计数​​为 3,因为在我的使用表示例中有 3 行

with t as (
select u.user_id, u.user_name, up.p_id, up.value
from user_property up
join user u on u.user_id = up.user_id
where u.user_name = 'smith'
)
select count(u.user_id)
from user u
left join t t_first_name on t_first_name.user_id = u.user_id and t_first_name.p_id = 1
left join t t_last_name on t_last_name.user_id = u.user_id and t_last_name.p_id = 2;
于 2014-05-12T09:58:43.133 回答
0

查询的性能取决于表的大小以及这些表上的索引。在大多数情况下,最佳做法是在每个主键和外键上都有一个索引。无论如何,主键上的索引是必须的。当您删除行时,外键上的索引可以加快连接速度并防止表锁定。

您的查询的替代方法是使用更多连接而不是子选择,并使用 WITH 子句来简化它:

with t as (
  select u.user_id, u.user_name, up.p_id, up.value
  from user_property up
  join user u on u.user_id = up.user_id
)
select u.user_id, u.user_name,
    t_first_name.value first_name,
    t_last_name.value last_name,
    (select min(value) from t where t.user_id = u.user_id and t.p_id = 4) skill
from user u
left join t t_first_name on t_first_name.user_id = u.user_id and t_first_name.p_id = 1
left join t t_last_name on t_last_name.user_id = u.user_id and t_last_name.p_id = 2;

顺便说一句:这是一个不太适合 SQL 的数据模型。我希望这些用户属性是例外,并且数据库的其余部分具有更简洁的设计。

于 2014-05-09T11:08:19.543 回答