I'm trying to write a query which will return which garment generated the most revenue during the last three months compared to the same period last year.
I want to display the results in one table. The garment_id from the queries might match but might not. If it matches then I would like to display the results in the same row. I suppose I want to order by garment_id.
I have so far come up with this which almost works but returns incorrect/strange values for TotalDaysHired, MoneyIn, LastYrTotalDaysHired and LastYrMoneyIn; I've no idea why. I've also tried joining the two queries with an inner join ON a.garmentid = b.garmentid order by a.garmentid which wouldn't even run.
SELECT garment_hire_line.date_out as 'dateout',
garment_hire_line.garment_id as 'garmentid',
catalogue.description as 'description',
SUM(garment_hire_line.days) AS 'TotalDaysHired',
SUM(garment_hire_line.days*catalogue.daily_rate) AS 'MoneyIn',
'' as 'LastYrTotalDaysHired',
'' as 'LastYrMoneyIn'
FROM garment_hire_line
INNER JOIN garment ON garment_hire_line.garment_id = garment.garment_id
INNER JOIN catalogue ON garment.catalogue_id = catalogue.catalogue_id
WHERE garment_hire_line.date_out>DATE_SUB(NOW(),INTERVAL 3 MONTH)
GROUP by garment_hire_line.garment_id
UNION
SELECT garment_hire_line.date_out as 'dateout',
garment_hire_line.garment_id as 'garmentid',
catalogue.description as 'description','' as 'TotalDaysHired',
'' as 'MoneyIn',
SUM(garment_hire_line.days) AS 'LastYrTotalDaysHired',
SUM(garment_hire_line.days*catalogue.daily_rate) AS 'LastYrMoneyIn'
FROM garment_hire_line
INNER JOIN garment ON garment_hire_line.garment_id = garment.garment_id
INNER JOIN catalogue ON garment.catalogue_id = catalogue.catalogue_id
WHERE garment_hire_line.date_out<DATE_SUB(NOW(),INTERVAL 1 YEAR)
AND garment_hire_line.date_out>DATE_SUB(NOW(),INTERVAL '1:3' YEAR_MONTH)
GROUP by garment_hire_line.garment_id
garment_hire_line
garment_line_id date_out Days return_date discount hire_id garment_id
8 12/06/2012 4 16/06/2012 0 1 4
9 12/06/2012 5 17/06/2012 0 1 2
10 12/06/2012 4 16/06/2012 0 1 4
11 11/07/2012 3 14/07/2012 10 2 2
12 10/08/2012 3 13/08/2012 0 3 4
13 09/09/2012 2 11/09/2012 5 4 3
14 09/01/2017 3 12/09/2017 0 5 3
Catalogue
catalogue_id| description| designer| Type| daily_rate| supplier_name| supplier_purchase_price| date_purchased| quantity|
1 Hat Elizabeth Kate Accessory 3 Lids 25 28/02/2017 3
2 Dress Calvin Klein Designer Outfit 20 Glam 260 12/05/2012 2
3 Handbag Gucci Accessory 4 Hold On 200 01/01/2017 4
4 Witches Dress null Fancy Dress 12 Fancy Fred 74 21/05/2012 7
Garment
garment_id Colour sizing catalogue_id location_id supplier_id
1 Black Medium 1 2 1
2 Black 10 2 2 2
3 Black 8 2 2 3
4 Black 0 3 2 4
5 Red Child 4 2 1
6 Black Medium 1 2 2
7 Black 10 2 2 3
The main issue is that in your SQL query you use '' for some fields that really are supposed to return numerical data. So you get some records with '' and 3.00 in the same column, which is a conflict in data type. This causes some undesired conversions leading to the garbage output you saw.
Fix this by replacing '' with null.
But you might also want to look into some other issues:
As you group by the garment ID, you have no control over which date is being displayed in the first column when a particular garment was hired multiple times in the same period.
In fact this query would not be valid in newer versions of MySql (unless you set an option to allow it) and violates standard SQL rules. So you should either remove that column from the query, or apply an aggregation function to it (like MAX), or group by it.
By using a union you will not really take advantage of showing the two periods side-by-side: 2 out of the 4 fields in one record will always be null. You can do this without union and filter what you sum up with an expression in the sum aggregate function.
So I would suggest this query:
SELECT MAX(garment_hire_line.date_out) as `LastDateOut`,
garment_hire_line.garment_id as `garmentid`,
catalogue.description as `description`,
SUM(CASE WHEN garment_hire_line.date_out > DATE_SUB(NOW(),INTERVAL 3 MONTH)
THEN garment_hire_line.days
ELSE 0
END) AS `TotalDaysHired`,
SUM(CASE WHEN garment_hire_line.date_out > DATE_SUB(NOW(),INTERVAL 3 MONTH)
THEN garment_hire_line.days*catalogue.daily_rate
ELSE 0
END) AS `MoneyIn`,
SUM(CASE WHEN garment_hire_line.date_out <= DATE_SUB(NOW(),INTERVAL 3 MONTH)
THEN garment_hire_line.days
ELSE 0
END) AS `LastYrTotalDaysHired`,
SUM(CASE WHEN garment_hire_line.date_out <= DATE_SUB(NOW(),INTERVAL 3 MONTH)
THEN garment_hire_line.days*catalogue.daily_rate
ELSE 0
END) AS `LastYrMoneyIn`
FROM garment_hire_line
INNER JOIN garment ON garment_hire_line.garment_id = garment.garment_id
INNER JOIN catalogue ON garment.catalogue_id = catalogue.catalogue_id
WHERE garment_hire_line.date_out > DATE_SUB(NOW(),INTERVAL 3 MONTH)
OR ( garment_hire_line.date_out > DATE_SUB(NOW(),INTERVAL 15 MONTH)
AND garment_hire_line.date_out < DATE_SUB(NOW(),INTERVAL 12 MONTH)
)
GROUP BY garment_hire_line.garment_id
ORDER BY 1
If you prefer to have a separate line for each date, then remove the MAX function, but add garment_hire_line.date_out in the GROUP BY list.
Related
I am working on a program that will track a salespersons sold units, these units can be full deals (1) or half deals (0.5). What I need to do is find a way to get the SUM of the full deals and the half deals grouped by a salespersons ID.
Here is the database structure:
id
salesperson_id
salesperson_two_id
sold_date
1
5
null
2022-07-02
2
3
5
2022-07-18
3
4
null
2022-07-16
4
5
3
2022-07-12
5
3
5
2022-07-17
6
5
null
2022-07-18
I have a query that works if I only want to retrieve the SUM for one salesperson:
SELECT
SUM(case when salesperson_id = 5 and isnull(salesperson_two_id) then 1 end) as fullDeals,
SUM(case when salesperson_id != 5 and salesperson_two_id = 5
or salesperson_id = 5 and salesperson_two_id != 5 then 0.5 end) as halfDeals
FROM sold_logs WHERE MONTH(sold_date) = 07 AND YEAR(sold_date) = 2022;
Output would be as expected:
fullDeals
halfDeals
2
1.5
What I am trying to accomplish is get these results for all salespeople in the table and have no clue how to make it happen. Here is what I am trying to get in the results:
salesperson_id
totalDeals
5
3.5
3
1.5
4
1
I would like the results sorted by totalDeals if at all possible.
Use UNION ALL to get a resultset with all the rows for each salesperson, filter for the month that you want and aggregate:
SELECT salesperson_id,
SUM(CASE WHEN salesperson_two_id IS NULL THEN 1 ELSE 0.5 END) totalDeals
FROM (
SELECT salesperson_id, salesperson_two_id, sold_date FROM sold_logs
UNION ALL
SELECT salesperson_two_id, salesperson_id, sold_date FROM sold_logs WHERE salesperson_two_id IS NOT NULL
) t
WHERE MONTH(sold_date) = 7 AND YEAR(sold_date) = 2022
GROUP BY salesperson_id
ORDER BY totalDeals DESC;
See the demo.
I have example data
ID DAY ORDER TIME PRODUCT
1 1 1 1 1
2 1 1 1 2
3 1 1 1 3
4 1 2 2 1
5 1 2 2 2
6 1 2 2 3
7 1 2 *3* 1
8 1 2 *3* 2
9 1 2 *3* 3
I want to prevent to having mltiple orders in different time at same day. if I set unique index on DAY,ORDER,TIME I will not be able to insert multiple time anyway, but I want to disable multiple different TIME. Is this possible with mysql?
Have can I find all records where there multiple different TIME value in same DAY and ORDER and delete them?
in this case I would like to delete records 7,8 ad 9 with SQL query because it is duplicate ORDER inserted.
I don't want to normalize table I will stick with this database structure.
Thank you very much
You can use delete with a join clause to find the duplicates and delete them:
delete
from t join
(select day, "order", min(time) as tokeeptime
from t
group by day, "order"
) tokeep
on t.day = tokeep.day and t."order" = tokeep."order" and t.time <> tokeeptime;
DELETE a
FROM tableName a
INNER JOIN
(
SELECT a.DAY, a.ORDER, MAX(a.TIME) Time
FROM tableName a
GROUP BY a.DAY, a.ORDER
HAVING COUNT(DISTINCT TIME) > 1
) b ON a.DAY = b.DAY AND
a.Order = b.Order AND
a.Time = b.Time
SQLFiddle Demo
I am trying to compare 2 rows and display the same ones.I did browse but was not able to find the right solution.
Table A
Count status Division
20 A 1
30 B 2
10 c 1
12 z 1
From the above table I want to display whose division is same.
Count status Division
20 A 1
10 c 1
12 z 1
Try this
Select * from TableA
Group By Division
Having Count(*) > 1
Select * from TableA
Group By Division
having Count(*) = 1
Here i used case statement , it worked for me
select CompanyCode ,'Commission Pec', Year
,sum(case when CommissionType='Commission Recevied' then JAN else 0 end)/sum(case when CommissionType='Net Payments from WM' and isnull(JAN,0)<>0 then JAN else 1 end)
from Commission_Consolidate
group by CompanyCode,Year
end
I am trying to show three different figures of the same column In a mysql query and joining all three tables, I would like to keep one month static: April, so it would be a case like this I want to show The current month, the previous month and the static month of the year I'm working with, in this case let us stick with 2012
table: persons
ID name
1 Carl
table: vehicle
ID v_name person_veh
100 Dodge Viper 1
Table:payment
pay_id , pay_date, amount person_id
1 2012-02-12 1000 1
2 2012-03-11 780 1
3 2012-04-15 890 1
4 2012-05-12 1200 1
5 2012-06-12 1890 1
6 2012-07-12 1350 1
7 2012-08-12 1450 1
So what I want to do is show the column amount for the month of April as I said I want to keep that row static: 890, the current month lets say the current month is August:1450 and the previous month amount which would be July:1350: so the final result would be something like this:
name v_name april_amount current_month_amount previous_month_amount
Carl Dodge viper 890 1450 1350
You can use the following - which uses an aggregate function with a CASE statement:
select p.name,
v.v_name,
sum(case when Month(py.pay_date) = 4 then amount end) april_amount,
sum(case when Month(py.pay_date) = Month(curdate())
then amount end) current_month_amount,
sum(case when Month(py.pay_date) = Month(curdate())-1
then amount end) previous_month_amount
from persons p
left join vehicle v
on p.id = v.person_veh
left join payment py
on p.id = py.person_id
group by p.name,
v.v_name
see SQL Fiddle with Demo
Try
SELECT a.name, b.pay_date, b.amount, b.person_id, c.v_name
FROM persons a
LEFT JOIN payment b on a.id = b.person_id
LEFT JOIN vehicle c on a.id = c.person_veh
This query assumes id, person_veh and person_id are the like columns which links this user across these three tables
I have a query that involves searching database over a range of 30 days. Queries, both with correct output and wrong output are below:
CORRECT RESULTS:
SELECT
affiliates.member_id,
IFNULL( COUNT(orders.deal_id) , 0 ) AS deals_count,
IFNULL( SUM(orders.quantity) , 0 ) AS deals_quanity
FROM affiliates
LEFT JOIN deals ON affiliates.member_id = deals.member_id
LEFT JOIN orders ON deals.deal_id = orders.deal_id
LEFT JOIN customers_orders_link ON orders.order_id = customers_orders_link.order_id
AND DATE(customers_orders_link.datetime) BETWEEN '2011-06-01' AND '2011-07-01'
AND customers_orders_link.order_status = 'Delivered'
GROUP BY affiliates.member_id;
EXPECTED & RECEIVED: (Correct)
MemberID COUNT SUM
1 11 16
2 0 0
WRONG RESULTS:
//Notice the change in the date range
SELECT
affiliates.member_id,
IFNULL( COUNT(orders.deal_id) , 0 ) AS deals_count,
IFNULL( SUM(orders.quantity) , 0 ) AS deals_quanity
FROM affiliates
LEFT JOIN deals ON affiliates.member_id = deals.member_id
LEFT JOIN orders ON deals.deal_id = orders.deal_id
LEFT JOIN customers_orders_link ON orders.order_id = customers_orders_link.order_id
AND DATE(customers_orders_link.datetime) BETWEEN '2011-10-01' AND '2011-10-31'
AND customers_orders_link.order_status = 'Delivered'
GROUP BY affiliates.member_id
EXPECTED:
MemberID COUNT SUM
1 0 0
2 0 0
BUT I RECEIVE: (INCORRECT OUTPUT)
MemberID COUNT SUM
1 11 16
2 0 0
The first query is producing correct results whereas the second query is producing incorrect results. Even if I use a date in the past as the range, I still receive the same Incorrect Output. Its as if the query is completely ignoring the date range specification. So this case of ignoring the date range specification seems to be the problem.
How can I make the query "see" and "obey" the date range specification and actually receive the Expected Output for the 2nd query listed above?
EDIT 1:
//Table: Orders
order_id deal_id quantity price
1 1 2 40.00
1 2 1 15.00
2 1 1 20.00
3 9 1 5.00
4 1 2 40.00
4 9 2 10.00
5 1 1 20.00
5 9 1 5.00
6 1 2 40.00
6 9 2 10.00
7 1 1 20.00
8 11 1 1.00
//Table: customers_orders_link
order_id customer_id order_status datetime
1 4 Cancelled 2011-06-05 20:26:45
2 4 Delivered 2011-06-05 20:38:28
3 4 Pending Payment 2011-06-05 20:56:50
4 4 Pending Payment 2011-06-09 17:03:08
5 4 Pending Payment 2011-06-09 17:12:23
6 4 Pending Payment 2011-06-09 17:19:57
7 4 Pending Payment 2011-06-09 17:40:59
8 4 Pending Payment 2011-06-10 03:55:17
I solved it myself using a totally different method.
I don't know what your data looks like, but I suspect your LEFT JOIN customers_orders_link is to blame. If you only want to tally COUNT() and SUM() when the conditions of that table are met, it should be a standard JOIN in place of a LEFT JOIN.