Case statement bucketing in Sybase Sql - sql

I have a data set which looks like this:
month year total_sales
01 2014 4567889
02 2014 5635627
03 2014 997673
04 2014 2134566
05 2014 2666477
My goal is to create a YTD function on the above dataset.
Eg: If I want the 01 month data to display, it should give the total sales for 01 month. If i want the 02 month to display, it should give me the total sales for 01 + 02 month combined and so on for the other months.
The query i wrote goes as follows:
select year, case when month in ('01') then 'JAN'
when month in ('01','02') then 'FEB'
-
-
-
when month in ('01','02','03','04','05') then 'MAY'
end as bucket, sum(total_sales) from <table_name>
group by year, case when month in ('01') then 'JAN'
when month in ('01','02') then 'FEB'
-
-
-
when month in ('01','02','03','04','05') then 'MAY'
end
The result set it fetches, doesn't add up the total sales as a YTD function but instead shows the total sales for that particular month only.
I can create the Pivot table view for the required data set but that is not how i need it because i need to build reports on the data set.
Can someone help me with the concept if i am missing something?
Thanks in advance.

Perhaps a correlated subquery would help:
select t.*,
(select sum(total_sales)
from table t2
where t2.year = t.year and
t2.month <= t.month
) as YTD
from table t;

Here is another solution:
WITH months AS (
SELECT month, year
FROM <table_name>
)
SELECT m.month, m.year, SUM(t.total_sales)
FROM months m JOIN <table_name> t ON t.year=m.year AND t.month<=m.month
GROUP BY m.year, m.month
ORDER BY m.year, m.month;

Related

Count number of members each month

I have a table like so
--Member--
ID char(10),
Name (nvarchar(50),
joiningDay date,
exitDay date
How can I count total number of member each month with a selected period of time with member that has exit will not be counted in that month
and the result should be like:
Start from month 1 to month 10
Month totalOfMember
1 5
2 6
3 9
... ...
10 35
If you want to select number of members joined in a month
select month(joiningday)[Month],sum(case when month(joiningday)=month(exitday) then 0 else 1 end)TotalOfMember
from Member where joiningDay>='1 jan 2020' and joiningDay<'1 jan 2021'
group by month(joiningday)
order by [Month]
But I would suggest to use Format(datevalue,'yyyy MM') to count member month and year wise instead of only month. 01 can be repeated in a date range if there are two January but 2020 01 and 2021 01 will be uniquely identified.
select Format(joiningday,'yyyy MM') [Month],sum(case when Format(joiningday,'yyyy MM') = Format(exitday,'yyyy MM') then 0 else 1 end)TotalOfMember
from Member where joiningDay>='1 jan 2020' and joiningDay<'1 jan 2021'
group by Format(joiningday,'yyyy MM')
order by [Month]
Or if you want to have month wise cumulative count for members :
select Format(joiningday,'yyyy MM') [Month],sum(case when Format(joiningday,'yyyy MM') = Format(exitday,'yyyy MM') then 0 else 1 end)over(order by Format(joiningday,'yyyy MM')) TotalOfMember
from Member where joiningDay>='1 jan 2020' and joiningDay<'1 jan 2021'
group by Format(joiningday,'yyyy MM')
order by [Month]
Join the table to itself to eliminate same-month exiters:
select
year(a.joinjngday) Year,
month(a.joiningday) Month,
count(*) total
from Member a
join Member b on a.ID = b.ID
and month(b.exitday) = month(a.joinjngday)
and year(b.exitday) = year(a.joiningday)
where b.ID is null -- exclude same month exits
group by month(a.joiningday)
order by year(a.joinjngday), month(a.joiningday)
The most efficient way to do this is to use a cumulative sum. Basically, you want a + count and - count for each month based on the number of members who join and leave. I would approach this as:
with changes as (
select dateformparts(year(dte), month(dte), 1) as yyyymm,
sum(inc) as month_changes
from members m cross apply
(values (joiningday, 1),
(exitday, -1)
) v(dte, inc)
)
select yyyymm, sum(month_changes)
from changes
group by yyyymm
order by yyyymm;
If you want this for a particular period of time, then filter the above. Also, this will not contain months that have no changes.
If you wanted this for just a handful of months -- even those with no changes -- then you might find that explicit counting is simpler:
select d.dte,
(select count(*)
from members m
where m.joiningday <= eomonth(d.dte) and
m.exitday > eomonth(d.dte)
) as members_in_month
from (values (convert(date, '2021-01-01')),
(convert(date, '2021-02-01')),
(convert(date, '2021-03-01'))
) d(dte);

SQL Server : aggregating multiple measures columns into 1 column

I'm a SQL novice and tried my best to search for this topic before asking.
I have data in this format:
I need in this format:
I realize this is something probably very easy, but any help would be greatly appreciated.
Thanks!
You can use APPLY if you are working with SQL Server :
SELECT t.year, tt.Months, tt.Amount
FROM TABLE t CROSS APPLY
( VALUES (1, 'January', [Month1]),
(2, 'February', [Month2]),
. . .
) tt(seq, Months, Amount)
ORDER BY tt.seq, t.year;
You can try this on SQL SERVER:
CREATE TABLE TestPvt (Year varchar(32), January int, february int,
March int);
GO
INSERT INTO TestPvt VALUES ('Actual 2019',700,220,456);
INSERT INTO TestPvt VALUES ('Budget 2019',200,752,500);
SELECT Year, Month, Amount
FROM
(SELECT Year, January, february, March
FROM TestPvt) p
UNPIVOT
(Amount FOR Month IN
(January, february, March)
)AS unpvt;
The result is:
Year Month Amount
Actual 2019 January 700
Actual 2019 february 220
Actual 2019 March 456
Budget 2019 January 200
Budget 2019 february 752
Budget 2019 March 500
You could try:
Taking the columns you provide i made this SQL, i hope this helps!
Just change the table for the original
SELECT Year,
case when Month = 'Month1' then 'January'
when Month = 'Month2' then 'February'
when Month = 'Month3' then 'March'
else '' end as Month,
Amount
FROM
(SELECT Year, Month1, Month2, Month3
FROM [dbo].[ExampleMonths]) tb1
UNPIVOT
(Amount for Month IN
(tb1.Month1, tb1.Month2, tb1.Month3)
) AS uNp

SQL: Outputting month names in correct order

I am using the query composer on Google BigQuery.
I want to output the months in the correct order, e.g. starting with January, ending with December.
Here is my query:
SELECT month, gender, SUM(cost) AS Cost
FROM [medicare.medicareTable]
GROUP BY month, gender
ORDER BY month, gender
Without the ORDER BY above, the months were in a completely random order. Now they are alphabetised, which is a little better but still not what I want.
Using the above query, the output looks like this: https://docs.google.com/spreadsheets/d/18r_HhY1jG3Edkj5Nk8gDM_eSQ_1fI6ePHSZuJuoAppE/edit?usp=sharing
Thanks to anyone who can help.
for BigQuery Standard SQL you can use PARSE_DATE(). You can see Supported Format Elements for DATE
WITH m AS (
SELECT 'January 01 2016' AS d UNION ALL
SELECT 'February 01 2016' AS d UNION ALL
SELECT 'March 01 2016' AS d
)
SELECT d, EXTRACT(month FROM PARSE_DATE('%B %d %Y', d)) AS month_number
FROM m
ORDER BY month_number
You can try to get month number from month name and sort is ascending order.
Syntax for SQL Server
select DATEPART(MM,'january 01 2016') -- returns 1
So you can try something like this
SELECT month, gender, SUM(cost) AS Cost
FROM [medicare.medicareTable]
GROUP BY month, gender
ORDER BY datepart(MM,month + ' 01 2016'),gender
Hope this helps

How to divide between rows in one table in Postgres

I am working in Postgres with a table like this:
mon yyyy weather
Apr 2014 78.45
Apr 2015 77.32
May 2014 79.56
May 2015 78.43
I would like to be able to query some results, ordered by "mon", where the weather column values are divided according to year-on-year by month.
In other words I want to query weather where Apr 2015 is divided by Apr 2014.
However, I would like to write the query in such a way that I do not have to specify month or year, and the query automatically divides weather values according to: Apr 2015/Apr 2014, then May 2014/May 2014 without having to key in every month and every year, which is laborious.
I have the following code, but this expands columns which is not what I want:
select (select "Weather" from yoy
where mon = 'Apr' and yyyy = '2015'
)/(select "American" from yoy
where mon = 'Apr' and yyyy = '2014'
) as "weather_apr",
(select "Weather" from yoy
where mon = 'May' and yyyy = '2015'
)/(select "Weather" from yoy
where mon = 'May' and yyyy = '2014'
) as "weather_may",
from yoy;
In my opinion this is the right scenario to take advantage of analytical window function. Here the magic without joins:
SELECT yyyy,
weather,
mon,
lead( weather ) over (partition by mon order by mon, yyyy desc),
weather / lead( weather ) over (partition by mon order by mon, yyyy desc)
FROM joy
I think you need a self join like in the below example:
SELECT j1."yyyy" As year,
j2."yyyy" As next_year,
j1."mon",
j1."weather",
j2."weather" As "weather from next year",
j1."weather"::float / j2."weather" As divide
FROM joy j1
JOIN joy j2
ON j1."yyyy" = j2."yyyy" - 1 AND j1."mon" = j2."mon"
demo: http://sqlfiddle.com/#!15/e02ec/1
I find conditional aggregation can be quite useful for this type of query:
select mon,
max(case when yyyy = 2014 then weather end) as weather_2014,
max(case when yyyy = 2015 then weather end) as weather_2015,
(max(case when yyyy = 2015 then weather end) /
max(case when yyyy = 2014 then weather end)
) as ratio
from yoy
group by mon
This assumes that you want the rows reduced to one per month. To get the previous value, just use lag():
select yoy.*,
lag(weather) over (partition by month order by year) as prev_weather
from yoy;

TSQL Running Totals aggregate from sum of previous rows

Not sure how to word this. Say i have a select returing this.
Name, month, amount
John, June, 5
John, July,6
John, July, 3
John August, 10
and I want to aggregate and report beggining blance for each month.
name, month, beggining balance.
john, may, 0
john, june, 0
john, july, 5
john, august, 14
john, September, 24
I can do this in excel with cell formulas, but how can I do it in SQL without storing values somewhere? I have another table with fiscal months i can do a left outer join with so all months are reported, just not sure how to aggregate from prior months in sql.
select
name
, month
, (select sum(balance) from mytable
where mytable.month < m.month and mytable.name = m.name) as starting_balance
from mytable m
group by name, month
This is not as nice as windowing functions, but since they vary from database to database, you'd need to tell us which system you are using.
And it's an inline subquery, which is not very performant. But at least it's easy to understand what's going on !
Use Grouping like this
SELECT NAME, MONTH , SUM(Balance) FROM table GROUP BY NAME, MONTH
Assuming your months are represented as dates, this will give you the running total.
select t1.name, t1.month, sum(t2.amount)
from yourtable t1
left join yourtable t2
on t1.name = t2.name
and t1.month>t2.month
group by t1.name, t1.month