SQL - Percentage - mysql

I need to make a query, which results in a percentage.
The query I have at the moment looks like this:
select COUNT(CREATE_WEEKDAY),
CREATE_WEEKDAY,
COUNT(CREATE_WEEKDAY) * 100 /
from call_view
WHERE (create_month = MONTH(NOW() - INTERVAL 1 MONTH))
AND (create_year = YEAR(NOW() - INTERVAL 1 MONTH))
AND CUSTOMER_COMPANY_NAME = "Company"
group by CREATE_WEEKDAY
If I start the query the result shows:
COUNT(CREATE_WEEKDAY) | CREATE_WEEKDAY | COUNT(CREATE_WEEKDAY) * 100
111 Friday 11100
225 MONDAY 22500
and so on....
I want the last column to display the
"COUNT(CREATE_WEEKDAY) * 100 / SUM(COUNT(CREATE_WEEKDAY))"
->> this last part should be the SUM OF all the CREATE_WEEKDAY. In the example give = 111 + 225 = 336
But this Code isn't working. I appreciate any help.
Cheers

Here is one way using Sub-query
First identify the total count for the given filter's(where clause)
SELECT Count(*)
FROM call_view
WHERE ( create_month = Month(Now() - INTERVAL 1 month) )
AND ( create_year = Year(Now() - INTERVAL 1 month) )
AND customer_company_name = 'Company'
Then use this query in denominator to find percentage
SELECT Count(create_weekday),
create_weekday,
Count(create_weekday) * 100 / (SELECT Count(*)
FROM call_view
WHERE
( create_month = Month(Now() -
INTERVAL 1 month) )
AND ( create_year = Year(
Now() - INTERVAL 1 month) )
AND customer_company_name =
'Company')
FROM call_view
WHERE ( create_month = Month(Now() - INTERVAL 1 month) )
AND ( create_year = Year(Now() - INTERVAL 1 month) )
AND customer_company_name = "Company"
GROUP BY create_weekday

Join with a subquery that calculates the total count.
select COUNT(*),
CREATE_WEEKDAY,
COUNT(*) * 100 / total_count
from call_view
CROSS JOIN (SELECT COUNT(*) AS total_count
FROM call_view
WHERE create_month = MONTH(NOW() - INTERVAL 1 MONTH)
AND create_year = YEAR(NOW() - INTERVAL 1 MONTH)
AND customer_company_name = "Company") AS x
WHERE (create_month = MONTH(NOW() - INTERVAL 1 MONTH))
AND (create_year = YEAR(NOW() - INTERVAL 1 MONTH))
AND CUSTOMER_COMPANY_NAME = "Company"
group by CREATE_WEEKDAY

Related

QOQ growth Mysql

i have query
select a.`2021`,
b.`2022`,
a.product,
concat(ceil((b.`2022`-a.`2021`)/ a.`2021` * 100), '%') as growth
from ( SELECT SUM(total) as `2021`,
product,
sum
FROM table
WHERE YEAR(month) = 2021
AND case when day(CURRENT_DATE()) > 10
then QUARTER(month) = QUARTER(CURRENT_DATE() - INTERVAL 1 MONTH)
else QUARTER(month) = QUARTER(CURRENT_DATE() - INTERVAL 3 MONTH)
end
GROUP BY Product ,
YEAR(month) )a
JOIN ( SELECT SUM(total) as `2022`,
Product
FROM table
WHERE YEAR(month) = 2022
AND case when day(CURRENT_DATE()) > 10
then QUARTER(month) = QUARTER(CURRENT_DATE() - INTERVAL 1 MONTH)
else QUARTER(month) = QUARTER(CURRENT_DATE() - INTERVAL 3 MONTH)
end
GROUP BY Product ,
YEAR(month) ) b on a.Product=b.Product;
if the current date is not the end of the quarter then the data that appears is the data in the previous quarter period

MySQL query difficulty

I would like your help with the following:
query 1:
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 12) as x12WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY)
AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
query 2:
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 4) as x4WeeksAvg
FROM orders LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 28 DAY)
AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
Is there any way to have the result like this (the queries returns different number of results):
------------------------------------
| xCode | x12WeeksAvg | x4WeeksAvg |
------------------------------------
| ... | ... | ... |
------------------------------------
Thank you!!
Split the BETWEEN condition
orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY)
AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
into two parts
AND orders.O_CUSTDATE >= DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY)
AND orders.O_CUSTDATE <= DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
and rewrite it to
AND orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
AND orders.O_CUSTDATE <= CURDATE() - INTERVAL (DAYOFWEEK(NOW()) - 1) DAY
to get shorter and more readable code. Do the same for the second query.
Now the two queries differ only in two expressions
(sum(ordercont.QTY) / 12) as x12WeeksAvg
(sum(ordercont.QTY) / 4) as x4WeeksAvg
orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 28) DAY
Given
<X>: orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
and
<Y>: orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 28) DAY
you can use conditional aggregation to combine the two queries:
SELECT stock.ST_CODE as xCODE,
(sum(CASE WHEN <X> THEN ordercont.QTY ELSE 0 END) / 12) as x12WeeksAvg,
(sum(CASE WHEN <Y> THEN ordercont.QTY ELSE 0 END) / 4) as x4WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE <= CURDATE() - INTERVAL (DAYOFWEEK(NOW()) - 1) DAY
GROUP BY stock.ST_CODE
Replace <X> and <Y> accordingly.
Update
To improve the performance you can add
AND orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
to the WHERE clause.
Also note that the condition stock.ST_CODE IS NOT NULL will convert your LEFT JOINs to INNER JOINs. So you could as well just write JOIN.
You can subquery them like this to get your desired output:
SELECT A.xCODE,
COALESCE(B.x12WeeksAvg, 'N/A') as x12WeeksAvg,
COALESCE(C.x4WeeksAvg, 'N/A') as x4WeeksAvg
FROM (SELECT DISTINCT ST_CODE as xCODE FROM stock) A
LEFT JOIN (
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 12) as x12WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY) AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
) B ON A.xCODE = B.xCODE
LEFT JOIN (
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 4) as x4WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 28 DAY) AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
) C ON A.xCODE = C.xCODE
WHERE COALESCE(B.x12WeeksAvg, C.x4WeeksAvg) IS NOT NULL

Compare two numbers and receive true or false?

select *, COUNT(*), DATE_FORMAT(CREATE_DATE,'%m-%Y') AS form_date
from incident_view
where (create_month = month(NOW() - INTERVAL 1 MONTH)
and (create_year = year(NOW() - INTERVAL 1 MONTH)))
OR (create_month = month(NOW() - INTERVAL 2 MONTH)
and (create_year = year(NOW() - INTERVAL 2 MONTH)))
AND CUSTOMER_COMPANY_NAME = "Company"
GROUP BY CREATE_MONTH
Hello everyone,
The query I have above is working fine.
The result I get are some rows, but the important rows are:
COUNT(*) | form_date
667 01-16
1964 02-16
I wonder if it's possible to compare the two counts of the last 2 months, whether the last month (02-16) > the second last month (01-16).
If 02-16 > 01-16 I want the result to be true, if not then false.
Would appreciate any help.
Regards.
Instead of grouping by the month/year, use it in a CASE or IF when calculating the counts.
SELECT SUM(IF(create_month = MONTH(NOW() - INTERVAL 1 MONTH)
AND create_year = YEAR(NOW() - INTERVAL 1 MONTH), 1, 0)) >
SUM(IF(create_month = MONTH(NOW() - INTERVAL 2 MONTH)
AND create_year = YEAR(NOW() - INTERVAL 2 MONTH), 1, 0)) AS count_higher
FROM incident_view
WHERE customer_company_name = "Company"
If you want 3 different results for greater than, equal to, or less than, the best way is to calculate the sums in a subquery so you can name them and use CASE to return different values for each case.
SELECT CASE WHEN last_month > prev_month THEN 1
WHEN last_month = prev_month THEN 2
ELSE 0
END AS diff
FROM (
SELECT SUM(IF(create_month = MONTH(NOW() - INTERVAL 1 MONTH)
AND create_year = YEAR(NOW() - INTERVAL 1 MONTH), 1, 0)) AS last_month,
SUM(IF(create_month = MONTH(NOW() - INTERVAL 2 MONTH)
AND create_year = YEAR(NOW() - INTERVAL 2 MONTH), 1, 0)) AS prev_month
FROM incident_view
WHERE customer_company_name = "Company"
) AS subquery
You could do something like
Select max(viewcount)
FROM (select * , COUNT(*) AS viewcount,
DATE_FORMAT(CREATE_DATE,'%m-%Y') AS form_date
from incident_view
Where (create_month = month(NOW() - INTERVAL 1 MONTH) and (create_year = year(NOW() - INTERVAL 1 MONTH)))
OR (create_month = month(NOW() - INTERVAL 2 MONTH) and (create_year = year(NOW() - INTERVAL 2 MONTH)))
AND CUSTOMER_COMPANY_NAME = "Company"
GROUP BY CREATE_MONTH);

SQL - Limit all Except TOP 6

the SQL I got at the moment and it is working :
SELECT Count(CATEGORY), COUNT(INCIDENT_ID), CATEGORY,
ROUND(Count(CATEGORY) * 100 / (SELECT Count(*)
FROM incident_view
WHERE
( create_month = Month(Now() -
INTERVAL 1 month) )
AND ( create_year = Year(
Now() - INTERVAL 1 month) )
AND customer_company_name = "Company"
), 1) AS Percentage
FROM incident_view
WHERE ( create_month = Month(Now() - INTERVAL 1 month) )
AND ( create_year = Year(Now() - INTERVAL 1 month) )
AND customer_company_name = "Company"
GROUP BY CATEGORY
ORDER BY COUNT(INCIDENT_ID) DESC
limit 6
This query results in the top 6 Categorys and their number of Incidents with the Percentage.
Now I want to generate a second query, which shows me all Category and their Total Number + Percentage , !EXCEPT! the 6 Category I retrieved in the first query.
So if I have let's say 20 Categorys, I now want number 7-20 Displayed, under one name "Other" and the total Number Sumed up of all Categories (7-20) + their Percentage.
The result should look like this for example:
Category| Number of Inicdents | Percentage
Other 200 20%
Other should Contain all categories, except the from the first query..
Is this Possible?
Would appreciate any help.
------------EDIT-------------
SELECT Count(CATEGORY), COUNT(INCIDENT_ID), CATEGORY,
ROUND(Count(CATEGORY) * 100 / (SELECT Count(*)
FROM incident_view
WHERE
( create_month = Month(Now() -
INTERVAL 1 month) )
AND ( create_year = Year(
Now() - INTERVAL 1 month) )
AND customer_company_name = "Company"
), 1) AS Percentage
FROM incident_view
WHERE ( create_month = Month(Now() - INTERVAL 1 month) )
AND ( create_year = Year(Now() - INTERVAL 1 month) )
AND customer_company_name = "Company"
GROUP BY CATEGORY
ORDER BY COUNT(INCIDENT_ID)DESC
limit 6, 1295852105
Cheers
As you don't know the last record so use just a large number as below code
SELECT Count(CATEGORY), COUNT(INCIDENT_ID), CATEGORY,
ROUND(Count(CATEGORY) * 100 / (SELECT Count(*)
FROM incident_view
WHERE
( create_month = Month(Now() -
INTERVAL 1 month) )
AND ( create_year = Year(
Now() - INTERVAL 1 month) )
AND customer_company_name = "Company"
), 1) AS Percentage
FROM incident_view
WHERE ( create_month = Month(Now() - INTERVAL 1 month) )
AND ( create_year = Year(Now() - INTERVAL 1 month) )
AND customer_company_name = "Company"
GROUP BY CATEGORY
ORDER BY COUNT(INCIDENT_ID) DESC
limit 6, 18446744073709551615;

Calculate group percentage to 1 decimal places - SQL

I have this SQL at the moment:
SELECT Count(create_weekday),
create_weekday,
Count(create_weekday) * 100 / (SELECT Count(*)
FROM call_view
WHERE
( create_month = Month(Now() -
INTERVAL 1 month) )
AND ( create_year = Year(
Now() - INTERVAL 1 month) )
AND customer_company_name = "Company"
) AS Percentage
FROM call_view
WHERE ( create_month = Month(Now() - INTERVAL 1 month) )
AND ( create_year = Year(Now() - INTERVAL 1 month) )
AND customer_company_name = "Company"
GROUP BY CREATE_WEEKDAY
ORDER BY (CASE CREATE_WEEKDAY
WHEN 'Monday' THEN 1
WHEN 'Tuesday' THEN 2
WHEN 'Wednesday' THEN 3
WHEN 'Thursday' THEN 4
WHEN 'Friday' THEN 5
WHEN 'Saturday' THEN 6
WHEN 'Sunday' THEN 7
ELSE 100 END)
It's working and I received the result:
Count(create_weekday) | Create_Weekday | Percentage
225 Monday 28.0899
How do I round to only 1 decimal place?( Like 28.1)
Would appreciate any help
Use ROUND(Percentage, 1):
SELECT Count(create_weekday),
create_weekday,
ROUND(Count(create_weekday) * 100 / (SELECT Count(*)
FROM call_view
WHERE
( create_month = Month(Now() -
INTERVAL 1 month) )
AND ( create_year = Year(
Now() - INTERVAL 1 month) )
AND customer_company_name = "Company"
), 1) AS Percentage
FROM call_view
WHERE ( create_month = Month(Now() - INTERVAL 1 month) )
AND ( create_year = Year(Now() - INTERVAL 1 month) )
AND customer_company_name = "Company"
GROUP BY CREATE_WEEKDAY
ORDER BY (CASE CREATE_WEEKDAY
WHEN 'Monday' THEN 1
WHEN 'Tuesday' THEN 2
WHEN 'Wednesday' THEN 3
WHEN 'Thursday' THEN 4
WHEN 'Friday' THEN 5
WHEN 'Saturday' THEN 6
WHEN 'Sunday' THEN 7
ELSE 100 END)
You can just use the built-in ROUND(N,D) function, the second argument is the number of digits.
MySQL Reference: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_round
You have several options. I would not recommend round(), because this doesn't really change the underlying representation.
You can convert the value to a string, using format(), or just convert the value to a decimal/numeric. This looks like:
SELECT . . .
CAST(Count(create_weekday) * 100 /
(SELECT Count(*)
FROM call_view
WHERE (create_month = Month(Now() - INTERVAL 1 month) ) AND
(create_year = Year( Now() - INTRVAL 1 month) ) AND
customer_company_name = 'Company'
) as DECIMAL(4, 1)
) as Percentage
As Jarlh stated, cast(Percentage as decimal(4,1)) sets this to a decimal value with 4 places and 1 fraction place. The column value of Percentage will be rounded into this criteria.