mysql group by query (very close) - mysql

I have 3 tables (simplified):
orders (orderid, date)
orderlines (lineid, orderid, userid)
users (userid, name)
I would like a list of numbers of orders per user grouped by year and month orders by username. The reason why order lines have the user id is that an order line can be changed by another user. The following gives me a list of numbers of order lines, but it needs to count the orders only:
SELECT
users.name,
COUNT(orders.orderid) AS number,
MONTH(orders.date) AS month,
YEAR(orders.date) AS year
FROM orders
INNER JOIN orderlines ON orders.orderid = orderlines.orderid
INNER JOIN users ON orderlines.userid = users.userid
GROUP BY orderlines.userid, YEAR(order.date), MONTH(order.date)
ORDER BY users.name, orders.date
I'm feeling I'm very close...
Current output is:
name | number | month | year
----------------------------
jeff | 1000 | 1 | 2018
jeff | 1100 | 2 | 2018
Should be:
name | number | month | year
----------------------------
jeff | 100 | 1 | 2018
jeff | 110 | 2 | 2018
The number currently shown is the number of order lines, but I would like it to be the number of orders.

Try below: you need to use users.name in group by, also it should be in your order by clause as your question says it, another thing is as you want to know the count of order per user, so it should be count distinct orderid
SELECT users.name, COUNT(distinct orders.orderid), MONTH(orders.date), YEAR(orders.date)
FROM orders
INNER JOIN orderlines ON orders.orderid = orderlines.orderid
INNER JOIN users ON order lines.userid = users.userid
GROUP BY users.name, YEAR(order.date), MONTH(order.date)
ORDER BY users.name

Related

Union Select two queries subtract from particular data

I need to build a query which performs subtraction on basis of client name here is my query I built for getting data
SELECT invoice.client_name, (Sum(invoice.freight_rate)+Sum(invoice.total_basic_amount)+Sum(invoice.delivery_rate))
FROM invoice GROUP BY invoice.client_name
UNION SELECT client_name,(Sum(payments.payment_received))
FROM payments GROUP BY client_name
And here is what I get as an output
client_name | Expr1001
John | 2500
John | 3630
MAc | 12000
MAc | 15300
What I need is
client_name | Expr1001
John | 1130
MAc | 3300
Which is simple subtraction of both query.
I already asked this question before and I got some good responses but they aren't working and now nobody replies to it. Here is what I got from them.
SELECT invoice.client_name, (Sum(invoice.freight_rate)+Sum(invoice.total_basic_amount)+Sum(invoice.delivery_rate)-Sum(payments.payment_received)) AS Expr1
FROM invoice, payments
WHERE (([invoice].[client_name]=[payments].[client_name]))
GROUP BY invoice.client_name;
This query returns some very strange output which is
client_name | Expr1001
John | 2260
MAc | 18600
I'm Attaching the db file here is the link.
https://drive.google.com/file/d/1dbxHzXDbfe8l1ZDN9ZxZo7Rs1UImhV8r/view?usp=share_link
You need subqueries:
Select
Charges.client_name,
TotalCharges-TotalPayments As Total
From
(Select
invoice.client_name,
Sum(CCur([invoice].[freight_rate]))+Sum(CCur([invoice].[total_basic_amount]))+Sum(CCur([invoice].[delivery_rate])) As TotalCharges
From
invoice
Group By
invoice.client_name) As Charges
Inner Join
(Select
payments.client_name,
Sum(CCur([payment_received])) As TotalPayments
From
payments
Group By
payments.client_name) As Payments
On Charges.client_name = Payments.client_name
and you should not store amount as text ...
There are multiple invoice and payment records for each client. This means must aggregate each table's data then join those datasets.
SELECT I.client_name, amt - pmt AS Total
FROM (SELECT client_name, Sum(total_basic_amount) AS amt FROM invoice GROUP BY client_name) AS I
LEFT JOIN (SELECT client_name, Sum(payment_received) AS pmt FROM payments GROUP BY client_name) AS P
ON I.client_name = P.client_name;
Or this version:
SELECT invoice.client_name, Sum(total_basic_amount)-Max(pmt) AS Total
FROM Invoice LEFT JOIN (SELECT client_name, Sum(payment_received) AS pmt FROM Payments GROUP BY client_name) AS P
ON invoice.client_name = P.client_name
GROUP BY invoice.client_name;

SQL: join 2 tables based on column value and select row values where grouped column value is max

Ive got this query and I want to get all names from those clients that have the highest price of a day.
If multiple clients exist having the same max price, they shall be selected too.
I managed to get the customers with max price grouped by date but I dont think it gives me both customers if they have the same max value on the same day.
The names should be distinct.
The output needs to be as follows:
| Name (asc) |
------------------
| customer name |
| customer name |
| ...... |
The Orders table looks as follows:
|Client|Price|Orderdate |
------------------------
|1 |100.0|2010.01.10|
|... |... | ..... |
and the Client table:
|Client_NR|Name |
-----------------------
|1 |customer#001|
|2 |customer#002|
select distinct k1.NAME from Orders a LEFT JOIN Order b on a.Orderdate = b.Orderdate
JOIN Client k1 on k1.Client_NR = a.Client
where a.Price IN
(SELECT MAX(a.Price) from Order a group by Orderdate)
order by NAME asc
I presume my error lies within the Join Client line but I just cant figure it out.
Ive tried to use a.price = b.price in the first join but the test would fail.
Any advise is highly appreciated.
WITH cte AS ( SELECT Client.Name,
RANK() OVER (PARTITION BY Orders.Orderdate
ORDER BY Orders.Price DESC) rnk
FROM Client
JOIN Orders ON Client.Client_NR = Orders.Client )
SELECT Name
FROM cte
WHERE rnk = 1
ORDER BY Name

MySQL double group

I am making queries to extract data from database which holds customer order. There's one table which holds customer id's and the customer's name. Another table which has the order id, customer id of who placed the order, a quantity of the item bought, and an item id. The last table holds the item id's and item names. I am trying to sort these to show an individual's most popular purchase, but am having issues properly grouping and ordering to produce the correct result, below is an example of what is intended.
customers
1 | John
---+-----
2 | Jane
orders
1 | 2 | 4 | 1
---+---+---+---
2 | 2 | 5 | 2
---+---+---+---
3 | 2 | 2 | 1
---+---+---+---
4 | 1 | 1 | 2
items
1 | Chair
---+-------
2 | Sofa
After properly sorting and grouping, the output table should like:
John | Sofa
------+------
Jane | Chair
Currently I can connect the item names to the purchaser and return a random item bought, but not the most popular by quantity. I have tried entering multiple fields into group by and managed to properly group the items by name and sort by quantity, but in doing so the customer id's became ungrouped. Been trying to solve this for days so any help would be appreciated. Please note that this is a very simplified version of the actual problem where many more tables are involved, including multiple items table which are being joined together to one.
You should use group by on joined tables
select
b.name
, c.name
, sum(quantity) as tot
from orders as a
inner join Customers as b on a.customer_id = b.id
inner join Items as c on a.item_id = c.id
group by b.name, c.name
order by tot
Selecting the sum of the quantities per customer-item group is easy, but selecting the top seller is a bit harder.
The first step is the query to get all the groups with the sums of the quantities for each customer-item:
SELECT
customer_name,item_name,SUM(quantity)
FROM
orders o
JOIN customers c ON o.customer_id=c.id
JOIN items i ON o.item_id=i.id
GROUP BY customer_name,item_name;
Then to only select the groups with the maximum quantity sums we use some trickery:
SELECT
customer_name,item_name,SUM(quantity),
(SELECT SUM(quantity) AS qmax
FROM
orders o2
JOIN customers c2 ON o2.customer_id=c2.id
JOIN items i2 ON o2.item_id=i2.id
WHERE c2.id=c.id
GROUP BY c2.customer_name,i2.item_name
ORDER BY qmax DESC LIMIT 1) AS qmax
FROM
orders o
JOIN customers c ON o.customer_id=c.id
JOIN items i ON o.item_id=i.id
GROUP BY customer_name,item_name
HAVING SUM(quantity)=qmax;
Edit:
Here's a link to a fiddle: SQLFiddle

Sql query to get data diffrence of total in 2 tables

I have two tables:
booking - records the order detail
id | booking_amount
-------------------
1 | 150
2 | 500
3 | 400
payment - records the payment for order
id | booking_id | amount
------------------------
1 | 1 | 100
2 | 1 | 50
2 | 2 | 100
I want to find all bookings where the payments are not complete. With the above data, we expect the answer to be 2,3, because the sum of payments for booking_id=1 matches the corresponding booking_amount in the booking_table.
To answer your question, you have 2 things you need to think about :
you want the total amount in your table payment by every booking row
you want to join your booking_amount table with payment.
Part 1 is quite simple:
SELECT sum(amount) as TotalP, booking_id FROM payment GROUP BY booking_id
Just a basic query with a simple aggregate function...
For part 2, we want to join booking_amount and payment; the basic JOIN would be:
SELECT * FROM booking b
LEFT JOIN payment p ON b.id = p.booking_id
We do a LEFT JOIN because we may have some booking who are not in the payment table. For those bookings, you will get NULL value. We will use a COALESCE to replace the NULL values by 0.
The final query is this:
SELECT b.id, COALESCE(TotalP, 0), b.booking_amount
FROM
booking b
LEFT JOIN
(SELECT sum(amount) as TotalP, booking_id FROM payment GROUP BY booking_id) as T
ON b.id = T.booking_id
WHERE COALESCE(TotalP, 0) < b.booking_amount
You need to use a outer join to combine your two tables and look for your conditions. Also, you will need to use SUM(..) function to get the sum of the amount for each id in the payment table.
Please try this:
select b.id from booking b
left outer join -- cant be inner join because we lose id:3 in that case.
(
select booking_id, SUM(amount) as Total
from payment group by booking_id
) p on b.id = p.booking_id
where b.booking_amount > Coalesce(Total,0) --Coalesce is required for such values coming NULL, like id:3, they will be assigned as 0.

MySQL filter on column value within multiple rows?

Suppose I have these two tables:
|Customers | |Purchases |
---------------- -----------------
|CusID |----- |PurchaseID |
|CusName | |---<|CusID |
|CusAge | |ItemName |
|CusDateAdded | |DatePurchased |
I am needing to filter my result set by multiple ItemNames. Say I want to return all Customers who are between the ages of 18 and 24 who purchased a 'camera' AND a 'phone'. I can run the following query to obtain all records for customers between the age range:
SELECT CusID
FROM Customers AS C
JOIN Purchases AS P
ON C.CusID = P.CusID
WHERE C.CusAge BETWEEN 18 AND 24
However when it comes time to filter on the ItemName column in Purchases table how does one filter on multiple rows? Supposing it is possible without multiple queries?
SELECT C.CusID
FROM Customers AS C
JOIN Purchases AS P ON C.CusID = P.CusID
WHERE C.CusAge BETWEEN 18 AND 24
AND ItemName IN ('camera','phone')
GROUP BY C.CusID
HAVING count(distinct ItemName) = 2
Group by the customer and return only those having both items.
I believe this will answer your question: SQL FIDDLE
SELECT C.CustID,C.CustName,P.ItemName
FROM Customers AS C
JOIN Purchases AS P ON C.CustID = P.CustID
GROUP BY C.CustID,C.CustName,P.ItemName
HAVING P.ItemName IN ('camera','phone')