oracle sql - 查找在两个用户之间购买的常用项目

时间:2012-04-28 01:48:32

标签: sql oracle

项目 - Id,Name,
PurchaseLog - Id,ItemId,CustomerId,PurchaseDate 用户 - ID,用户名

对于给定的两个客户的用户名,找到他们去年购买的普通商品的名称。

这是天真(甚至是正确的)吗? :

select distinct item.id, item.name
from item i, PurchaseLog log_username1, PurchaseLog log_username2,  user user1, user user2
where lower(user1.username) = lower('UserName1') AND
      lower(user2.username) = lower('UserName2') AND
      log_username1.itemid = log_username2.itemid AND
      log_username2.itemid = i.itemid AND
      log_username1 >-- satisfy date contraint AND
      log_username2 >-- satisfy date contraint

2 个答案:

答案 0 :(得分:8)

您描述了交叉点查询的基本要求。

select item.id, item.name
from item, PurchaseLog p, user u
where lower(u.username) = lower('Username1')
AND p.user_id = u.user_id
and item.id = p.itemid
and p.purchasedate between SYSDATE and SYSDATE-365
INTERSECT
select item.id, item.name
from item, PurchaseLog p, user u
where lower(u.username) = lower('Username2')
AND p.user_id = u.user_id
and item.id = p.itemid
and p.purchasedate between SYSDATE and SYSDATE-365

这将返回为两个用户显示的item.id和item.name列表。

答案 1 :(得分:0)

此解决方案使用半连接,在您的情况下应该是最佳的,因为它不需要在结果上有明显区别。 / + inline / hint告诉优化器不要在user_items子查询上使用临时表。为了提高性能,你应该使用一个列(一个虚拟列应该是最佳的),user.userid被限制为小写并在其上使用索引,所以以后你不需要在它上面调用较低的。

我还认为您错过了在查询中指定PurchaseLog和用户表之间的连接条件。

with user_items as (
        select /*+inline*/ lower(username),itemid
        from PurchaseLog
            join user using (userid) /*you were missing this join in your query*/
        where  log_username >-- satisfy date contraint
    )
select item.id, item.name
from item i
where itemid in (
        select itemid
        from user_items
        where username = lower('UserName1')
    ) and itemid in (
        select itemid
        from user_items
        where username = lower('UserName2')
    )
/