Select buyers and sellers data from customer - sql

I have two tables Customer and Market
Select * from Customer :
customer_id | f_name | l_name
-------------------------------
1 | Sam | Brow
2 | Alex | Fore
3 | Marc | Lor
4 | Fab | Sow
Select * from Market
Orderid | Product | SellerID | BuyerID
-----------------------------------------
5 | Apple | 1 | 2
6 | Juice | 3 | 4
When doing this SELECT to have Sellers and buyers data, I have data of all customers.
SELECT c.f_name, c.l_name ,m.Orderid
FROM Customer c
INNER JOIN Market m ON m.BuyerID = c.customer_id OR m.SellerID = c.customer_id
Instead, I need to separate the data of buyers on their own and sellers on their own. I'd expect something like this :
Orderid | Seller_f_name | Buyer_f_name
----------------------------------------
5 | Sam | Alex
6 | Marc | Fab
Any idea please ?

You need to join the market table twice with customer table -
SELECT Orderid, C1.f_name Seller_f_name, C2.f_name Buyer_f_name
FROM Market M
LEFT JOIN Customer C1 ON M.SellerID = C1.customer_id
LEFT JOIN Customer C2 ON M.BuyerID = C2.customer_id;

Related

Getting an empty result with 'AND' operation and wrong result with 'OR' operation in SQL

I have two tables and I want to find out the customer_id and customer_name of all customers who bought product A and B both.
Customers table:
+-------------+---------------+
| customer_id | customer_name |
+-------------+---------------+
| 1 | Daniel |
| 2 | Diana |
| 3 | Elizabeth |
| 4 | Jhon |
+-------------+---------------+
Orders table:
+------------+--------------+---------------+
| order_id | customer_id | product_name |
+------------+--------------+---------------+
| 10 | 1 | A |
| 20 | 1 | B |
| 30 | 1 | D |
| 40 | 1 | C |
| 50 | 2 | A |
| 60 | 3 | A |
| 70 | 3 | B |
| 80 | 3 | D |
| 90 | 4 | C |
+------------+--------------+---------------+
In this example only the customers with id 1 and 3 have bought both the product A and B.
To find that i wrote this code -
SELECT distinct c.customer_id,
c.customer_name
from customers c inner join orders o
on c.customer_id = o.customer_id
where o.product_name = 'A' and o.product_name = 'B'
When I am doing this I am getting an empty result.
So tried to use OR -
SELECT distinct c.customer_id,
c.customer_name
from customers c inner join orders o
on c.customer_id = o.customer_id
where o.product_name = 'A' or o.product_name = 'B'
output -
customer_name customer_id
Daniel 1
Diana 2
Elizabeth 3
Based on OR it is working right but I am still not getting the result I am trying to find. Because customer with id 2 only bought A and not Product B. And Using AND bringing me an empty result.
I always feel confused with AND and OR operations. can someone help?
If you want both use aggregation:
select c.customer_id, c.customer_name
from customers c inner join
orders o
on c.customer_id = o.customer_id
where o.product_name in ('A', 'B')
group by c.customer_id, c.customer_name
having count(distinct product_name) = 2;
Note: This assumes that the data could have multiple rows for a customer and product. If that is not possible, just use count(*) = 2 for performance reasons.

SQL List other products bought and count buyers, by product originally purchased

After years of reading answers, it's finally time to ask a question myself.
I have a list of products purchased and unique customer IDs:
+---------+--------+
| Product | Buyer |
+---------+--------+
| Apples | Rod |
| Apples | Jane |
| Apples | Freddy |
| Bananas | Rod |
| Bananas | Jane |
| Bananas | Freddy |
| Bananas | Zippy |
| Pears | Rod |
| Pears | Zippy |
+---------+--------+
I want to produce the following output in Netezza SQL:
+-----------+-------------+------------------------+---------------------+
| Product A | Buyers of A | A Buyers Also Bought B | No of A Buyers of B |
+-----------+-------------+------------------------+---------------------+
| Apples | 3 | Bananas | 3 |
| Apples | 3 | Pears | 1 |
| Bananas | 4 | Apples | 3 |
| Bananas | 4 | Pears | 2 |
| Pears | 2 | Apples | 1 |
| Pears | 2 | Bananas | 2 |
+-----------+-------------+------------------------+---------------------+
..so that I can see, for each product, the total purchasers. Crucially, I also want to see, for each product, of those purchasers, how many bought other products within the same list. Edit: It's important to reiterate that I should not have any buyers appearing in columns for B if they didn't also buy product A.
What's the most efficient way to do this please?
(I'll then work out a percentage of B buying A, but that part's easy).
Thank you!
You can create a summary of counts and then cross join with itself, excluding same matches.
Like this:
SELECT
A.Product,
A.Buyers,
B.Product,
B.Buyers
FROM (
SELECT
Product
count(*) AS Buyers
FROM
ProductBuyers
GROUP BY
) AS A
CROSS JOIN (
SELECT
Product
count(*) AS Buyers
FROM
ProductBuyers
GROUP BY
) AS B
WHERE
A.Product != B.Product
The basic data on purchases in-common is a self-join and group by:
select p1.product, p2.product, count(*) as in_common
from purchases p1 join
purchases p2
on p1.buyer = p2.buyer
group by p1.product, p2.product;
To get the count for one (or the other) is then a join:
select p1.product, p2.product, pp.cnt, count(*) as in_common
from purchases p1 join
purchases p2
on p1.buyer = p2.buyer join
(select p1.product, count(*) as cnt
from purchases
group by p1.product
) pp
on pp.product = p1.product
group by p1.product, p2.product, pp.cnt;
Alternatively, you could use window functions:
select p1.product, p1.cnt, p2.product, count(*) as in_common
from (select p1.*,
count(*) over (partition by p1.product) as cnt
from purchases p1
) p1 join
purchases p2
on p1.buyer = p2.buyer
group by p1.product, p2.product, p1.cnt;
Here is a rextester showing it working.

Find supplier which supplies a product that others don't

I'm trying to write an SQL query which selects the supplier based on the fact that it can supply a product other suppliers cannot.
I have 2 columns:
Supplier and Product
How would I select all the suppliers which supply at least 1 product which other suppliers do not supply?
I currently have:
SELECT incart.product, incart.supplier
FROM incart
WHERE incart.product
HAVING count(incart.supplier)=1
;
Try this:
SELECT
i1.supplier
FROM incart i1
WHERE i1.product NOT IN(SELECT product
FROM incart i2
WHERE i1.supplier <> i2.supplier);
For example, for the following sample data:
| PRODUCT | SUPPLIER |
|---------|----------|
| 1 | a |
| 2 | b |
| 3 | b |
| 2 | c |
| 3 | c |
| 4 | c |
It will select suppliers a and c, because supplier a supplies product 1 which others don't, and supplier c supplies product 4 which others don't.
SQL Fiddle Demo

Get a count of rows not matching criteria

Given a simple table (order detail/history kind of thing) with a customer and a product:
+--------------------+
| customer | product |
+--------------------+
| Smith | p1 |
| Smith | p3 |
| Jones | p1 |
| Jones | p2 |
| Davis | p3 |
| Davis | p9 |
| Brown | p1 |
| Brown | p2 |
| Brown | p5 |
+----------+---------+
I want to list all customers that have never ordered product p1, i.e. Davis in the above data set.
This is where i started but, of course, it doesnt work and I can't think of where to go next:
select
customer,
count(*) as c
where product='p1'
and c = 0
Try this out:
select customer
from MyTable
where customer not in (select customer from MyTable where Product = 'P1')
Here is one way, using an aggregation query:
select customer
from t
group by customer
having sum(case when product = 'p1' then 1 else 0 end) = 0
This gives you all the customers in the table. If you have a separate list of customers, then you might use:
select customer
from customerTable
where customer not in (select customer from t where product = 'p1')
You can also use this approach
SELECT t.CustomerName
FROM Table t
WHERE NOT EXISTS (SELECT 1
FROM Table t2
WHERE t2.CustomerName = t.CustomerName
AND t2.ProductName = 'p1')

Inner join with multiple tables

I have these four tables:
PRODUCTS
---------
PRODUCT_ID
PRODUCT_TITLE
(other fields)
COLORS
---------
COLOR_ID
COLOR_NAME
MATERIALS
---------
MATERIAL_ID
MATERIAL_NAME
IMAGES
---------
IMAGE_ID
BIG
MED
SMALL
THUMB
SIZE
---------
SIZE_ID
SIZE_NAME
And also:
PRODUCT_COLOR
---------
PRODUCT_ID
COLOR_ID
PRODUCT_MATERIAL
---------
PRODUCT_ID
MATERIAL_ID
PRODUCT_SIZE
---------
PRODUCT_ID
SIZE_ID
PRODUCT_IMAGE
---------
PRODUCT_ID
IMAGE_ID
COLOR_ID (can be null)
MATERIAL_ID (can be null)
All the products can have a different color and/or material. E.g. I can have a product that has one or more material options but no colors associated and vice versa. The output should be something like this:
-----------------------------------------------------------------------------
| PRODUCT_ID | PRODUCT_NAME | COLOR_ID | MATERIAL_ID | IMAGE_ID | SIZE_ID |
-----------------------------------------------------------------------------
| 1 | T-SHIRT | 1 | null | 1 | 1 |
| 1 | T-SHIRT | 1 | null | 1 | 2 |
| 1 | T-SHIRT | 1 | null | 1 | 3 |
| 1 | T-SHIRT | 1 | null | 1 | 4 |
| 2 | JEANS | null | 1 | 2 | 1 |
| 2 | JEANS | null | 1 | 2 | 2 |
| 2 | JEANS | null | 1 | 2 | 3 |
| 2 | JEANS | null | 1 | 2 | 4 |
| 2 | JEANS | null | 1 | 2 | 5 |
| 3 | T-SHIRT VNECK | 2 | 2 | 3 | 1 |
| 3 | T-SHIRT VNECK | 2 | 2 | 3 | 2 |
| 3 | T-SHIRT VNECK | 3 | 2 | 4 | 1 |
| 3 | T-SHIRT VNECK | 3 | 2 | 4 | 2 |
| 3 | T-SHIRT VNECK | 4 | 3 | 5 | 1 |
| 3 | T-SHIRT VNECK | 4 | 3 | 5 | 2 |
-----------------------------------------------------------------------------
I have tried the following statement but it returns 0 rows:
SELECT PRODUCTS.PRODUCT_ID, PRODUCTS.PRODUCT_TITLE, COLORS.COLOR_ID, MATERIALS.MATERIAL_ID, IMAGES.IMAGE_ID, SIZE.SIZE_ID from PRODUCTS
INNER JOIN PRODUCT_COLOR ON (PRODUCTS.PRODUCT_ID = PRODUCT_COLOR.PRODUCT_ID)
INNER JOIN COLORS ON (COLORS.COLOR_ID = PRODUCT_COLOR.COLOR_ID)
INNER JOIN PRODUCT_MATERIAL ON (PRODUCTS.PRODUCT_ID = PRODUCT_MATERIAL.PRODUCT_ID)
INNER JOIN MATERIALS ON (MATERIALS.MATERIAL_ID = PRODUCT_MATERIAL.MATERIAL_ID)
INNER JOIN PRODUCT_IMAGE ON (PRODUCTS.PRODUCT_ID = PRODUCT_IMAGE.PRODUCT_ID)
INNER JOIN IMAGES ON (IMAGES.IMAGE_ID = PRODUCT_IMAGE.IMAGE_ID)
INNER JOIN PRODUCT_SIZE ON (PRODUCTS.PRODUCT_ID = PRODUCT_SIZE.PRODUCT_ID)
INNER JOIN SIZE ON (SIZE.SIZE_ID = PRODUCT_SIZE.SIZE_ID)
ORDER BY PRODUCTS.id_PRODUCT;
Any ideas?
You could do something like this:
select p.product_id,
p.product_name,
c.color_id,
m.material_id,
i.image_id,
s.size_id
from products p
left join product_color pc
on p.product_id = pc.product_id
left join colors c
on pc.color_id = c.colorid
left join product_material pm
on p.product_id = pm.product_id
left join materials m
on pm.material_id = m.material_id
left join product_image pi
on p.product_id = pi.product_id
left join images i
on pi.image_id = i.image_id
or c.color_id = i.color_id
or m.material_id = i.material_id
left join product_size ps
on p.product_id = ps.product_id
left join size s
on ps.size_id = s.size_id
I would advise you reviewing JOINs. There is a great visual explanation of joins online that will help you write these queries.
Well, you need to learn how to build joins, and the way I normally do it is by selecting one table and join the next one and the next one and the next one until I have the result I want.
select product_id, product_name
from products
next I join the first one I need so I go ahead and say
select p.product_id, p.product_name, pc.color_id
from products p
join product_color pc on (pc.product_id = p.product_id)
On the join it is important to figure out if I maybe have nothing to join with and I still want to see the line. So I rather use a left join
select p.product_id, p.product_name, pc.color_id
from products p
left join product_color pc on (pc.product_id = p.product_id)
That way you add each table to join. By the way. Is this homework?
If you just need IDs, keep it simple
select p.product_id,
p.product_name,
pc.color_id,
pm.material_id,
pi.image_id,
ps.size_id
from products p,
PRODUCT_COLOR pc,
product_material pm,
PRODUCT_SIZE ps,
PRODUCT_IMAGE pi
where
p.product_id = pc.product_id(+)
and p.product_id = pm.product_id(+)
and p.product_id = ps.product_id(+)
and p.product_id = pi.product_id(+);