Mysql complex select query from 4 tables - mysql

I research almost 200 example pages about mysql complex queries but stuck in it.
This is my stucture
Table name: zones
zoneId | zoneName
------------------
Table name: customers
customesId | zoneId | customerName
----------------------------------
Table name: products
productId | productName
-----------------------
Table name: sales
sid | zoneId | customerId | productId | amount
----------------------------------------------
Is it possible to get the following output only with the query?
zoneName | customerName | productName | amount(SUM)
---------------------------------------------------
ZoneX | customerA | productName_1 | 10
| | productName_2 | 0
| | productName_3 | 4
| | productName_4 | 0
ZoneX | customerB | productName_1 | 7
| | productName_2 | 0
| | productName_3 | 4
| | productName_4 | 3
.......
I want to get as "0" even customer or product has no sale
I tried:
SELECT zones.zoneName
, customers.customerName
, products.productName
, SUM(amount) AS amount
FROM customers
INNER JOIN zones
ON customers.zoneId = zones.zoneId
LEFT JOIN sales
ON customers.customerId = sales.customerId
LEFT JOIN products
ON sales.productId = products.productId

You need to cross join all the customers to the products so that each customer has every product listed regardless of sale.
SELECT z.zoneName
, c.customerName
, p.productName
, SUM(coalesce(s.amount,0)) AS amount
FROM customers c
INNER JOIN zones z
ON c.zoneId = z.zoneId
CROSS JOIN PRODUCTS P
LEFT JOIN sales S
ON c.customerId = s.customerId
and s.productID = p.productID
GROUP BY z.zoneName
, c.customerName
, p.productName

You can try this query
SELECT c.zoneId ,c.customesId ,c.customerName,IF(s.amount IS NULL, 0 , s.amount)
FROM customers AS c, products AS p
LEFT JOIN sales AS s ON s.productId = p.productId and s.customersid = c.customersid
Hope this helps.

Related

How do I join multiple (four) tables using sql with conditions?

I am trying to create an SQL query that conditionally pulls data from multiple tables.
I have four tables:
orders
+------+------------+------------+
| id | date_added | currency |
+------+------------+------------+
| 1 | 2018-07-23 | 1 |
+------+------------+------------+
order_items
+------+------------+------------+---------------+---------------+
| id | order_id | price | product_id | product_type |
+------+------------+------------+---------------+---------------+
| 1 | 1 | 100.00 | 1 | ticket |
+------+------------+------------+---------------+---------------+
order_data
+------+--------------+---------------+
| id | order_id | ext_order_ref |
+------+--------------+---------------+
| 1 | 1 | ABC |
+------+--------------+---------------+
products
+------+------------+------------+
| id | date | product_id |
+------+------------+------------+
| 1 | 2020-03-12 | 1 |
+------+------------+------------+
| 2 | 2020-03-18 | 2 |
+------+------------+------------+
| 3 | 2020-03-20 | 3 |
+------+------------+------------+
I need to output orders with the following conditions:
Each order in a row with total (calculated from order items with matching order id)
The 'ext_order_ref' from the order_data table that matches that order
Only include order items that have a specific product type
Only include orders with products from a particular date range
Preferred output would look like this:
+------------+------------+--------------+
| order_id | total | ext_order_ref|
+------------+------------+--------------+
| 1 | 100 | ABC |
+------------+------------+--------------+
My current query is basically like this; please advise
SELECT
orders.id as order_id,
SUM(order_items.price) as total,
order_data.ext_order_ref
FROM orders
INNER JOIN order_data
ON orders.id = order_data.ext_order_ref
RIGHT JOIN order_items
ON orders.id = order_items.order_id
LEFT JOIN products
ON order_items.product_id = products.product_id
WHERE order_items.product_type = 'ticket' AND products.date BETWEEN '2020-03-12' AND '2020-03-18'
GROUP BY orders.id
It almost works, but not quite. The date particularly is causing issue.
Thanks in advance!
First decide the driving table for the query and form the query based on the driving table.
Driving table is the one primary table from which other tables join.
More information on driving tables from askTom
In your case, the driving table is Orders table. You are switching between RIGHT OUTER JOIN and LEFT OUTER JOIN. This will cause confusion in the resultset.
I have modified the query. See whether it works.
SELECT
orders.id as order_id,
SUM(order_items.price) as total,
order_data.ext_order_id
FROM orders
INNER JOIN order_data
ON orders.id = order_data.ext_order_id
LEFT OUTER JOIN order_items
ON orders.id = order_items.order_id
LEFT OUTER JOIN products
ON order_items.product_id = products.product_id
WHERE order_items.product_type = 'ticket' AND products.date BETWEEN '2020-03-12' AND '2020-03-18'
GROUP BY orders.id
I don't understand why you would want outer joins at all. If I follow the conditions correctly:
SELECT o.id as order_id,
SUM(oi.price) as total,
od.ext_order_id
FROM orders o INNER JOIN
order_data od
ON o.id = od.ext_order_id INNER JOIN
order_items oi
ON o.id = oi.order_id INNER JOIN
products p
ON oi.product_id = p.product_id
WHERE oi.product_type = 'ticket' AND
p.date >= '2020-03-12' AND
p.date < '2020-03-19'
GROUP BY o.id, od.ext_order_id;
Note the use of table aliases so the query is easier to write and read.

MySql query code to fetch unique data from single ID

How do i List the CUSTNUMs and NAMES of any customer who has only ordered chemical [NUMBER].
ORDERS TABLE
+---------+--------+------------+------+
| CUSTNUM | CHEMNO | DATE | QTY |
+---------+--------+------------+------+
| 123456 | 1234 | 2000-00-00 | 35 |
+---------+--------+------------+------+
CUSTOMER TABLE
+---------+-----------+-----------+
| CUSTNUM | NAME | LOCATION |
+---------+-----------+-----------+
| 123456 | AmChem | New York |
+---------+-----------+-----------+
You could join the CUSTOMER and ORDERS tables containing orders for a particular <chemno> with a subquery for the custnum that buy only a product:
SELECT
CUSTNUM, NAME
FROM
CUSTOMER c
INNER JOIN
ORDERS o ON o.CUSTNUM = c.CUSTNUM and o.CHEMNO = <chemno>
INNER JOIN
( SELECT
CUSTNUM
FROM
ORDERS
GROUP BY
CUSTNUM
HAVING
COUNT(DISTINCT CHEMNO) = 1 ) t ON t.CUSTNUM = o.CUSTNUM
I will approach this with one join between both tables, then grouping by the column CUSTNUM of the ORDERS table and finally adding the required conditions on the HAVING clause, like this:
SELECT
o.CUSTNUM,
c.NAME
FROM
ORDERS AS o
INNER JOIN
CUSTOMER AS c ON c.CUSTNUM = o.CUSTNUM
GROUP BY
o.CUSTNUM
HAVING
( COUNT(DISTINCT o.CHEMNO) = 1 AND MIN(o.CHEMNO) = <some_chemno> )
OK, slow day...
SELECT DISTINCT x.custnum
FROM orders x
LEFT
JOIN orders y
ON y.custnum = x.custnum
AND y.chemno <> x.chemno
WHERE x.chemno = 9377
AND y.order_id IS NULL;
The rest of this task has been left as an exercise for the reader

Inner join, sql confused

This is the challeng for my class.
Using INNER JOIN retrieve the following information:
Using the customers and orders table find all the orders that were created by an owner of a company.
I came up with this but when I enter it it says empty set>>>
SELECT id FROM orders INNER JOIN customers USING (id);
These are the columns from the customers table.
CUSTOMERS
| id | company | last_name | first_name | email_address | job_title
| business_phone | home_phone | mobile_phone | fax_number | address
| city | state_province | zip_postal_code | country_region | web_page
| notes | attachments |.
These are the columns from the orders table.
ORDERS
| id | employee_id | customer_id | order_date | shipped_date | shipper_id
| ship_name | ship_address | ship_city | ship_state_province
| ship_zip_postal_code | ship_country_region | shipping_fee | taxes
| payment_type | paid_date | notes | tax_rate | tax_status_id | status_id
When you write:
SELECT id FROM orders INNER JOIN customers USING (id);
you are requesting:
SELECT o.ID -- or c.ID
FROM Orders AS o
JOIN Customers AS c
ON O.ID = C.ID;
You're asking "which customers have an ID that is the same as an order ID?", which is probably not what you meant.
Most likely, you want to use some variant of:
SELECT o.ID AS Order_ID, c.ID AS Customer_ID
FROM Orders AS o
JOIN Customers AS c
ON O.Customer_ID = C.ID;
You get to choose what information you get in the select list.
You can find examples of inner join syntax here. Here is one example of how to do this:
select o.*
from orders o
inner join customers c on o.customer_id = c.id
/* not sure how "owner of company" is represented in the data, but I'm assuming it's some value for job_title */
where c.job_title = 'owner'

mysql sum column with same id

I have orders table, order_details table
I join orders table with order_details table to make a temporary table that look like this
order_id | customer_id | Quantity |
2 | 2 | 10 |
2 | 2 | 25 |
2 | 2 | 5 |
2 | 2 | 15 |
3 | 2 | 25 |
What I am trying to achieve is sum Quantity column where order_id is same.
so the end result look like this
order_id | customer_id | Quantity |
2 | 2 | 55 |
3 | 2 | 25 |
my sql statement to get to here look like this
SELECT
orders.orders_id,
orders.customer_id_fk,
sum(order_detail.quantity)
FROM orders
LEFT JOIN order_detail on orders.orders_id = order_detail.orders_id_fk
WHERE customer_id_fk IN(2) <-- this is needed because I only want to see customer 2.
how do I put a condition on the sum ?
Looks like you are very close!
You should be able to group by order_idto get a list of unique order_ids with the Quantity sum for each order_id
SELECT
orders.orders_id,
orders.customer_id_fk,
sum(order_detail.quantity)
FROM orders
LEFT JOIN order_detail on orders.orders_id = order_detail.orders_id_fk
WHERE customer_id_fk IN(2)
GROUP BY orders.orders_id,orders.customer_id_fk
use Group by
SELECT
orders.orders_id,
orders.customer_id_fk,
sum(order_detail.quantity)
FROM orders
LEFT JOIN order_detail on orders.orders_id = order_detail.orders_id_fk
WHERE customer_id_fk IN(2) GROUP BY orders.orders_id,orders.customer_id_fk
Here is OP. Sorry I derped. I put GROUP BY after Order by and it didnt work. the below sovled it
SELECT
orders.orders_id,
orders.customer_id_fk,
sum(order_detail.quantity)
FROM orders
LEFT JOIN order_detail on orders.orders_id = order_detail.orders_id_fk
WHERE customer_id_fk IN(2)
GROUP BY orders_id
ORDER BY customer_id

Select and summarize data from three tables

i have three tables
customer
id | name
1 | john
orders
id | customer_id | date
1 | 1 | 2013-01-01
2 | 1 | 2013-02-01
3 | 2 | 2013-03-01
order_details
id | order_id | qty | cost
1 | 1 | 2 | 10
2 | 1 | 5 | 10
3 | 2 | 2 | 10
4 | 2 | 2 | 15
5 | 3 | 3 | 15
6 | 3 | 3 | 15
i need to select data so i can get the output for each order_id the summary of the order
sample output. I will query the database with a specific customer id
output
date | amount | qty | order_id
2013-01-01 | 70 | 7 | 1
2013-02-01 | 50 | 4 | 2
this is what i tried
SELECT
orders.id, orders.date,
SUM(order_details.qty * order_details.cost) AS amount,
SUM(order_details.qty) AS qty
FROM orders
LEFT OUTER JOIN order_details ON order_details.order_id=orders.id AND orders.customer_id = 1
GROUP BY orders.date
but this returns the same rows for all customers, only that the qty and cost dont hav values
Maybe
SELECT
orders.id, orders.date,
SUM(order_details.qty * order_details.cost) AS amount,
SUM(order_details.qty) AS qty
FROM orders
LEFT JOIN order_details ON order_details.order_id=orders.id
AND orders.customer_id = 1
GROUP BY orders.date
HAVING amount is not null AND qty is not null
SQL Fiddle
NOTE: In the following query, it is assumed that the dates are stored in the database as a string in the format specified in the OP. If they are actually stored as some type of date with time then you'll want to modify this query such that the time is truncated from the date so the date represents the whole day. You can use the date or date_format functions. But then you'll need to make sure that you modify the query appropriately so the group by and select clauses still work. I added this modification as comments inside the query.
select
o.date -- or date(o.date) as date
, sum(odtc.total_cost) as amount
, sum(odtc.qty) as qty
, o.order_id
from
orders o
inner join (
select
od.id
, od.order_id
, od.qty
, od.qty * od.cost as total_cost
from
order_details od
inner join orders _o on _o.id = od.order_id
where
_o.customer_id = :customer_id
group by
od.id
, od.order_id
, od.qty
, od.cost
) odtc on odtc.order_id = o.id
where
o.customer_id = :customer_id
group by
o.date -- or date(o.date)
, o.order_id
;
I don't think you want an outer join just a simple inner join on all 3 tables:
FROM orders, order_details, customer
WHERE orders.customer_id=customer.id
AND order_details.order_id=orders.id