Show formula result applying on more than one column - sql

I am on Microsoft SQL Server 2017.
I am having these results on SQL Server applying a simple SELECT sentence:
SELECT Result, Year, Month FROM Table;
Result Year Month
DELAY 2019 5
DELAY 2019 1
PUNCTUAL 2020 2
PUNCTUAL 2020 2
PUNCTUAL 2020 3
PUNCTUAL 2020 3
PUNCTUAL 2020 3
PUNCTUAL 2020 3
DELAY 2020 3
PUNCTUAL 2020 3
I need to get the percentage of PUNCTUAL results, separated by month and year columns. The formula would be the sum of total results separated by month and year, divided by the PUNCTUAL results multiplied * 100.
For instance, on March 2020 would be: 5 punctual / 6 results * 100 = 83.3% punctual results; the other rest are delays, which I am not interested in.
I tried with COUNT CASE WHEN but I couldn't get it to work properly.
For instance, the result I need to get would be like:
Year Month Success
2019 1 0%
2019 5 0%
2020 2 100%
2020 3 83.3%
Thanks for your help.

I like using AVG() for this:
select year, month,
avg(case when result = 'PUNCTUAL' then 1.0 else 0 end) as punctual_rate
from t
group by year, month
order by year, month;
If you want a number between 0 and 100, just use 100.0 rather than 1.0.

You may use the following statement to calculate the percentage using COUNT() and CASE:
SELECT
Year,
Month,
COUNT(CASE WHEN Result = 'PUNCTUAL' THEN 1 END) * 100.0 / COUNT(*) As Success
FROM (VALUES
('DELAY', 2019, 5),
('DELAY', 2019, 1),
('PUNCTUAL', 2020, 2),
('PUNCTUAL', 2020, 2),
('PUNCTUAL', 2020, 3),
('PUNCTUAL', 2020, 3),
('PUNCTUAL', 2020, 3),
('PUNCTUAL', 2020, 3),
('DELAY', 2020, 3),
('PUNCTUAL', 2020, 3)
) v (Result, Year, Month)
GROUP BY Year, Month
ORDER BY Year, Month
Result:
Year Month Success
2019 1 0.000000000000
2019 5 0.000000000000
2020 2 100.000000000000
2020 3 83.333333333333
If you need to get the percentage as text, you may use CONCAT():
CONCAT(
CONVERT(numeric(10, 2), COUNT(CASE WHEN Result = 'PUNCTUAL' THEN 1 END) * 100.0 / COUNT(*)),
'%') AS SuccessFormatted

You can use the aggregation with the FORMAT command to get your desired result:
CREATE TABLE #T1(Result varchar(10),Year int, Month int)
INSERT INTO #T1 VALUES('DELAY', 2019, 5),
('DELAY',2019,1),
('PUNCTUAL',2020,2),
('PUNCTUAL',2020,2),
('PUNCTUAL',2020,3),
('PUNCTUAL',2020,3),
('PUNCTUAL',2020,3),
('PUNCTUAL',2020,3),
('DELAY',2020,3),
('PUNCTUAL',2020,3)
SELECT [Year], [Month], FORMAT( (((PuncCnt * 1.0) / Total)) ,'P2') Success
FROM
(
SELECT [Year],[Month], SUM(CASE WHEN Result = 'PUNCTUAL' THEN 1 ELSE 0 END) PuncCnt, COUNT(*) Total
FROM #t1
GROUP BY [Year],[Month]
) T2
ORDER BY [Year],[Month]
RESULT:
Year Month Success
2019 1 0.00%
2019 5 0.00%
2020 2 100.00%
2020 3 83.33%

Related

Sum of last 12 months

I have a table with 3 columns (Year, Month, Value) like this in Sql Server :
Year
Month
Value
ValueOfLastTwelveMonths
2021
1
30
30
2021
2
24
54 (30 + 24)
2021
5
26
80 (54+26)
2021
11
12
92 (80+12)
2022
1
25
87 (SUM of values from 1 2022 TO 2 2021)
2022
2
40
103 (SUM of values from 2 2022 TO 3 2021)
2022
4
20
123 (SUM of values from 4 2022 TO 5 2021)
I need a SQL request to calculate ValueOfLastTwelveMonths.
SELECT Year,
       Month,
Value,
SUM (Value) OVER (PARTITION BY Year, Month)
FROM MyTable
This is much easier if you have a row for each month and year, and then (if needed) you can filter the NULL rows out. The reason it's easier is because then you know how many rows you need to look back at: 11.
If you make a dataset of the years and months, you can then LEFT JOIN to your data, aggregate, and then finally filter the data out:
SELECT *
INTO dbo.YourTable
FROM (VALUES(2021,1,30),
(2021,2,24),
(2021,5,26),
(2021,11,12),
(2022,1,25),
(2022,2,40),
(2022,4,20))V(Year,Month,Value);
GO
WITH YearMonth AS(
SELECT YT.Year,
V.Month
FROM (SELECT DISTINCT Year
FROM dbo.YourTable) YT
CROSS APPLY (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12))V(Month)),
RunningTotal AS(
SELECT YM.Year,
YM.Month,
YT.Value,
SUM(YT.Value) OVER (ORDER BY YM.Year, YM.Month
ROWS BETWEEN 11 PRECEDING AND CURRENT ROW) AS Last12Months
FROM YearMonth YM
LEFT JOIN dbo.YourTable YT ON YM.Year = YT.Year
AND YM.Month = YT.Month)
SELECT Year,
Month,
Value,
Last12Months
FROM RunningTotal
WHERE Value IS NOT NULL;
GO
DROP TABLE dbo.YourTable;

How to compare two date values in SQL Server?

I have a table with the date 2018 and date 2019 and here is my data.
select amount, date
from TABLE1
where date in (2018, 2019) and empid = 21120
It didn't work for me as the query says case when date =2019 then amount as my data above when date=2019 it will just show me the amount. This is what my result is:
Amount Data
9.67 2019
21 2019
6 2019
9.56 2018
42 2018
7 2018
What is want it: the difference between the Amount for the two dates 2018 and 2019.
The above query gives me only one row of the amount for those dates.
My expected result is to find the difference in the amount between 2018 and 2019. Any ideas on how I could get the difference. I am trying self joining but any help is appreciated.
Ex: 2019 amount 9.67 - 2018 amount 9.56.
You seem to be looking for conditional aggregation:
select
sum(case when date = 2019 then amount else 0 end)
- sum(case when date = 2018 then amount else 0 end) diff
from mytable
where empid = 21 and date in (2018, 2019)
The query gives you the difference between the total amount of 2019 and that of 2018 for the given employee.
This can be shortened a little:
select sum(case when date = 2019 then amount else -amount end) diff
from mytable
where empid = 21 and date in (2018, 2019)
You can do as
SELECT ABS(SUM(CASE WHEN Data = '2019' THEN Amount ELSE -Amount END)) Diff
FROM
(
VALUES
(9.67 , '2019'),
(21 , '2019'),
(6 , '2019'),
(9.56 , '2018'),
(42 , '2018'),
(7 , '2018')
) T(Amount, Data)
WHERE Data IN ('2018', '2019')
-- AND empid = 21120; Uncomment this when you run it against your table

How to Get Monthly/Quarterly Sales Percent

I Have a table of Monthly Sales
Quarter Month Monthly Sales
1 Jan 586
1 Feb 204
1 Mar 465
2 Apr 684
2 May 756
2 Jun 97
Now I want a result a below
Quarter Month Monthly Sales Total Sales% Quarterly Sales%
1 Jan 586 20.98% 45.25%
1 Feb 204 7.30% 16.25%
1 Mar 465 16.65% 37.05%
2 Apr 684 24.49% 44.50%
2 May 756 27.07% 49.18%
2 Jun 97 3.47 6.31%
Total Sales% = Monthly Sales/Sum (Monthly Sales)
Quarterly Sales% = Monthly Sales/ Quarterly Sales
How Do i Get this output in SQL?
Using CROSS APPLY:
SELECT
s.*,
[Total Sales %] = CAST(CAST(s.MonthlySales/t.Total * 100.00 AS DECIMAL(5, 2)) AS VARCHAR(5)) +'%',
[Quarterly Sales %] = CAST(CAST(s.MonthlySales/q.QtrTotal* 100.00 AS DECIMAL(5, 2)) AS VARCHAR(5)) +'%'
FROM Sales s
CROSS APPLY(
SELECT Total = SUM(MonthlySales) * 1.0
FROM Sales
) t
CROSS APPLY(
SELECT QtrTotal = SUM(MonthlySales) * 1.0
FROM Sales
WHERE Quarter = s.Quarter
GROUP BY Quarter
)q
If you are using Oracle you should be using the ratio_to_report analytic function. (http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions124.htm)
select quarter,
month,
monthly_sales,
round(ratio_to_report(monthly_sales) over() * 100, 2) as total_sales_pct,
round(ratio_to_report(monthly_sales) over(partition by quarter) * 100, 2) as qtr_sales_pct
from monthly_sales;
Fiddle: http://sqlfiddle.com/#!4/71aeb7/1/0
The above assumes you're selecting data for just one year as the analytic function will interpret the given result set. If your query spans multiple years you need to additionally partition by whatever column represents the year in your real table.

How to get calculate percentage increase or decrease in single sql query?

I have a table with following structure
Event Id | Year
-------------------
1xxxxx | 2014
2xxxxx | 2014
3xxxxx | 2014
4xxxxx | 2014
5xxxxx | 2014
6xxxxx | 2015
7xxxxx | 2015
8xxxxx | 2015
I need to find the percentage increase of number of events happened in 2015 compared to 2014. I need to find it using a single SQL query. How can I achieve this?
For example if we take the number of events happened in 2014 it is equal to 5 and the same is 3 in 2015. So the percentage increase of events in 2015 compared to 2014 is ((3-5)*100)/5 = -40.0 %.
Here is generic statement which is not limited to only 2014 and 2015:
CREATE TABLE test (id INT, year int);
Insert into test values
(1, 2014),
(2, 2014),
(3, 2014),
(4, 2014),
(5, 2014),
(6, 2015),
(7, 2015),
(8, 2015),
(9, 2016)
;with cte as(
select year y, count(*) c from test
group by year)
select c1.y,
ca.y,
(c1.c - ca.c)*100.0/ca.c inc,
(ca.c - c1.c)*100.0/c1.c dec
from cte c1
cross apply(select top 1 * from cte c2 where c2.y < c1.y order by c2.y desc)ca
Output:
y y inc dec
2015 2014 -40 66.666666666666
2016 2015 -66.666666666666 200
Fiddle http://sqlfiddle.com/#!6/9e1cf/3
if I understand correctly, you can do this with conditional aggregation:
select sum(case when year = 2014 then 1 else 0 end) as ev_2014,
sum(case when year = 2015 then 1 else 0 end) as ev_2015,
(sum(case when year = 2015 then 100.0 else 0 end)
sum(case when year = 2014 then 1.0 end)
) - 100.0 as percent_change
from table t;

Calculate substraction by a specific quarter of year

I have some records after SQL generating:
YEARS MONTHS SUMMONTH SUMQUARTER QTR
----- ------ -------- ---------- ---
2009 Jan 363639 855922 1
2009 Feb 128305 855922 1
2009 Mar 363978 855922 1
2009 Apr 376633 1058871 2
2009 May 299140 1058871 2
2009 Jun 383098 1058871 2
2009 Jul 435000 1063577 3
2009 Aug 266227 1063577 3
2009 Sep 362350 1063577 3
2009 Oct 449366 1017906 4
2009 Nov 280943 1017906 4
2009 Dec 287597 1017906 4
2010 Jan 418277 661083 1
2010 Feb 129895 661083 1
2010 Mar 112911 661083 1
2010 Apr 163593 685625 2
2010 May 228505 685625 2
2010 Jun 293527 685625 2
2010 Jul 451608 1044364 3
2010 Aug 356683 1044364 3
2010 Sep 236073 1044364 3
2010 Oct 247365 798925 4
2010 Nov 414100 798925 4
2010 Dec 137460 798925 4
24 rows selected
The SUMQUARTER column sum up each quarter of a year...
The qtr specify it belongs to which quarter.
The problem is how to have a subtraction of sumquarter between 2 different years to get the specific query result?
The difference is not the: max value-min value.
It is the user-defined value that he want to input...
Let say...
For example, the user want to see the substraction(sumquarter) between 2009 qtr=2 and 2010 qtr=2,
user may change the parameter(years,qtr) of sql to view the record.
This mean the result should be: (1058871 - 685625)
Here is the SQL that I am currently using:
select years,months,summonth,sumquarter,qtr
from(
select years,months,summonth,sumhour,hours,to_char(ym, 'Q') qtr,
sum(sumhour) over(partition by years || to_char(ym, 'Q') order by years || to_char(ym, 'Q')) sumquarter,ym,
count(days) over(partition by years,months,hours) days_month
from(
select years, months, days, hours, mins, sumHour,
SUM (sumHour) OVER (PARTITION BY years,months,days) sumDay,
SUM (sumHour) OVER (PARTITION BY years,months) sumMonth,
SUM (sumHour) OVER (PARTITION BY years) sumyear,
to_date(years || months, 'YYYYMon', 'NLS_DATE_LANGUAGE=American') ym
from (
SELECT x.years, x.months, x.days, x.hours, x.mins, sum(x.value) as sumHour
FROM xmltest,
XMLTABLE ('$d/cdata/name' passing doc as "d"
COLUMNS
years integer path 'year',
months varchar(3) path 'month',
days varchar(2) path 'day',
hours varchar(2) path 'hour',
mins varchar(2) path 'minute',
value float path 'value'
) as X
group by x.years, x.months, x.days, x.hours, x.mins
order by x.years, x.months, x.days
)
)
)
group by years,months,summonth,sumquarter,qtr,ym
order by ym
The sql pattern maybe something like this:...??
select ((select sumquarter from table where years=2009 and qtr=2) - (select sumquarter from table where years=2010 and qtr=2)) from table
Actually, it doesn't work...
The result maybe look in this view:
SUBTRACT
----------
373246
Thanks everyone helps!!:)
I'd use the following:
select
((select sumquarter from table where years=2009 and qtr=2 and rownum=1) -
(select sumquarter from table where years=2010 and qtr=2 and rownum=1)) as substract
from dual
try this query:
select (case when years=2009 and qtr=2 then sumquater end) - (case when years=2010 and qtr=2 then sumquater end) from table