The intersect keyword is not available in mysql. I want to know how to implement the following in mysql db. My tables are:
customer(cid,city,name,state)
orders(cid,oid,date)
product(pid,price,productname)
lineitem(lid,pid,oid,totalquantity,totalprice)
I want the products bought by all the customers of a particular city 'X'. i.e. every customer in city 'x' should have bought the product. I managed to select the oid's and the pid's of customers living in that particular city. Now I should select the pid's which is present in all the oid's.
Example.
Oid Pid
2400 1
2400 2
2401 3
2401 1
2402 1
2403 1
2403 3
The answer from the above input should be 1 because it is present in all oid's. The query which I used to get the oid's and pid's:
select t.oid,l.pid
from lineitem l
join (select o.oid,c1.cid
from orders o
join (select c.cid
from customer c
where c.city='X') c1
where o.cid=c1.cid) t on l.oid=t.oid
Now I need to intersect all the oid's and get the result.The query should not be dependent on data.
Try:
select pid, count(*)
from (select t.oid, l.pid
from lineitem l
join (select o.oid, c1.cid
from orders o
join (select c.cid from customer c where c.city = 'X') c1
where o.cid = c1.cid) t
on l.oid = t.oid) x
group by pid
having count(*) = (select count(*)
from (select distinct oid
from lineitem l
join (select o.oid, c1.cid
from orders o
join (select c.cid
from customer c
where c.city = 'X') c1
where o.cid = c1.cid) t
on l.oid = t.oid) y) z
I think you can achieve what you want by using IN
Related
I have these below 5 tables and I am trying to find customers that ordered from the same category they clicked. With a condition where order date should be greater than the click date
Table: customers
email cid
a#gmail.com 1001
b#gmail.com 1002
c#gmail.com 1003
Table : orders
cid pid order_date
1001 4000 Aug-1-2021
1002 5000 Aug-1-2021
1003 4000 Aug-1-2021
Table : clicks
cid pid click_date
1001 4000 Jul-1-2021
1002 8000 Jul-1-2021
1003 8000 Jul-1-2021
Table : product
pid category_id
4000 1
8000 2
5000 2
Table : dim
categorty_id category
1 Games
2 Books
3 Music
Expected results
email cid category_clicked category_ordered
a#gmail.com 1001 games games
b#gmail.com 1002 books books
c#gmail will be excluded because he ordered a different category than the one he clicked. I am not able to get how to fetch the data based on the category. I was only able to write a query to fetch if customers bought the same item they clicked.
Any help is appreciated. This is the query i have to find exactly what customer clicked & bought the same pid.
select distinct cust.email
From customers cust
Join orders o
on cust.cid=o.cid
join clicks c
on c.cid=o.cid and c.pid=o.pid
Join product prod
ON c.pid=prod.pid
inner join dim dim
on dim.category_id=prod.category_id
where o.order_date>=c.click_date
1. t1: join between the customers table and the orders and product
2. t2: join between the customers table and the clicks and product
3. result join t1 to t2 with t1.cid = t2.cid and t1.categorty_id = t2.categorty_id
4. join t1 to dim
select t1.email, t1.cid, dim.category as category_clicked, dim.category as category_ordered
From
(select cust.*,o.pid,o.order_date,prod.categorty_id
from customers cust
Join orders o on cust.cid=o.cid
Join product prod on o.pid=prod.pid) t1
join (select cust.*,c.pid,c.click_date,prod.categorty_id
from customers cust
Join clicks c on cust.cid=c.cid
Join product prod on c.pid=prod.pid ) t2
on t1.cid = t2.cid and t1.categorty_id = t2.categorty_id
join dim on dim.categorty_id= t1.categorty_id
where t2.click_date <= t1.order_date;
demo in db<>fiddle
For this, you must join 2 copies of product.
The 1st copy is used to fetch the category from orders and the 2nd to fetch the category from clicks, so that they can be compared:
SELECT c.email, c.cid,
d.category category_clicked,
d.category category_ordered
FROM customers c
INNER JOIN orders o ON o.cid = c.cid
INNER JOIN product po ON po.pid = o.pid
INNER JOIN clicks cl ON cl.cid = c.cid
INNER JOIN product pc ON pc.pid = cl.pid
INNER JOIN dim d ON d.category_id = po.category_id AND d.category_id = pc.category_id
WHERE cl.click_date <= o.order_date;
See the demo.
There are 3 types of adventures for which I used distinct function in query.
There is only one 1 customer who have booked all types of adventures.
The query i used to fetch the data is:
select c.customerid,c.name
from customer c
inner join booking b
on c.customerid = b.customerid
inner join destination d
on b.destinationid=d.destinationid
inner join adventure a
on d.adventureid=a.adventureid
group by c.customerid
having count(distinct b.bid)=(select count(*) from bid)
or count(distinct a.adventuretype)=(
select count(distinct a.adventuretype)
from adventure
)
You can get the customer ids using aggregation and having:
select b.customerid
from booking b join
destination d
on b.destinationid = d.destinationid join
adventure a
on d.adventureid = a.adventureid
group by b.customerid
having count(distinct a.advtype) = 3;
Or, if you don't want to hardcode the "3", you can use:
having count(distinct a.advtype) = (select count(distinct advtype from adventure)
I'll leave it up to you to add in the customer name (using join, exists, or in).
I have 2 tables with below description.
table 1: customer, columns : customer_id, source
table 2: source, columns: source, rank
one customer would have many sources, each source has a particular rank in the rank table, i need to fetch the data in such a way that for each individual customer which ever has a lowest ranked source i need to fetch those records.
Here is an example:
customer table data is
1 abc
2 efg
3 abc
1 efg
1 hij
2 hij
source table data is
abc 2
hij 1
efg 3
the result set should be:
1 hij
2 hij
3 abc
You could use either of the two queries below to satisfy your requirement.
QUERY 1
SELECT c.customer_id,
c.source
FROM customer c
INNER JOIN source s
ON c.source = s.source
WHERE s.rank = (SELECT Min(s1.rank)
FROM source s1 inner join customer c1 on s1.source = c1.source
WHERE c1.customer_id = c.customer_id)
QUERY 2
SELECT x.customer_id ,
c1.source
FROM
(SELECT c.customer_id ,
MIN(s.rank) AS MinRank
FROM customer c
INNER JOIN SOURCE s ON c.source = s.source
GROUP BY c.customer_id) x
INNER JOIN customer c1 ON x.customer_id = c1.customer_id
INNER JOIN SOURCE s1 ON s1.source = c1.source
AND s1.rank = x.MinRank;
UPDATE 1
This update is in response to your comment for 3 tables rather than 2 tables. The query below extends Query 1 when your schema is spread across 3 tables.
SELECT c.customer_id,
s.source_name
FROM customer c
INNER JOIN source s
ON c.cust_id = s.cust_id
INNER JOIN rank r
ON s.source_name = r.source_name
WHERE r.rank = (SELECT Min(r1.rank)
FROM customer c1
INNER JOIN source s1
ON s1.cust_id = c1.cust_id
INNER JOIN rank r1
ON r1.source_name = s.source_name
WHERE c1.cust_id = c.cust_id);
For Oracle:
select d.customer_id, d.source
from (
select
c.customer_id,
s.source,
row_number() over (partition by c.customer_id order by s.rank asc) as rn
from customer c
join source s
on c.source = s.source
) d
where d.rn = 1
;
A much simpler way. Try this -
select c.cid,c.sourceid,min(s.rankid)
from customer c inner join sourc s
on (c.sourceid=s.sourceid)
group by c.cid order by c.cid asc
Here's an SQLFiddle
Select a.customer_id,b.source
from
(select c.customer_id,min(s.rank) as rank
from customer c
inner join source s
on c.source=s.source
group by c.customer_id) as a
inner join source b
on a.rank = b.rank
customers
id INT PK
name VARCHAR
details
id INT PK
detail_name VARCHAR
customers_details
customer_id INT FK
detail_id INT FK
value INT
For each customer I have a set of details.
The following query will get all users that have the detail #2 equals to 10:
SELECT c.* FROM customers c
INNER JOIN customers_details cd ON cd.customer_id = c.customer_id
WHERE cd.detail_id = 2 AND cd.value = 10
My problem is that I need to get all customers that have 2 or more specific details. For example: I want to get all customers that have detail #2 = 10 AND detail #3 = 20.
Is there a simple way to do that using SQL?
I would do that:
select c.*
from customers_details cd
inner join customers c
on c.id = cd.customer_id
where cd.detail_id in (2,10)
group by cd.customer_id
having
sum(cd.detail_id = 2 and cd.value = 1) = 1
and sum(cd.detail_id = 10) = 1
What I do here is:
Grouping details by customer
Sum 1 if the condition is satisfied. If there is a detail = 2
Having filters only customers which has the both conditions
I use the WHERE clause in order to filter less results for HAVING filters again trying to avoid a full-scan.
Regards,
You're just looking for customers that have more than one detail ID, where one equals 2 and one equals 20?
SELECT c.customer_id, count (*) FROM customers c
INNER JOIN customers_details cd ON cd.customer_id = c.customer_id
WHERE cd.detail_id IN (2, 20)
GROUP BY c.customer_id
HAVING count(*) > 1
This should give you every customer_id that has a detail_id of 2 and a detail_id of 20
Use Group by and having
SELECT c.customer_id
, min(c.name) customer_name
, count(cd.customer_id) detailcount
FROM customers c
INNER JOIN customers_details cd ON cd.customer_id = c.customer_id
WHERE cd.Value is not null
group by c.customer_id
having COUNT(cd.customer_id)>=2
You can use count (distinct detail_id) = 2 to select all customers that have both detail ids
select c.* from customers_details cd
join customers c on c.id = cd.customer_id
where (detail_id = 2 and value = 10)
or (detail_id = 3 and value = 20)
group by customer_id
having count (distinct detail_id) = 2
select *
from customers as c
where exists (
select 1
from customer_details as cd
where
cd.customer_id = c.customer_id and
(detail_id = 2 and value = 10 or detail_id = 3 and value = 20)
having count(*) = 2
)
Be careful with parens. Not sure if some platforms might require a grouping on the subquery with a having clause. You can add a dummy group by like group by cd.customer_id if it does.
Not sure how to write this join for 2 tables. Here is some sample data to illustrate:
orders
-----------------------
| order_id | customer |
-----------------------
ABC12345 1
ABC12346 4
ABC12347 3
ABC12348 2
ABC12349 2
ABC12350 3
customers
-----------------------------------
| id | name | email |
-----------------------------------
1 James james#gmail.com
2 Alice alice#hotmail.com
3 Jimbo james#gmail.com
4 Jim james#gmail.com
5 Lucy lucy#yahoo.com
I have an order_id, which I already know. Let's use the first one in the table: ABC12345. As you can see, the customer ID is 1, so that order was placed by James. Now sometimes James has ordered again using different names but we know it's him because of his email address.
So how do I retrieve all of James' orders based on his email address of james#gmail.com, if I know one of his order numbers (ABC12345)?
Edit: Not sure I stressed this enough... James has ordered 3 times, using the same email address but names of James, Jim and Jimbo. I need all of his orders using james#gmail.com as the email address.
SELECT o2.order_id
FROM orders o1
INNER JOIN customers c1
ON o1.customer = c1.id -- get the customer for the first order
INNER JOIN customers c2
ON c1.email = c2.email -- find all customers with same email
INNER JOIN orders o2
ON c2.id = o2.customer -- find all orders for those customers
WHERE o1.order_id = 'ABC12345'
You can use this:
SELECT order_id
FROM orders
WHERE customer IN (
SELECT id
FROM customers
WHERE email = (SELECT c.email FROM customers c JOIN orders o ON c.id = o.customer WHERE o.order_id = 'ABC12345')
)
You need to first quantify the person of the order to the customer table... Then, get all customer IDs by that same email... THEN get the orders that qualify those customer IDs.
select o2.*
from orders o2
JOIN ( select c2.ID
from customers c2
join ( select c1.email
from orders o
join customers c1
on o.Customer = c1.ID
where
o.order_id = 'ABC12345' ) FoundTheEmail
on c2.email = FoundTheEmail.email
) as SameCustomerEMail
on o2.Customer = SameCustomerEMail.ID
SELECT order_id
FROM orders
WHERE customer IN (SELECT customer
FROM orders
WHERE order_id = 'ABC12345')
try this since james has only one order
SELECT orders.order_id, customers.name, customers.email
FROM orders
INNER JOIN customers ON customers.id = orders.customer
WHERE orders.orer_id = 'ABC12345'
The order ID is a UNIQUE number, then you will not have two orders with the same ID, why care about the customer name?
"Every order will have a Customer's ID."