I need empty fields in multitable query - mysql

This should be easy for you, but I'm lost here:
I have a database with 4 tables: orders, clients, products, orders_products
I need to fetch all clients, with all of their orders, including the ones that don't have any order.
I'm only getting the ones that have made an order. Poor old "Nick" in the Clients table won't show up.
What am I doing wrong here?
SELECT c.name clientname, o.id orderID, GROUP_CONCAT(p.name) productNAMEs,
GROUP_CONCAT(p.id) productIDs
FROM clients c, orders o, orders_products op, products p
WHERE c.id = o.client_id
AND c.status = 1
AND o.id = op.order_id
AND p.id = op.product_id
GROUP BY c.name
See table definitions here:
https://www.db-fiddle.com/f/bTRSLfYTa19S2EpE2zKwUv/7
Update
#scaisedge came up with an answer that includes clients without orders:
SELECT c.name clientname, o.id orderID, GROUP_CONCAT(p.name) productNAMEs,
GROUP_CONCAT(p.id) productIDs
FROM clients c
LEFT JOIN orders o ON c.id = o.client_id
LEFT JOIN orders_products op ON o.id = op.order_id
LEFT JOIN products p ON p.id = op.product_id
WHERE c.status = 1
GROUP BY c.name
You can see the results here: https://www.db-fiddle.com/f/8bGcQJSbSFmKMUo1tLuZuA/1
It seems that not using JOINs was my problem.

Use explicit join sintax and left join for retrive also row that don't match
SELECT c.name clientname, o.id orderID, GROUP_CONCAT(p.name) productNAMEs,
GROUP_CONCAT(p.id) productIDs
FROM clients c
LEFT JOIN orders o ON c.id = o.client_id
LEFT JOIN orders_products op ON o.id = op.order_id
LEFT JOIN products p ON p.id = op.product_id
WHERE c.status = 1
GROUP BY c.name

I recommand you to use JOIN's to UNIFY the tables data. A JOIN clause is used to combine rows from two or more tables, based on a related column between them.
https://www.w3schools.com/sql/sql_join.asp
SELECT *
FROM clients LEFT JOIN orders ON clients.id = orders.client_id
LEFT JOIN orders_products ON clients.id = orders_products.order_id
LEFT JOIN products ON products.id = orders_products.product_id
WHERE clients.status = 1;

Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
Also, your GROUP BY needs to match the unaggregated columns in the SELECT.
I'm not sure if you intend this:
SELECT c.name as clientname, o.id as orderID,
GROUP_CONCAT(p.name) as productNAMEs,
GROUP_CONCAT(p.id) productIDs
FROM clients c left join
orders o
on c.id = o.client_id left join
orders_products op
on o.id = op.order_id left join
products p
on p.id = op.product_id
WHERE c.status = 1
GROUP BY c.name, o.id;
Or:
SELECT c.name as clientname,
GROUP_CONCAT(p.name) as productNAMEs,
GROUP_CONCAT(p.id) productIDs
FROM clients c left join
orders o
on c.id = o.client_id left join
orders_products op
on o.id = op.order_id left join
products p
on p.id = op.product_id
WHERE c.status = 1
GROUP BY c.name;

Related

How Can I join multiple tables with information i want?

I'm using mysql 8.0.31 version.
Below is my database schema ERD.
I want to get inforamtion about products from my DB.
Below is my sql raw query.
SELECT
p.id, p.name, sc.name sub_category, c.name category, count(po.color_id) color_count
FROM products p
INNER JOIN sub_categories sc
ON sc.id = p.sub_category_id
INNER JOIN categories c
ON sc.category_id = c.id
LEFT JOIN products_options po
ON po.product_id = p.id
INNER JOIN genders g
ON po.gender_id = g.id
WHERE c.id = 1
GROUP BY p.id
ORDER BY p.id ASC;
I want to join products table with sub_categories, categories to get categories information about my products AND products table with products_options, colors, genders to get color_count about a product and gender type about a product.
So I wanted to query like this added g.type (gender type information for a product)
SELECT
p.id, p.name, sc.name sub_category, c.name category, count(po.color_id) color_count, g.type
FROM products p
INNER JOIN sub_categories sc
ON sc.id = p.sub_category_id
INNER JOIN categories c
ON sc.category_id = c.id
LEFT JOIN products_options po
ON po.product_id = p.id
INNER JOIN genders g
ON po.gender_id = g.id
WHERE c.id = 1
GROUP BY p.id
ORDER BY p.id ASC;
But this occurs error like this
SQL Error [1055] [42000]: Expression #6 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'mydb.g.type' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
I think this error occurs cuz I didn't use aggregate function for g.type.
Below is my result except g.type in sql select field.
I want to get genders.type field together.
I think I need to sub query and join that table created by sub query. But I don' t know well How can I implement that method.
To combine this gender type information, How can I modify my sql query?
I tried multiple method sql queries in various ways to join table.
You need to either remove the column from select list like:
SELECT p.id, count(po.color_id) color_count
FROM products p
INNER JOIN sub_categories sc
ON sc.id = p.sub_category_i`enter code here`d
INNER JOIN categories c
ON sc.category_id = c.id
LEFT JOIN products_options po
ON po.product_id = p.id
INNER JOIN genders g
ON po.gender_id = g.id
WHERE c.id = 1
GROUP BY p.id
ORDER BY p.id ASC;
or add in group by clause the select columns like:
SELECT p.id, p.name, sc.name sub_category, c.name category, count(po.color_id) color_count, g.type
FROM products p
INNER JOIN sub_categories sc
ON sc.id = p.sub_category_id
INNER JOIN categories c
ON sc.category_id = c.id
LEFT JOIN products_options po
ON po.product_id = p.id
INNER JOIN genders g
ON po.gender_id = g.id
WHERE c.id = 1
GROUP BY p.id,p.name, sc.name sub_category, c.name category, g.type
ORDER BY p.id ASC;

Getting data from multiple tables in mysql using joins ends in wrong data

I need to select the customer and product code and the date on which the order was made, but I'm having some trouble with the join orders.
My SQL select:
select c.customerNumber, p.productCode, o.orderDate as data_compra
from customers as c inner join orders as o
inner join products as p
where p.productCode =
any (
select p2.productCode from products as p2
inner join orders as o
inner join orderdetails as odt
where o.orderNumber = odt.orderNumber and
p2.productCode = odt.productCode
)
and o.orderNumber =
any (
select o2.orderNumber from orders as o2
inner join orderdetails as odt
where o.orderNumber = odt.orderNumber and
p.productCode = odt.productCode
)
Two simple joins should do what you want:
select
c.customerNumber,
d.productCode,
o.orderDate
from customer c
join orders o on o.customerNumber = c.customerNumber
join orderdetails d on d.orderNumber = o.orderNumber
In the code you're asking to inner join two tables but not specifying the relationship. You need to do so SQL can relate and match the rows in each table.
You do this with the ON keyword.
I suggest you watch this video and read this article before continuing

Multiple inner joins to get a complex report, not working

For the schema below, I need to get this report
This is what I have
select c.name, sr.name, count(o.order_id)
from contact c
INNER JOIN accounts a
ON c.account_id=a.account_id
INNER JOIN sales_reps sr
ON a.sales_rep_id =sr.sales_rep_id
INNER JOIN orders o
ON a.account_id =o.account_id
where o.order_id in (
select SUM(oi.quantity*p.price) from
order_items oi INNER JOIN parts p
on oi.part_id =p.part_id
)
group by a.account_id, c.name
But this does not give any results.
Please help.
Your where condition is not right, how should be a order_id equal a sum?
Try the below:
select
c.name, sr.name, COUNT(o.order_id), SUM(op.order_total)
FROM
contact c
INNER JOIN
accounts a ON c.account_id = a.account_id
INNER JOIN
sales_reps sr ON a.sales_rep_id = sr.sales_rep_id
INNER JOIN
orders o ON a.account_id = o.account_id
INNER JOIN
(SELECT
oi.order_id, SUM(oi.quantity * p.price) AS order_total
FROM
order_items oi
INNER JOIN
parts p ON oi.part_id = p.part_id
GROUP BY
oi.order_id
) op ON o.order_id = op.order_id
WHERE o.delivery_data >= CURDATE()
GROUP by c.contact_id
It won't give results as your WHERE ... IN SELECT is based on a query returning a sum() value which will not equal a key (most likely), or incorrect at best... and since you are dealing with a quantity and price which will have decimal precision (typically), you won't even get that to match even LESS likely...
I would swap the query around to pre-qualify the orders within a given date in question and sum that... THEN join to rest...
select
c.name,
sr.name,
PreQualified.NumberOrders,
PreQualified.OrderTotal
from
( select
o.Account_ID,
count( distinct o.order_id ) as NumberOrders,
sum( oi.quantity * p.price ) as OrderTotal
from
orders o
join order_items oi
on o.order_id = oi.order_id
join parts p
on oi.part_id = p.part_id
where
o.Delivery_Date >= CURDATE()
group by
o.Account_ID ) as PreQualified
JOIN Accounts a
on PreQualified.Account_ID = a.Account_ID
Join Contact C
on a.Account_ID = c.Account_ID
JOIN Sales_Reps sr
ON a.sales_rep_id = sr.sales_rep_id
If you want to count records use
count(*)
Instead of
count(o.order_id)

Mysql Query: Find Customer W/Orders but without Payment

As the title says, i am trying to find the customer's who have made orders but have not made payments yet.
I have Three tables;
Customers, Payments, Orders
The sql i have so far gives me (nested query) all the customers without payments, the outer query then tries to join all the customers with orders and checks if those customers are not in my inner table?
SELECT customerWOpayments.customerNumber FROM
ClassicModels.Customers c
INNER JOIN ClassicModels.Orders o ON c.customerName = o.customerNumber
NOT IN
(SELECT distinct c.customerNumber
FROM ClassicModels.Customers c
LEFT OUTER JOIN ClassicModels.Payments p ON c.customerNumber = p.customerNumber
WHERE p.customerNumber IS NULL) customerWOpayments;
I am getting a mysql syntax error at line 8 but cannot figure out why?
This should return customers who have orders but no matching payment assuming all of the keys you joined on in your original example were correct (for example c.customerName = o.customerNumber seems suspicious).
SELECT c.customerNumber
FROM ClassicModels.Customers c
INNER JOIN ClassicModels.Orders o
ON c.customerNumber = o.customerNumber
LEFT OUTER JOIN ClassicModels.Payments p
ON c.customerNumber = p.customerNumber
WHERE p.customerNumber IS NULL;
Basically you missed the WHERE clause. And your question lacks information. Please provide the Schema of your tables. Thanks!
try this one:
Are you sure with this condition ON c.customerName = o.customerNumber?
SELECT customerWOpayments.customerNumber
FROM ClassicModels.Customers c INNER JOIN ClassicModels.Orders o
ON c.customerName = o.customerNumber -- Please check this out
WHERE o.customerNumber NOT IN
(SELECT distinct c.customerNumber
FROM ClassicModels.Customers c LEFT JOIN ClassicModels.Payments p
ON c.customerNumber = p.customerNumber
WHERE p.customerNumber IS NULL);
OR Without Subquery
SELECT a.*
FROM Customers a INNER JOIN Orders b ON
a.CustomerName = b.CustomerNumber -- Please check this line
LEFT JOIN Payments c ON
b.CustomerNumber = c.CustomerNumber
WHERE c.CustomerNumber IS NULL
I believe it's a typo error on a.CustomerName = b.CustomerNumber, instead a.CustomerNumber = b.CustomerNumber
I can't tell exactly if it is because you didn't provide the schema of your tables with some dummy records.
Hope this helps.
Unlike the other solutions, this solution will not produce duplicate customer numbers when customers have more than one order.
SELECT C.customerNumber
FROM ClassicModels.Customers C
WHERE
EXISTS(
-- customer has orders
SELECT *
FROM ClassicModels.Orders AS O
WHERE O.customerNumber = C.customerNumber
)
AND NOT EXISTS(
-- customer does not have payments
SELECT *
FROM ClassicModels.Payments P
WHERE P.customerNumber = C.customerNumber
)

Modify SQL query to get all users?

I currently have this query.
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM `order` AS o LEFT JOIN customer AS c ON o.customer_id = c.id
GROUP BY customer_id
What it does is it returns all customers that have made an order and counts the number of orders each customer has made.
What I need to do is modify this query so it also returns those customers who haven't made an order. Do you have any idea how this would be done?
I tried to reverse the query but this didn't do the trick..
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
GROUP BY o.customer_id
Try this.
SELECT o.customer_id, sum( case when o.id is not null then 1 else 0 end ) AS orders, c.*
FROM customer c
LEFT JOIN order o ON o.customer_id = c.id GROUP BY customer_id
What about:
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM `order` AS o
LEFT OUTER JOIN customer AS c ON o.customer_id = c.id GROUP BY customer_id
SELECT o.customer_id, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
WHERE o.id IS NULL
GROUP BY o.customer_id
You can also skip the "GROUP BY" clause because when the orders side is NULL, there is always only one row for the customer:
SELECT o.customer_id, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
WHERE o.id IS NULL