Oracle SQL count days in week for every month - sql

I have these two tables (times and sales):
times
TIME_ID | DAY_NAME | DAY_NUMBER_IN_WEEK | CALENDAR_MONTH_NAME | CALENDAR_MONTH_ID
1998-01-10| Monday | 1 | January | 1684
1998-01-10| Tuesday | 2 | January | 1684
1998-01-10| Wednesday | 3 | January | 1684
...
1998-01-11| Monday | 1 | February | 1685
1998-01-11| Tuesday | 2 | January | 1685
1998-01-11| Wednesday | 3 | January | 1685
sales
PROD_ID | TIME_ID | AMOUNT_SOLD
13 | 1998-01-10 | 1232
13 | 1998-01-11 | 1233
14 | 1998-01-11 | 1233
I need to make columns for every day in week (Monday, Tuesday, Wednesday...) and SUM of AMOUNT_SOLD for each PROD_ID for each day for each month.
SELECT SUM(times.day_number_in_week), times.calendar_month_name, times.day_name, times.calendar_year
FROM sales
INNER JOIN times ON times.time_id = sales.time_id
GROUP BY times.calendar_month_number, times.calendar_month_name, times.day_name, times.calendar_year
Output:
5988 March Wednesday 1998
9408 April Thursday 1998
7532 June Sunday 1998
9220 July Thursday 1998
7490 July Sunday 1998
12540 August Saturday 1998
but this sum all Wednesdays for all years, i need sum of amount for 1 month for all days (Wednesday, Monday...) for one month.
Can you help me?

You can do conditional aggregation:
SELECT
t.calendar_year
t.calendar_month_name,
SUM(case when t.day_number_in_week = 1 then s.amount_sold else 0 end) amount_sold_mon,
SUM(case when t.day_number_in_week = 2 then s.amount_sold else 0 end) amount_sold_tue,
SUM(case when t.day_number_in_week = 3 then s.amount_sold else 0 end) amount_sold_wed,
...
FROM sales s
INNER JOIN times t ON t.time_id = sales.time_id
GROUP BY t.calendar_year, t.calendar_month_number, t.calendar_month_name

Related

How to split q1 data into months

Hi I have one doubt in sql server:
in my table have 4 querter related totalamt values is available.
here I want split q1 sum values to months (april,may,june) of current year and
q2 sum values to months (july,Aug,Sep) of current year
q3 sum values to months (Oct,Nov,Dec) of current year
q4 sum values to months (Jan,Feb,Mar) of current year if i run current months are (jan or feb or mar ) then consider year as current year else next year of current year.
table :
CREATE TABLE [dbo].[task](
[Vertical] [varchar](50) NULL,
[AccountName] [varchar](50) NULL,
[q1] [money] NULL,
[q2] [money] NULL,
[q3] [money] NULL,
[q4] [money] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[task] ([Vertical], [AccountName], [q1], [q2], [q3], [q4]) VALUES (N'BFSI', N'susse', 90.0000, 15.0000, 30.0000, 6.0000)
GO
INSERT [dbo].[task] ([Vertical], [AccountName], [q1], [q2], [q3], [q4]) VALUES (N'BFSI', N'AIG', 100.0000, 50.0000, 40.0000, 60.0000)
GO
based on the above data I want output like below :
+----------+-------------+---------+-----------+------+
| vertical | accountname | reveune | month | year |
+----------+-------------+---------+-----------+------+
| BFSI | AIG | 13.3333 | December | 2018 |
| BFSI | AIG | 13.3333 | November | 2018 |
| BFSI | AIG | 13.3333 | October | 2018 |
| BFSI | AIG | 16.6666 | August | 2018 |
| BFSI | AIG | 16.6666 | July | 2018 |
| BFSI | AIG | 16.6666 | September | 2018 |
| BFSI | AIG | 20.00 | Feburary | 2019 |
| BFSI | AIG | 20.00 | January | 2019 |
| BFSI | AIG | 20.00 | March | 2019 |
| BFSI | AIG | 33.3333 | April | 2018 |
| BFSI | AIG | 33.3333 | June | 2018 |
| BFSI | AIG | 33.3333 | May | 2018 |
| BFSI | susse | 2.00 | Feburary | 2019 |
| BFSI | susse | 2.00 | January | 2019 |
| BFSI | susse | 2.00 | March | 2019 |
| BFSI | susse | 5.00 | August | 2018 |
| BFSI | susse | 5.00 | July | 2018 |
| BFSI | susse | 5.00 | September | 2018 |
| BFSI | susse | 10.00 | December | 2018 |
| BFSI | susse | 10.00 | November | 2018 |
| BFSI | susse | 10.00 | October | 2018 |
| BFSI | susse | 30.00 | April | 2018 |
| BFSI | susse | 30.00 | June | 2018 |
| BFSI | susse | 30.00 | May | 2018 |
+----------+-------------+---------+-----------+------+
I tried like below:
select vertical ,accountname ,[q1]/3 as reveune , 'April' as month ,year(getdate())as year from task
union
select vertical ,accountname ,[q1]/3 revenue ,'May' as month, year(getdate())as year from task
union
select vertical ,accountname ,[q1]/3 as reveune , 'June' as month ,year(getdate())as year from task
union
select vertical ,accountname ,[q2]/3 revenue ,'July' as month, year(getdate())as year from task
union
select vertical ,accountname ,[q2]/3 revenue ,'August' as month, year(getdate())as year from task
union
select vertical ,accountname ,[q2]/3 revenue ,'September' as month, year(getdate())as year from task
union
select vertical ,accountname ,[q3]/3 revenue ,'October' as month, year(getdate())as year from task
union
select vertical ,accountname ,[q3]/3 revenue ,'November' as month, year(getdate())as year from task
union
select vertical ,accountname ,[q3]/3 revenue ,'December' as month, year(getdate())as year from task
union
select vertical ,accountname ,[q4]/3 revenue ,'January' as month,
case when datepart(mm,getdate())=1 then datepart(yyyy,getdate()) else datepart(yyyy,getdate())+1 end year from task
union
select vertical ,accountname ,[q4]/3 revenue ,'Feburary' as month,
case when datepart(mm,getdate())=1 then datepart(yyyy,getdate()) else datepart(yyyy,getdate())+1 end year from task
union
select vertical ,accountname ,[q4]/3 revenue ,'March' as month,
case when datepart(mm,getdate())=1 then datepart(yyyy,getdate()) else datepart(yyyy,getdate())+1 end year from task
above query is giving expected result .but its taking very long time .can you please tell me any alternative solution
to achieve this task in sql server
You can try to build the desired output with cross apply:
select Vertical, AccountName, x.v as revenue, x.m as month, x.y as year
from [dbo].[task]
cross apply (values
(q1/3, 'April' , year(getdate()))
,(q1/3, 'May' , year(getdate()))
,(q1/3, 'June' , year(getdate()))
,(q2/3, 'July' , year(getdate()))
,(q2/3, 'August' , year(getdate()))
,(q2/3, 'September', year(getdate()))
,(q3/3, 'October' , year(getdate()))
,(q3/3, 'November' , year(getdate()))
,(q3/3, 'December' , year(getdate()))
,(q4/3, 'January' , case when datepart(mm,getdate())=1 then datepart(yyyy,getdate()) else datepart(yyyy,getdate())+1 end)
,(q4/3, 'February' , case when datepart(mm,getdate())=1 then datepart(yyyy,getdate()) else datepart(yyyy,getdate())+1 end)
,(q4/3, 'March' , case when datepart(mm,getdate())=1 then datepart(yyyy,getdate()) else datepart(yyyy,getdate())+1 end)
) x(v,m,y)
Note: I'm not sure if the association between months and quarters is actually correct, but this is just an implementative detail, you should be able to quickly fix it

how to get data of this week day wise in SQL SERVER

I have data entry table(ServiceData) with users data.Columns are Userid,BillDate (type DateTime)and etc.
I need to fetch count of users weekly (current week).
Query
select BillDate,DATENAME(dw,BillDate) as day ,count(BillDate) as total
from ServiceData
group by BillDate,DATENAME(dw,BillDate)
order by BillDate desc
this only fetches the day of billdate, but i want the count of sunday entries , count of monday entries - from sunday to saturday (current weeek). Is this possible?
expected Output
ID | TOTAL | DAY
--------------------------
1 | 23 | Sun
2 | 54 | Mon
3 | 17 | Tues
4 | 56 | Thus
5 | 45 | Fri
6 | 78 | Sat

how to display a weekday(set it to zero) of datepart function when there are no occurence of the day in the table

Sat Naam
I have a table in my databse that register of sales and stores. some stores are close on sundays so there are no sales on that day
i have the following query code to get the number of sale
SELECT DATENAME(WEEKDAY, [Data_Hora_Ficheiro_fim]),[Store_id],count([sales_no])
FROM [GPOS].[dbo].[V_Period_stats_with_CAE_GC]
group by [Store_id],[Store name],DATEPART(WEEKDAY,[Data_Hora_Ficheiro_fim])DATENAME(WEEKDAY, [Data_Hora_Ficheiro_fim])
order by DATEPART(WEEKDAY, [Data_Hora_Ficheiro_fim]),DATENAME(WEEKDAY, [Data_Hora_Ficheiro_fim]),[Store_id]
of the query would be something like(store 4 close on sunday)
day Storeid num_sales
----------|--------|----------
Monday 3 90
Tuesday 3 70
Wednesday 3 20
Thursday 3 60
Friday 3 96
Saturday 3 98
Sunday 3 200
Monday 4 90
Tuesday 4 70
Wednesday 4 20
Thursday 4 60
Friday 4 96
Saturday 4 98
so what changes do i need to do to my query in order to the output also include the line
Sunday 4 0
thanks in advance
One way would be to cross join the weekdays and distinct store_id to get all combinations of the two, and left join your view.
Using a common table expression for the first part and a Table Value Constructor (Transact-SQL)
;with Weekdays as (
select
day=datename(weekday, convert(datetime,t.n))
, s.Store_id
from (values(0),(1),(2),(3),(4),(5),(6)) t(n)
cross join (
select distinct Store_id
from [gpos].[dbo].[V_Period_stats_with_cae_gc]
) s
)
select
w.day
, w.[Store_id]
, count(v.[sales_no])
from Weekdays w
left join [gpos].[dbo].[V_Period_stats_with_cae_gc] v
on w.day = datename(weekday, v.[Data_Hora_Ficheiro_fim])
and w.Store_id = v.Store_id
group by
w.day
w.Store_id
order by
w.day
, w.Store_id
rextester demo (modified for provided example data): http://rextester.com/JZLF76266
returns:
+-----------+---------+-----------+
| day | storeid | num_sales |
+-----------+---------+-----------+
| Monday | 3 | 90 |
| Tuesday | 3 | 70 |
| Wednesday | 3 | 20 |
| Thursday | 3 | 60 |
| Friday | 3 | 96 |
| Saturday | 3 | 98 |
| Sunday | 3 | 200 |
| Monday | 4 | 90 |
| Tuesday | 4 | 70 |
| Wednesday | 4 | 20 |
| Thursday | 4 | 60 |
| Friday | 4 | 96 |
| Saturday | 4 | 98 |
| Sunday | 4 | 0 |
+-----------+---------+-----------+
If you have a table where store_id is unique (e.g. dbo.Store) then that would be an alternative source for select distinct Store_id ....
Another option would be to use a calendar table restricted to the date range you are interested in cross joined with the Store_id. This would allow you to join on an actual date data type instead of the datename() function, which would could improve performance.
Number and Calendar table reference:
Generate a set or sequence without loops - 2 - Aaron Bertrand
The "Numbers" or "Tally" Table: What it is and how it replaces a loop - Jeff Moden
Creating a Date Table/Dimension in sql Server 2008 - David Stein
Calendar Tables - Why You Need One - David Stein
Creating a date dimension or calendar table in sql Server - Aaron Bertrand

Reorganize Postgrest Query

Im using a query on postgresql that return a result like this.
schedule | day | subject | grade |
===============================================
06 - 08 | Monday | Biology | Second |
-----------------------------------------------
08 - 10 | Monday | Chemistry | Third |
-----------------------------------------------
06 - 08 | Tuesday | Math | Second |
-----------------------------------------------
10 - 12 | Wednesday | English | Second |
-----------------------------------------------
10 - 12 | Friday | Language | Second |
-----------------------------------------------
I need a result or reorganize this query like this.
schedule | Monday | Tuesday| Wednesday | Friday | grade
==============================================================
06 - 08 | Biology | Math | null | null | second
--------------------------------------------------------------
10 - 12 | null | null | English |Language | second
--------------------------------------------------------------
I appreciate any help or suggestion.
Thnks.
One method is conditional aggregation:
select schedule,
max(case when day = 'Monday' then subject end) as Monday,
max(case when day = 'Tuesday' then subject end) as Tuesday,
max(case when day = 'Wednesday' then subject end) as Wednesday,
max(case when day = 'Friday' then subject end) as Friday,
min(grade) as grade,
from t
group by schedule;
I'm not really sure where the grade comes from; the above is just a guess.

weekly aggregate with CTE not behaving as expected

I have this USERS table with users that can be of two different types (A and B). I need to show a report with the aggregate per type for each week. The query I have so far works well except some weeks are not grouping properly. In the example below, the week starting Jan 28th should have one line, not two.
Week Starts |Week| Type A | Type B
------------+----+--------+------
2013-02-04 | 14 | 2 | 26
2013-01-28 | 13 | 5 | 191
2013-01-28 | 13 | 0 | 24
2013-01-21 | 12 | 1 | 134
2013-01-21 | 12 | 0 | 20
2013-01-14 | 11 | 1 | 143
2013-01-14 | 11 | 0 | 2
2013-01-07 | 10 | 0 | 233
2013-01-07 | 10 | 0 | 23
2012-12-31 | 9 | 0 | 12
2012-12-31 | 9 | 4 | 164
2012-12-31 | 9 | 0 | 20
SQL
;with cte as
(
select DATEADD(m,-3,GETDATE()) firstday, DATEADD(m,-3,GETDATE()) + 6 - DATEDIFF(day, 0, DATEADD(m,-3,GETDATE())) %7 lastday, 1 week
union all
select lastday + 1, case when GETDATE() < lastday + 7 then GETDATE() else lastday + 7 end, week + 1
from cte
where lastday < GETDATE()
)
SELECT
cast(firstday as date) 'Week Starts',
cte.week as 'Week',
Sum(CASE WHEN USR_TYPE = 'A' THEN 1 ELSE 0 END) As 'Type A',
Sum(CASE WHEN USR_TYPE = 'B' THEN 1 ELSE 0 END) As 'Type B'
FROM cte left join USERS
ON cte.firstday <= USERS.CREATED
AND cte.lastday > USERS.CREATED
GROUP BY cte.week, cte.firstday, cte.lastday, DATEPART(YEAR,USERS.CREATED), DATEPART(wk,USERS.CREATED)
ORDER BY week desc
What am I doing wrong?
Without seeing any data from your users table I am going to take a guess.
The list of dates you are generating in the CTE includes the time.
You might need to cast() your firstday and lastday values as either a date or generate the list with no time.
See a SQL Fiddle Demo
Sample from your CTE and the new dates cast:
| CASTFIRSTDAY | CASTLASTDAY | WEEK | FIRSTDAY | LASTDAY |
---------------------------------------------------------------------------------------------------------
| 2012-11-05 | 2012-11-11 | 1 | November, 05 2012 20:08:10+0000 | November, 11 2012 20:08:10+0000 |
| 2012-11-12 | 2012-11-18 | 2 | November, 12 2012 20:08:10+0000 | November, 18 2012 20:08:10+0000 |
| 2012-11-19 | 2012-11-25 | 3 | November, 19 2012 20:08:10+0000 | November, 25 2012 20:08:10+0000 |
| 2012-11-26 | 2012-12-02 | 4 | November, 26 2012 20:08:10+0000 | December, 02 2012 20:08:10+0000 |
| 2012-12-03 | 2012-12-09 | 5 | December, 03 2012 20:08:10+0000 | December, 09 2012 20:08:10+0000 |
| 2012-12-10 | 2012-12-16 | 6 | December, 10 2012 20:08:10+0000 | December, 16 2012 20:08:10+0000 |
You might want to edit your CTE to return the date only values:
;with cte as
(
select
cast(DATEADD(m,-3,GETDATE()) as date) firstday,
cast(DATEADD(m,-3,GETDATE()) + 6 - DATEDIFF(day, 0, DATEADD(m,-3,GETDATE())) %7 as DATE) lastday,
1 week
union all
select
cast(DATEADD(DAY, 1, lastday) as date),
case
when cast(GETDATE() as date) < cast(DATEADD(DAY, 7, lastday) as date)
then cast(GETDATE() as date)
else cast(DATEADD(DAY, 7, lastday) as date)
end,
week + 1
from cte
where cast(lastday as date) < cast(GETDATE() as date)
)
select *
from cte
See SQL Fiddle with Demo