我有以下表格
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
我想编写一个查询,它将从以上所有表中获取数据,如下所示:(如果可用,技能将是该用户的第一项技能,否则为null)
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的优化查询。
答案 0 :(得分: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;
BTW:这是一个不太适合SQL的数据模型。我希望这些用户属性是例外,数据库的其余部分设计更清晰。
答案 1 :(得分: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;