Joining the tables while manipulating SELECT - mysql

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

Related

How can I SUM values in a joined table without screwing up totals of values in the first table?

I'd like to SELECT a count of the number of customers, the sum of customer order totals, and a count of customers in specific states.
I know how to do this in two queries easily, however the same WHERE constraints will be used, so it seems like it would be better to do it in one query and avoid repetition. I'm eager to improve my SQL but I can't work out how to combine them. Having them as two separate queries feels very clumsy.
Is there a way to combine them? What factors should I consider to determine if combining them is a good idea?
Customers Table
*-------------*-------------*--------------*------------*
| ID_Customer | ID_State | Name | ...etc... |
*-------------*-------------*--------------*------------*
States Table
*-------------*-------------*
| ID_State | Name |
*-------------*-------------*
Orders Table
*----------*-------------*--------------*------------*
| ID_Order | ID_Customer | ...etc... | Total |
*----------*-------------*--------------*------------*
Query 1.1 - Select Count of Customers and Count of Customers in specific states
SELECT
COUNT(*) AS Customers,
SUM(States.Name = 'California') AS California_Customers,
SUM(States.Name = 'New York') AS NewYork_Customers
FROM Customers
INNER JOIN States ON Customers.ID_State = States.ID_State
Query 1.2 - Select Sum of Customer Order Totals
SELECT
SUM(Total) AS SumOfOrderTotals
FROM Orders
INNER JOIN Customers ON Customers.ID_Customer = Orders.ID_Customer
Query 2 - An attempt at combining the queries into one (does not work)
SELECT
COUNT (DISTINCT(Customers.ID_Customer)) AS Customers,
SUM (Orders.Total) AS SumOfOrderTotals,
SUM (States.Name = 'California') AS California_Customers,
SUM (States.Name = 'New York') AS NewYork_Customers
FROM
Customers
INNER JOIN Orders ON Customers.ID_Customer = Orders.ID_Customer
INNER JOIN States ON Customers.ID_State = States.ID_State
Obviously this does not work as it is because the INNER JOIN between Customers and Orders means that States.Names are counted xN (where N is the number of orders a customer has) for each customer, making those totals wrong.
I considered a Subquery, however I'm not sure how to apply one in this case (if that is what I should be doing).
You need to do the aggregation before the join or use subqueries:
SELECT COUNT(DISTINCT(c.ID_Customer)) AS Customers,
o.SumOfOrderTotals,
SUM(s.Name = 'California') AS California_Customers,
SUM(s.Name = 'New York') AS NewYork_Customers
FROM Customers c JOIN
States s
ON c.ID_State = s.ID_State CROSS JOIN
(SELECT SUM(Total) as SumOfOrderTotals
FROM Orders o
) o;
You could also write this as:
SELECT COUNT(DISTINCT(c.ID_Customer)) AS Customers,
(SELECT SUM(Total)
FROM Orders o
) as SumOfOrderTotals,
SUM(s.Name = 'California') AS California_Customers,
SUM(s.Name = 'New York') AS NewYork_Customers
FROM Customers c JOIN
States s
ON c.ID_State = s.ID_State;
You place the subquery where you would have placed any additional field, as another thing in the SELECT clause.
SELECT
COUNT(*) AS Customers,
SUM(States.Name = 'California') AS California_Customers,
SUM(States.Name = 'New York') AS NewYork_Customers,
(SELECT SUM(Total) FROM Orders) AS SumOfOrderTotals
FROM Customers
INNER JOIN States ON Customers.ID_State = States.ID_State;

MYSQL Query: Customer Sales Gap Analysis

I'm looking to query 3 tables (Customers, Sales, & Top-Items) and create a list of the top-items that each customer has not purchased.
Relevant fields are
Customers: Customer#
Sales: Invoice#, Customer#, Item#
Top-Items: Item#
SELECT c.*, GROUP_CONCAT(t.`Item#`) AS list_of_top_items_not_purchased
FROM Customers c
CROSS JOIN `Top-Items` t
LEFT OUTER JOIN Sales s ON c.`Customer#` = s.`Customer#` AND s.`Item#` = t.`Item#`
WHERE s.`Item#` IS NULL
GROUP BY c.`Customer#`;

Pulling last 10 orders from mysql table

I'm new to mysql and I'm trying to figure out if there is a way that you can pull information from the the last 5 most recent orders.
I'm trying to pull orderNumber, productName, and firstname for last 5 most recent orders.
I created 2 dummy tables that I'm working with:
Table:
orders
Fields:
orderNumber
customerOid
orderInformationOid
purchaseDateTime
Table:
customerData
Fields:
customerOid
firstName
middleInitial
lastName
Table:
products
Fields:
productOid
productName
companyOid
I was thinking an INNER JOIN but how to determine the most recent orders?
I suppose there's a productOid column in your orders table, then you can use this query:
SELECT o.orderNumber, p.productName, c.firstname
FROM
(SELECT orderNumber, customerOid, productOid
FROM orders
ORDER BY purchaseDateTime DESC
LIMIT 5) o
INNER JOIN customers c ON o.customerOid = c.customerOid
INNER JOIN products p ON o.productOid = p.productOid

Joining two tables for the result?

I have 2 tables in a database person and order tables.
PERSON table:
PERSON_ID | NAME
ORDER table:
ORDER_ID | ORDER_NO | PERSON_ID
I need to display all the orders + a name of corresponding person if it exists, if not just order details.
So far I got up to query:
SELECT ORDER_ID, ORDER_NO, order.PERSON_ID, NAME
FROM person, order
WHERE person.PERSON_ID = order.PERSON_ID AND
person.FIRST_NAME IS NOT NULL;
Which gives me orders only if the name is available whereas I need to display all the orders despite the fact if name is available or not.
Any suggestions?
Yes, you can use LEFT JOIN for that:
SELECT o.order_id, o.order_no, o.person_id, p.name
FROM `order` o
LEFT JOIN person p
ON p.person_id = o.person_id AND p.FIRST_NAME IS NOT NULL
With LEFT JOIN if the name is null it will still give you the orders.

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