Getting monthly totals in MySQL - mysql

I have a table with 4 columns:
bookingdatetime (DateTime)
status (Varchar, with 4 possible entries: 'Open', 'Closed', 'Canceled', and 'Unconfirmed')
quotedprice (Int)
city (Varchar, with 3 possible entries: la, sf, ny
I want to get a total amount for reach month for rows that have the status of 'Closed' and 'Open' in a specific city.
I want the output to look like:
mm/yy - total of all of that month's quotes for 'Closed' in X city
mm/yy - total of all of that month's quotes all 4 categories
This is what I have now, but it doesn't let me do the second output mentioned above:
SELECT DATE_FORMAT(bookingdatetime, "%m/%y") AS mmyy,
SUM(quotedprice) as revenue
FROM `reservations`
WHERE city = 'oc' and status = "Closed"
GROUP BY DATE_FORMAT(bookingdatetime, '%m/%y'), YEAR(bookingdatetime)
ORDER BY YEAR(bookingdatetime), DATE_FORMAT(bookingdatetime, '%m/%y')
But I want to be able to get potential (all 4 categories, not just 'Closed') sales as well, so how would I do that?

From Luuk's comment this seems to do it, is this the best way to do it?
SELECT DATE_FORMAT(bookingdatetime, "%m/%y") AS mmyy,
SUM(quotedprice) as potentialrevenue,
SUM(CASE WHEN status='Confirmed' THEN quotedprice ELSE 0 END) AS revenue
FROM `reservations`
WHERE city = 'la'
GROUP BY DATE_FORMAT(bookingdatetime, '%m/%y'), YEAR(bookingdatetime)
ORDER BY YEAR(bookingdatetime), DATE_FORMAT(bookingdatetime, '%m/%y')
Can someone explain to me what "ELSE 0 END" does? I'm not familiar with that...

Related

How to create a calculated row in sql or power bi?

I am trying to do a calculation on 2 rows on a SQL I wrote so I can have a 3 row that will be Profit and show the amount is it possible?
This dummy data not true to any company!
see below :
SELECT a.pcg_type GL_Acoount_Group,
Abs(sum(b.debit-b.credit)) GL_Amount
FROM dolibarr.llx_accounting_account a
JOIN dolibarr.llx_accounting_bookkeeping b
ON a.account_number = b.numero_compte
WHERE a.pcg_type IN ('INCOME', 'EXPENSE')
ANDa.fk_pcg_version = 'PCG99-BASE'
GROUP BY a.pcg_type
Results:
Group. Amt
INCOME 379200
EXPENSE 65700
Expected Results:
Group. Amt
INCOME 379200
EXPENSE 65700
PROFIT 313500
Use ROLLUP for adding an extra row and use CASE statement inside SUM() function for treating expense value as negative for calculation
--MySQL
SELECT COALESCE(acc_type, 'Profit') "Group"
, ABS(SUM(CASE WHEN acc_type = 'EXPENSE' THEN -amount ELSE amount END)) amt
FROM test
GROUP BY acc_type WITH ROLLUP
Another way by using UNION ALL
SELECT acc_type "Group"
, SUM(amount) Amt
FROM test
GROUP BY acc_type
UNION ALL
SELECT 'Profit' AS "Group"
, SUM(CASE WHEN acc_type = 'EXPENSE' THEN -amount ELSE amount END) Amt
FROM test
Please check this url https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=f859036ffcb3d808330bce5346daee1e

Combining two resulted columns on order by when one is null

I have a inventory table where i have records which refers to inventory movement of products sold by a company. The movement have 'INCOMING', 'OUTGOING' params based on type of inventory movement. It also has one more column which says the type of 'INCOMING' or 'OUTGOING'... like incoming because of NEW STOCK arrival, outgoing because of PURCHASE by customer... etc...
Now am making a report where i want to list non sold products for a long while. So am making the following query...
SELECT p.id as pid, product_name, DATEDIFF(NOW(), MAX(case when movement_type='OUTGOING' and movement_type_category='PURCHASED' then movement_on end)) AS unsold_days_since_last_sale, DATEDIFF(NOW(), MIN(case when movement_type='INCOMING' and movement_type_category='NEW_STOCK' and quantity>0 then movement_on end)) AS unsold_days_since_first_inventory_in, MAX(case when movement_type='INCOMING' and movement_type_category='NEW_STOCK' and quantity>0 then movement_on end) AS last_inv_in from inventory_movement im left join products p on im.product = p.id GROUP BY product having last_inv_in > 0 ORDER BY unsold_days_since_last_sale desc limit 100
And i get the following output as shown in the image.
This output is nearly correct but with one issue. If a product was never sold even once in the past the column where i try to get days different between CURRENT DAY and LAST SOLD DAY will return null. In that case i need the DAYS difference between CURRENT DAY and FIRST INVENTORY IN of that product to be on the place so i can order that column descending and get the output. But i can get those data as only 2 different columns not as one column. Can someone help me to write a query to get it as combined column so i can sort that data to get result. Am attaching my inventory movement table snap also to show how the data look like...
I think IfNull function will resolve your issue.
Here's modified query.
SELECT p.id AS pid,
product_name,
Datediff(Now(), Ifnull(Max(CASE
WHEN movement_type = 'OUTGOING'
AND movement_type_category =
'PURCHASED' THEN
movement_on
end), Min(CASE
WHEN movement_type = 'INCOMING'
AND movement_type_category =
'NEW_STOCK'
AND quantity > 0 THEN
movement_on
end))) AS
unsold_days_since_last_sale,
Datediff(Now(), Min(CASE
WHEN movement_type = 'INCOMING'
AND movement_type_category = 'NEW_STOCK'
AND quantity > 0 THEN movement_on
end)) AS
unsold_days_since_first_inventory_in,
Max(CASE
WHEN movement_type = 'INCOMING'
AND movement_type_category = 'NEW_STOCK'
AND quantity > 0 THEN movement_on
end) AS last_inv_in
FROM inventory_movement im
LEFT JOIN products p
ON im.product = p.id
GROUP BY product
HAVING last_inv_in > 0
ORDER BY unsold_days_since_last_sale DESC
LIMIT 100

mysql returning 2 different columns from the same field but with different conditions

How can I return 2 columns from the same field with different conditions, these are the two conditions:
SELECT CITY,REGION,SALES FROM SALESREPS WHERE SALES < QUOTA;
SELECT CITY,REGION,SALES FROM SALESREPS WHERE SALES > QUOTA;
I mean some say that I just need to put 'AND'. Well what I need is a 1 line code from that example that will return 2 different sales columns. 1st column will be the sales < quota and the other column is the sales > quota. All of these are from the same table.
You can use a mySql if statement like the following:
SELECT
CITY,
REGION,
SALES,
IF (SALES < QUOTA,SALES,null) as BELOW_QUOTA,
IF (SALES > QUOTA,SALES,null) as ABOVE_QUOTA
FROM SALESREPS;
SELECT CITY,REGION,IF(SALES < QUOTA, SALES) AS LessThanColumn, IF(Sales > QUOTA, Sales) AS GreaterThanColumn FROM SALESREPS
If you simply want 4 columns (CITY, REGION, LOW_SALES, HIGH_SALES), with data for every row but only one of LOW_SALES and HIGH_SALES have a value (the other is null), then you can:
select CITY
, REGION
, case when SALES < QUOTA then SALES end as LOW_SALES
, case when SALES > QUOTA then SALES end as HIGH_SALES
from SALESREPS;
The SQL statement uses database agnostic syntax, so it'll work on databases other than MySQL.
This can also be done with a union:
select CITY, REGION, SALES as LOW_SALES, null as HIGH_SALES
from SALESREPS
where SALES < QUOTA
union all
select CITY, REGION, null as LOW_SALES, SALES as HIGH_SALES
from SALESREPS
where SALES > QUOTA;
Neither makes much sense to me, e.g. what about rows with SALES = QUOTA?
Now, if you want totals for CITY/REGION, that makes more sense to me (including exact equal in HIGH_SALES):
select CITY
, REGION
, sum(case when SALES < QUOTA then SALES else 0 end) as LOW_SALES
, sum(case when SALES >= QUOTA then SALES else 0 end) as HIGH_SALES
from SALESREPS
group by CITY
, REGION;
If you just want counts instead:
select CITY
, REGION
, sum(case when SALES < QUOTA then 1 else 0 end) as LOW_SALES
, sum(case when SALES >= QUOTA then 1 else 0 end) as HIGH_SALES
from SALESREPS
group by CITY
, REGION;

MySql count in group_concat

I'm trying to create a query that would return a table as followed:
dayName, #ofStatus1,#ofStatus2,#ofStatus3
dayName, #ofStatus1,#ofStatus2,#ofStatus3
dayName, #ofStatus1,#ofStatus2,#ofStatus3
dayName, #ofStatus1,#ofStatus2,#ofStatus3
dayName, #ofStatus1,#ofStatus2,#ofStatus3
dayName, #ofStatus1,#ofStatus2,#ofStatus3
dayName, #ofStatus1,#ofStatus2,#ofStatus3
Basically I have a table where users get to enter cases. Each case has the following fields(datedCreated, status).
There are three (3) status possible (new, progress, closed)
So I would like to retrieve the number of each status for each day.
Each line would look something like this:
Monday, 8,3,2
Tuesday, 8,3,2
Wednesday, 8,3,2
...
I have something that looks like this but can't seem to get it to work.
SELECT DAYNAME(dateAdded)AS Date, COUNT(status) AS Count, GROUP_CONCAT(CONCAT(status, ',', "54") SEPARATOR ',' ) AS Text FROM clients GROUP BY DATE(dateAdded) ORDER BY dateAdded LIMIT 7
I know right now I have three colomns, but I need it to be in one columns.
Thank your for the help in advance.
Try:
SELECT concat(
DAYNAME(dateAdded),', '
sum(case when status = 'new' then 1 else 0 end),','
sum(case when status = 'progress' then 1 else 0 end),','
sum(case when status = 'closed' then 1 else 0 end)) as single_col
FROM clients
GROUP BY DATE(dateAdded)
ORDER BY dateAdded
Why not just group concat the results?
SELECT
GROUP_CONCAT(t_date, t_new, t_progress, t_closed) AS 'Status Per Day'
FROM
( SELECT
DAYNAME(dateAdded)AS t_date,
SUM(status = 'new') t_new,
SUM(status = 'progress') t_progress,
SUM(status = 'closed') t_closed
FROM clients
GROUP BY DATE(dateAdded)
ORDER BY dateAdded LIMIT 7
) t
GROUP BY t_date

MYSQL Query - grabbing all the records that meet the criteria 3 or more times

Not sure how to do this but I am trying to grab all the parcels from a MYSQL DB that have had multiple years of delinquencies. Right now I can count how many delinquencies I have for the years given using the following query:
SELECT
parcel, COUNT(*), due
FROM
`deliquent_property`
WHERE year IN ('2013', '2012', '2011', '2010', '2009') AND
CAST(replace(replace(ifnull(due,0),',',''),'$','') AS decimal(10,2)) > 0
GROUP BY parcel
HAVING COUNT(*) > 2;
So I get something like this
'XXX-XXX-XXX1' '3' '167.00'
'XXX-XXX-XXX2' '4' '190'
Where the amount is the last record for that parcel in the DB. The problem is what I really want is a list of parcels with each years overdue amount shown, something like this (skipping those that do not have a least 3 delinquencies):
'XXX-XXX-XXX1' '2013' '1267.78'
'XXX-XXX-XXX1' '2012' '1000.38'
'XXX-XXX-XXX1' '2011' '167.00'
'XXX-XXX-XXX2' '2013' '1000.00'
'XXX-XXX-XXX2' '2012' '500.00'
'XXX-XXX-XXX2' '2011' '100.00'
'XXX-XXX-XXX2' '2010' '190.00'
I am half way there but I am lost on getting this last part.
You can join the table back to your list. Here is one way:
select dp.*
from delinquent_property dp join
(SELECT parcel, COUNT(*)
FROM delinquent_property
WHERE year IN ('2013', '2012', '2011', '2010', '2009') AND
CAST(replace(replace(ifnull(due,0),',',''),'$','') AS decimal(10,2)) > 0
GROUP BY parcel
HAVING COUNT(*) > 2
) p3
on dp.parcel = p3.parcel
where CAST(replace(replace(ifnull(due,0),',',''),'$','') AS decimal(10,2)) > 0
order by parcel;