1

项目 - Id、名称、
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
4

2 回答 2

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 列表。

于 2012-04-28T01:59:46.427 回答
0

该解决方案使用半连接,在您的情况下应该是最佳的,因为它不需要对结果进行区分。/ +inline / 提示告诉优化器不要在 user_items 子查询上使用临时表。为了提高性能,您应该使用 user.userid 限制为小写的列(虚拟列应该是最佳的)并在其上使用索引,因此以后您不需要在其上调用 lower 查询。

我还假设您错过了在查询中指定 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')
    )
/
于 2012-04-29T13:45:48.403 回答