Transforming SQL query for product recommendation to Cypher query - memgraphdb

I have a recommendation system that uses SQL query similar to this one:
select B.* from user User1
join rating Rating1 on User1.user_id = Rating1.id and Rating1.value = 5
join product A on A.id = Rating1.product_id
join rating Rating2 on Rating2.product_id = A.id and Rating2.value = 5
join user User2 on User2.id = Rating2.user_id and User2.id <> User1.id
join rating RatingB on RatingB.user_id = User2.id and RatingB.value =5
join product B on B.id = RatingB.product_id
WHERE User1.id = 1;
This system recommends a product to a user if they didn’t buy that product yet. The recommendation is based on the rating of the product that they gave the best rating and it looks which other users also rated that product with the same rating.
How would this query look like in Cypher?

The mentioned SQL query would look something like this if it was written using Cypher:
MATCH (pA:PRODUCT)<-[r1:Rated {"rating":5}]-(n1:USER)-[r2:Rated {"rating":5}]->(pB:PRODUCT)
MATCH (n2:USER {id:1})-[r3:Rated {"rating":5}]->(pb)
WHERE n1.id != n2.id
RETURN pB;

Related

Customer details based on booking count

Write a query to display user id and user name where the number of seats booked by the user in the individual booking is greater than 1. Display records in ascending order by user name.
I have tried this query and I m getting errors. Please help me!!
select u.user_id,u.name
from users u join bookingdetails bd
on u.name=bd.name
join tickets t on u.user_id=t.user_id
group by u.name
having count(t.no_seats) > 1
order by u.name;
select distinct u.user_id,u.name from users u
join tickets t on u.user_id = t.user_id
where
u.user_id in( select user_id from tickets where no_seats>1)
order by u.name;
If I understand your assignment it looks like you should do
WITH cteBookings AS (SELECT bd.USER_ID, SUM(t.NO_SEATS) AS TOTAL_SEATS_BOOKED
FROM BOOKINGDETAILS bd
INNER JOIN PAYMENTS p
ON p.BD_ID = bd.BD_ID
INNER JOIN TICKETS t
ON t.TICKET_ID = p.TICKET_ID
GROUP BY bd.USER_ID)
SELECT DISTINCT b.USER_ID, u.USER_NAME
FROM USERS u
INNER JOIN cteBookings b
ON b.USER_ID = u.USER_ID
WHERE b.TOTAL_SEATS_BOOKED > 1
ORDER BY u.USER_NAME ASC
Best of luck.
According to the question, it asks for the individual bookings > 1
So, the solution is very simple i.e, for each ticket_id, the no of seats should be greater than 1.
SELECT DISTINCT(user_id),name
FROM Tickets inner join Users
USING (user_id)
WHERE no_seats>1
ORDER BY name;
It will simpler if you try it without joins.
A simple example using a subquery:
select user_id, name from users
where user_id = any(select distinct user_id from tickets where no_seats > 1)
order by name asc;

Calculated field returning same value SQL

I have an issue with the below sub-query:
(select AVG(retail)
from STOCK
where category = 'TOYOTA' or category = 'HONDA') as AVERAGE_SALE_PRICE
Entire query:
select
d.name, s.category,(select AVG(retail)
where category = 'TOYOTA' or category = 'HONDA') as AVERAGE_SALE_PRICE
from dealer d join stock s using (dealerID)
The issue is that this calculated field returns the same value for all the rows in the query, I understand that I may have add a GROUP BY but I am quite confused where...
Thanks for any help
Try this query:
select AVG(retail) as AVERAGE_SALE_PRICE, category
from STOCK
where category='TOYOTA' or category='HONDA'
group by category
Update.This should give you the desired results:
select
d.name,
s.category,
(select AVG(s.retail)
from stock s1
where s1.dealerID = s.dealerID
and (s1.category = 'TOYOTA' or s1.category = 'HONDA') as AVERAGE_SALE_PRICE
from dealer d
join stock s using (dealerID)

How to use LINQ Group By with Count

I want to convert the following SQL Query into Entity Framework + LINQ query. There are three tables Brands, Products and ProductReviews. Products table has BrandId as FK and ProductReviews has ProductId as FK.
SELECT Top 5 b.Id, b.ShortName, COUNT(r.Id) AS TotalReviews
FROM ProductsReviews r
INNER JOIN Products p ON r.ProductId = p.Id
INNER JOIN Brands b ON p.BrandId = b.Id
GROUP BY b.Id, b.ShortName
Order By TotalReviews desc
Basically, I want to display top 5 brands based on the reviews posted for the products of those brands. I want output like below:
Id ShortName TotalReviews
-----------------------------------------
76 Adidas 61
120 Yamaha 29
109 Tommy Hilfiger 26
61 Mothercare 25
31 Haier 22
pseudocode
var results =
( from r in ProductsReviews
join p in Products on r.ProductId equals p.Id
join b in Brands on p.BrandId equals b.Id
group c by new {
b.Id,
b.ShortName } into grp
select new {
Id = grp.key.Id,
ShortName = grp.key.ShortName,
TotalReviews = grp.Count()}
)
.OrderBy(x=>x.TotalReviews).Take(5);
It really depends on how your model is setup with EF.
If you have added relations in your model, the query could be as simple as
var result = context.ProductReviews.OrderByDescending(x => x.TotalReviews).Select(x => new { x.BrandId, X.Brand.ShortName, x.TotalReviews});
Because you are not selecting anything from Product, I am not including it in the query. If you have relationships in your EF, we would be able to use navigation properties such as x.Brand.Someproperty, and EF will handle creating the query based upon the model that you have setup.
the result variable will contain the query and once you access the values, the query will be executed. Lastly to only select the top 5 you would simply use the Take function like so
var result = context.ProductReviews.OrderByDescending(x => x.TotalReviews).Select(x => new { x.BrandId, X.Brand.ShortName, x.TotalReviews}).Take(5);
Regards
Louis

Linq left outer group by, then left outer the group

I've this query that i'm trying to put as linq:
select *
from stuff
inner join stuffowner so on so.stuffID = stuff.stuffID
left outer join (select min(loanId) as loanId, stuffownerId from loan
where userid = 1 and status <> 2 group by stuffownerId) t on t.stuffownerid = so.stuffownerid
left outer join loan on t.LoanId = loan.LoanId
when this is done, I would like to do a linq Group by to have Stuff has key, then stuffowners + Loan as value.
I can't seem to get to a nice query without sub query (hence the double left outer).
So basically what my query does, is for each stuff I've in my database, bring the owners, and then i want to bring the first loan a user has made on that stuff.
I've tried various linq:
from stuff in Stuffs
join so in StuffOwners on stuff.StuffId equals so.StuffId
join tLoan in Loans on so.StuffOwnerId equals tLoan.StuffOwnerId into tmpJoin
from tTmpJoin in tmpJoin.DefaultIfEmpty()
group tTmpJoin by new {stuff} into grouped
select new {grouped, fluk = (int?)grouped.Max(w=> w.Status )}
This is not good because if I don't get stuff owner and on top of that it seems to generate a lot of queries (LinqPad)
from stuff in Stuffs
join so in StuffOwners on stuff.StuffId equals so.StuffId
join tmpLoan in
(from tLoan in Loans group tLoan by tLoan.StuffOwnerId into g
select new {StuffOwnerId = g.Key, loanid = (from t2 in g select t2.LoanId).Max()})
on so.StuffOwnerId equals tmpLoan.StuffOwnerId
into tmptmp from tMaxLoan in tmptmp.DefaultIfEmpty()
select new {stuff, so, tmptmp}
Seems to generate a lot of subqueries as well.
I've tried the let keyworkd with:
from tstuffOwner in StuffOwners
let tloan = Loans.Where(p2 => tstuffOwner.StuffOwnerId == p2.StuffOwnerId).FirstOrDefault()
select new { qsdq = tstuffOwner, qsdsq= (int?) tloan.Status, kwk= (int?) tloan.UserId, kiwk= tloan.ReturnDate }
but the more info i get from tLoan, the longer the query gets with more subqueries
What would be the best way to achieve this?
Thanks

Using LINQ to get distinct items that do not join

I'm having problems running a LINQ query between two tables and returning an answer set that doesen't match.
TB_AvailableProducts
-Prod_ID
-Name
....
TB_Purchases
-Cust_ID
-Prod_ID
Is there a way to get all distinct products that a customer has not purchased by using 1 LINQ query, or do I have to be doing two separate queries, 1 for all products and 1 for purchased products, and compare the two?
This query will return all products, which do not have related record in purchases table.
int customerID = 1;
var query = from ap in context.TB_AvailableProducts
join p in context.TB_Purchases.Where(x => x.Cust_ID == customerID)
on ap.Prod_ID equals p.Prod_ID into g
where !g.Any()
select ap;
I don't think you need Distinct here if you don't have duplicated records in your products table.
Generated SQL query will look like:
SELECT ap.Prod_ID, ap.Name
FROM TB_AvailableProducts AS ap
WHERE NOT EXISTS (SELECT
1 AS C1
FROM TB_Purchases AS p
WHERE (1 = p.Cust_ID) AND (ap.Prod_ID = p.Prod_ID)
)

Resources