简体   繁体   中英

oracle sql - find common items purchased between two users

Item - Id, Name,
PurchaseLog - Id, ItemId, CustomerId, PurchaseDate User - Id, UserName

For given two customer's usernams, find names of common items they purchased within last year.

Is this naive (or even correct)? :

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

You describe the basic requirement for an intersection query.

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

This will return a list of item.id and item.name that appear for both users.

This solution solution uses semi-joins witch should be optimal in your case because it doesn't need a distinct on the result. The / +inline / hint tells the optimizer to not use a temporary table on the user_items subquery. To improve performances you should use a column(a virtual column should be optimal for it) with user.userid constrained to be lowercase and use an index on it, so later you don't need to call lower on queries on it.

I also supposed you missed to specify the join condition between PurchaseLog and user tables in your query.

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')
    )
/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM