mySQL using same table/fields multiple times in a single query - mysql

I have 2 tables in mySQL database :
customers
============
customer_id (1, 2 )
customer_name (john, mark)
orders
============
order_id = 123
customer_id = 1
customer_from_id = 2
Idea is to do single query on orders table joining customers table whereby
orders.customer_id = customers.customer_id
orders.customer_from_id = customers.customer_id
to get the "customer_name" by JOIN(ing) two tables.
So how do i do single query on "orders" and expand all (2) "customer_name" fields so result looks like this :
+--------+------------+---------------------+------------------+---------------------+
order_id customer_id customer_order_name customer_from_id customer_from_name
+--------+------------+---------------------+------------------+---------------------+
123 1 john 2 mark
+--------+------------+---------------------+------------------+---------------------+
It means using same table 2x in a query and
aliasing output field "customer_name" 2x with
"customer_order_name" and "customer_from_name".
It shall be simple but i am stuck.
Any help would be much appreciated.
Thank You.

Join twice and use prefix and give aliases:
select order_id, buyer.customer_id, buyer.customer_name, seller.customer_id as customer_from_id, seller.customer_name as customer_from_name from orders o
join customers seller on o.customer_from_id = seller.customer_id
join customers buyer on o.customer_id = buyer.customer_id;

select order_id, c1.customer_id as customer_id,
c1.customer_name as customer_order_name ,
c2.customer_id as customer_from_id,
c2.customer_name as customer_from_name
from orders o
left join customers c1 using (customer_id)
left join customers c2 on o.customer_from_id = c2.customer_id;
fiddle

Related

Show the amount of orders made by each customer from London

Given two tables: customers and orders
_____CUSTOMERS
customer_id
customer_name
contact_name
....
city
country
1
Alfreds Futterkiste
Maria Ander
....
Berlin
Germany
4
Around the Horn
Thomas Hardy
....
London
UK
______ORDERS
order_id
customer_id
employee_id
....
shipper_id
10254
14
5
....
2
10355
4
6
....
1
Show the amount of orders made by each customer from London. Hint: Your solution should contain two columns: customer_id and orders
I try
SELECT *
FROM orders
INNER JOIN customers ON customers.customer_id = orders.shipper_id
WHERE city ='London';
I think you can achieve this by joining the customer and order table then selecting customer_id from customer_table, and then with an aggregate count of orders
Example query:
SELECT
c.customer_id,
count(distinct o.order_id)
FROM customers as c
LEFT JOIN orders as o on o.customer_id = c.customer_id
WHERE c.city = 'London'
GROUP BY c.customer_id
You are most of the way there. You need a couple of things:
aggregation
fix the JOIN conditions
Does joining a "customer_id" to a "shipper_id" make sense? Not really -- and especially when both tables have a customer_id.
SELECT c.customer_id, COUNT(*) as num_orders
FROM customers c INNER JOIN
orders o
ON c.customer_id = o.customer_id
WHERE c.city = 'London'
GROUP BY c.customer_id;
I switched the two tables around. I just think it is more natural to go from customers to orders.
Note that this only returns customers who have at least one order. I am guessing that to become a "customer" someone has to make an order.

Joining the tables while manipulating SELECT

I am new to SQL and am wondering how to join two tables based on the user ID while, at the same time, manipulating one of the columns. I have the table of orders per ID, and another table with ID demographics. I want to sum the orders per ID, and then join the demographics information.
Separately, the codes work:
This one sums the orders per id up:
SELECT SUM(order) AS expenses, id
FROM orders
GROUP BY id;
And this one joins another table:
SELECT orders.id, demographics.*
FROM orders
JOIN demographics
ON orders.id = demographics.user;
But how can you do the two simultaneously? So the table becomes like:
id | expenses | demographics.1 | demographics.2 | demographics.3 | etc
SELECT orders.id, sum(order) as expenses, max(demographics.1), max(demographics.2),...
FROM orders
JOIN demographics
ON orders.id = demographics.user
Group by orders.id
select
o.id,
d.demographics.1,
d.demographics.2,
d.demographics.3,
sum (o.order) Expenses
from order o,
demographics d
where 1=1
and.o.id = d.user
group by
o.id

MySQL, Join two tables with one table?

I have one table customer, and one bill, and one sell.
Customer table
id-----name
Bill table
id-----customer_id
Sell table
id-----customer_id-----bill_id-----qtt-----price
A customer can have the records in the sell table with customer_id, and also have the bill record in the bill table with customer_id and this bill record has record in the sell table with bill_id.
This means a customer can have direct or indirect (in this case by passing the bill table) with sell table.
Now how to join tables that retrieve the total sell of a customer with ascending or deciding order?
Any idea?
I have tried many ways for example something like below, but none of them was working:
SELECT
sell.id AS sell_id,
customer.id,
bill.id AS bill_id,
customer.`name`,
sell.quantity*sell.price AS sell_price
FROM
customer_tb customer
JOIN bill ON bill.customer_id = customer.id
JOIN sell ON sell.customer_id = customer.id OR sell.bill_id = bill.id
NOTE: In case of bill table has a record in the sell table, the customer_id column is NULL and also same for the customer sell record the bill_id is NULL, this means in the sell table in the same entry only one of the (customer_id, bill_id) column has value.
You have the customer column in your sell tables, you don't need to join with bill table.
SELECT
customer.id,
customer.name,
SUM(sell.quantity * sell.price) AS total_amount
FROM customer_tb as customer
INNER JOIN sell
On sell.customer_id = customer.id
GROUP BY customer.id
You have to group your rows by the customer to get their sum independently
Your challenge is to look up the correct Customer.name for each Sell row.
You need to join Sell to Customer, and also join Sell to Bill to Customer.
How to do this?
FROM Sell s
LEFT JOIN Cust c1 ON s.customer_id = c1.id
LEFT JOIN Bill b on s.bill_id = b.id
LEFT JOIN Cust c2 ON b.customer_id = c2.id
That gives us:
s.id: the Sale id
s.quantity, s.price: the business details of the Sale
c1.name: the Customer name directly from the Sale's customer_id
c2.name: the Customer name indirectly through the Sale's bill_id
Because we use LEFT JOINs, either name can be NULL depending on which ids are null. And, I believe you favor using the direct name over the indirect name if you have both.
That means we use COALESCE() to choose one name from the two. Something like this
SELECT s.id, s.Quantity, s.Price,
COALESCE (c1.name, c2.name) name,
COALESCE (c1.id, c2.id) customer_id
FROM Sell s
LEFT JOIN Cust c1 ON s.customer_id = c1.id
LEFT JOIN Bill b on s.bill_id = b.id
LEFT JOIN Cust c2 ON b.customer_id = c2.id
But, if you have a chance to rework this database before you put a ton of data into it, please consider redesigning things to get rid of this ambiguity. It's going to drive you mad and cost you bigger servers if you have to make it work well with megarows.

Inverse of Inner join (Intersect) with multiple foreign keys

Hi I want to get opposite of intersect from two tables.
I have a sale table and purchase table. What I want to do is get all purchases ids where not included in the sales table.
sale table
sale_id (pk)
product_id (fk)
purchase_id (fk)
purchase table
product_id (fk)
purchase_id (pk)
SELECT DISTINCT purchase_id
, product_id
FROM
purchase
INNER JOIN sale
USING (purchase_id, product_id);
Here is an example:
If I run the above code, this will be the result.
purchase_id product id
1 1
1 2
1 4
2 1
2 3
Now I want to get:
purchase_id product id
1 3
2 2
In short I want to get inverse of above code. Thanks in advance.
Okay, I think I understand better now.
This should return any entry in purchase that have no matching entry in sales.
SELECT
`purchase`.`purchase_id`, `purchase`.`product_id`
FROM `purchase`
LEFT JOIN `sale` ON `sale`.`purchase_id` = `purchase`.`purchase_id` AND `sale`.`product_id` = `purchase`.`product_id`
WHERE
`sale`.`sale_id` IS NULL
ORDER BY
`purchase`.`purchase_id`, `purchase`.`product_id`
If you want to get all the purchases that have no related values in the sales table, you can use a LEFT JOIN:
select
p.purchase_id
from
purchase as p
left join sale as s on p.purchase_id = s.purchase_id
where
s.purchase_id is null;
"Unilateral" joins (LEFT JOIN, RIGHT JOIN) are useful when you want to get data from a table even if data in another related table does not exist. Of course, that means that you can filter data from one table when there's no related data in a second table.
Hope this helps.
Looking at your updated question and your comment, I think that you want all the possible combinations not used.
You'll need to split this in two steps:
First you need all the possible combinations of purchase_id and sale_id values (the "cartesian product" of both the sets).
Then you need to get all the combinations already used.
Finally you need to exclude all the combinations already used.
This can be done using subqueries.
Step 1.
select distinct p.purchase_id, s.product_id from purchase as p, sale as s;
Step 2. (Your query)
select distinct
purchase_id, product_id
from
purchase as p
inner join sale as s
on (p.purchase_id = s.purchase_id and p.product_id = s.product_id);
Step 3. Put it all together
select
a.*
from
(select distinct p.purchase_id, s.product_id from purchase as p, sale as s) as a
left join (
select distinct
purchase_id, product_id
from
purchase as p
inner join sale as s
on (p.purchase_id = s.purchase_id and p.product_id = s.product_id)
) as e on (a.purchase_id = e.purchase_id and a.product_id = e.product_id)
where
e.purchase_id is null and e.product_id is null;

WHERE value IS NOT IN (subquery)

I've been struggling with this query.
I have two tables. One with coupons and Invoicenumbers. One with Invoicenumbers and customer names.
I need to get the customers who have not used a given coupon.
Here are the tables:
Promotion table:
Promotions
Invoice | Coupon
----------------
1 | couponA
2 | couponB
3 | couponB
Orders Table:
Orders
Invoice | Customer
------------------
1 | Jack
2 | Jack
3 | Jill
So Jack has used coupons A and B. And Jill has only used coupon B.
If my query were select customers who have not used coupon A, I should get Jill.
This works, but it seems clumsy and slow. Is there a better way?
SELECT Customer
FROM Promotions INNER JOIN Orders
ON Promotions.Invoice = Orders.Invoice
WHERE Customer NOT IN(
SELECT Customer
FROM Promotions INNER JOIN Orders
ON Promotions.Invoice = Orders.Invoice
WHERE Coupon = couponA)
GROUP BY Customer
Thanks for looking!
edit:
Here's an SQLFiddle schema
http://sqlfiddle.com/#!2/21d31/6
Updated: We should use prefer to use joins for better performance when its easy to do for us. Join vs. sub-query
Sql Fiddle
Select distinct Customer from orders o
join
(
SELECT distinct Customer as changedname FROM Orders o2
join
(
Select distinct invoice from Promotions where Coupon='couponA'
) t3
on o2.invoice = t3.invoice
) t2
on o.customer != t2.changedname;
Note: I changed column name customer for t3 because two joined tables must have different column names
Explanation:
Using inner or sub query is expensive when you have big data. use joins instead, lets learn converting subquery to join
With Subquery We had:
Select distinct Customer from orders where customer not in
(SELECT distinct Customer FROM Orders where invoice in
(Select distinct invoice from Promotions where Coupon='couponA'));
Converting sub-query to join
First step:
Select distinct Customer from orders o
join
(
SELECT distinct Customer as changedname FROM Orders where invoice in
(Select distinct invoice from Promotions where Coupon='couponA')
) t2
on o.customer != t2.changedname;
2nd step:
Select distinct Customer from orders o
join
(
SELECT distinct Customer as changedname FROM Orders o2 where invoice
join
(
Select distinct invoice from Promotions where Coupon='couponA'
) t3
on o2.invoice = t3.invoice
) t2
on o.customer != t2.changedname;
And that's it, much faster for tables having numerous rows
Original answer:
Use not in. Have a look.
Select distinct Customer from orders where customer not in
(SELECT distinct Customer FROM Orders where invoice in
(Select distinct invoice from Promotions where Coupon='couponA'));
Edit I have added distinct to make query faster
SQL Fiddle
SELECT DISTINCT o2.customer FROM ORDER o2
LEFT JOIN (promotions p1
JOIN Orders o1 ON p1.cuopon = 'CuoponA' AND p1.invoice = o1.invoice ) p3
ON o2.customer = p3.customer
WHERE p3.customer IS NULL
Try this query instead:
SELECT DISTINCT Customer
FROM Orders o1
WHERE NOT EXISTS (
SELECT 1
FROM Orders o2
INNER JOIN Promotions ON Promotions.Invoice = o2.Invoice
WHERE o1.Customer = o2.Customer AND Coupon = 'couponB')
The idea is to get rid of the GROUP BY by removing a join in the top part of the query, and also eliminate the NOT IN by making a coordinated subquery.
Here is a link to sqlfiddle.
Try this with a right join
SELECT Customer, Coupon
FROM Promotions
RIGHT JOIN Orders ON Promotions.Invoice = Orders.Invoice
AND Coupon = 'couponA'
GROUP BY Customer
HAVING Coupon IS NULL