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

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

Related

How to get last value for each user_id (postgreSQL)

Current ratio of user is his last inserted ratio in table "Ratio History"
user_id | year | month | ratio
For example if user with ID 1 has two rows
1 | 2019 | 2 | 10
1 | 2019 | 3 | 15
his ratio is 15.
there is some slice from develop table
user_id | year | month | ratio
1 | 2018 | 7 | 10
2 | 2018 | 8 | 20
3 | 2018 | 8 | 30
1 | 2019 | 1 | 40
2 | 2019 | 2 | 50
3 | 2018 | 10 | 60
2 | 2019 | 3 | 70
I need a query which will select grouped rows by user_id and their last ratio.
As a result of the request, the following entries should be selected
user_id | year | month | ratio
1 | 2019 | 1 | 40
2 | 2019 | 3 | 70
3 | 2018 | 10 | 60
I tried use this query
select rh1.user_id, ratio, rh1.year, rh1.month from ratio_history rh1
join (
select user_id, max(year) as maxYear, max(month) as maxMonth
from ratio_history group by user_id
) rh2 on rh1.user_id = rh2.user_id and rh1.year = rh2.maxYear and rh1.month = rh2.maxMonth
but i got only one row
Use distinct on:
select distinct on (user_id) rh.*
from ratio_history rh
order by user_id, year desc, month desc;
distinct on is a very convenient Postgres extension. It returns one row for the key values in parentheses? Which row, it is the first row based on the sort criteria. Note that the sort criteria need to start with the expressions in parentheses.

Querying all past and future round birthdays

I got the birthdates of users in a table and want to display a list of round birthdays for the next n years (starting from an arbitrary date x) which looks like this:
+----------------------------------------------------------------------------------------+
| Name | id | birthdate | current_age | birthday | year | month | day | age_at_date |
+----------------------------------------------------------------------------------------+
| User 1 | 1 | 1958-01-23 | 59 | 2013-01-23 | 2013 | 1 | 23 | 55 |
| User 2 | 2 | 1988-01-29 | 29 | 2013-01-29 | 2013 | 1 | 29 | 25 |
| User 3 | 3 | 1963-02-12 | 54 | 2013-02-12 | 2013 | 2 | 12 | 50 |
| User 1 | 1 | 1958-01-23 | 59 | 2018-01-23 | 2018 | 1 | 23 | 60 |
| User 2 | 2 | 1988-01-29 | 29 | 2018-01-29 | 2018 | 1 | 29 | 30 |
| User 3 | 3 | 1963-02-12 | 54 | 2018-02-12 | 2018 | 2 | 12 | 55 |
| User 1 | 1 | 1958-01-23 | 59 | 2023-01-23 | 2023 | 1 | 23 | 65 |
| User 2 | 2 | 1988-01-29 | 29 | 2023-01-29 | 2023 | 1 | 29 | 35 |
| User 3 | 3 | 1963-02-12 | 54 | 2023-02-12 | 2023 | 2 | 12 | 60 |
+----------------------------------------------------------------------------------------+
As you can see, I want to be "wrap around" and not only show the next upcoming round birthday, which is easy, but also historical and far future data.
The core idea of my current approach is the following: I generate via generate_series all dates from 1900 till 2100 and join them by matching day and month of the birthdate with the user. Based on that, I calculate the age at that date to select finally only that birthdays, which are round (divideable by 5) and yield to a nonnegative age.
WITH
test_users(id, name, birthdate) AS (
VALUES
(1, 'User 1', '23-01-1958' :: DATE),
(2, 'User 2', '29-01-1988'),
(3, 'User 3', '12-02-1963')
),
dates AS (
SELECT
s AS date,
date_part('year', s) AS year,
date_part('month', s) AS month,
date_part('day', s) AS day
FROM generate_series('01-01-1900' :: TIMESTAMP, '01-01-2100' :: TIMESTAMP, '1 days' :: INTERVAL) AS s
),
birthday_data AS (
SELECT
id AS member_id,
test_users.birthdate AS birthdate,
(date_part('year', age((test_users.birthdate)))) :: INT AS current_age,
date :: DATE AS birthday,
date_part('year', date) AS year,
date_part('month', date) AS month,
date_part('day', date) AS day,
ROUND(extract(EPOCH FROM (dates.date - birthdate)) / (60 * 60 * 24 * 365)) :: INT AS age_at_date
FROM test_users, dates
WHERE
dates.day = date_part('day', birthdate) AND
dates.month = date_part('month', birthdate) AND
dates.year >= date_part('year', birthdate)
)
SELECT
test_users.name,
bd.*
FROM test_users
LEFT JOIN birthday_data bd ON bd.member_id = test_users.id
WHERE
bd.age_at_date % 5 = 0 AND
bd.birthday BETWEEN NOW() - INTERVAL '5' YEAR AND NOW() + INTERVAL '10' YEAR
ORDER BY bd.birthday;
My current approach seems to be very inefficient and rather complicated: It takes >100ms. Does anybody have an idea for a more compact and performant query? I am using Postgresql 9.5.3. Thank you!
Maybe try to join the generate series:
create table bday(id serial, name text, dob date);
insert into bday (name, dob) values ('a', '08-21-1972'::date);
insert into bday (name, dob) values ('b', '03-20-1974'::date);
select * from bday ,
lateral( select generate_series( (1950-y)/5 , (2010-y)/5)*5 + y as year
from (select date_part('year',dob)::integer as y) as t2
) as t1;
This will for each entry generate years between 1950 and 2010.
You can add a where clause to exclude people born after 2010 (they cant have a birthday in range)
Or exclude people born before 1850 (they are unlikely...)
--
Edit (after your edit):
So your generate_series creates 360+ rows per annum. In 100 years that is over 30.000. And they get joined to each user. (3 users => 100.000 rows)
My query generates only rows for years needed. In 100 years that is 20 rows.
That means 20 rows per user.
By dividing by 5, it ensures that the start date is a round birthday.
(1950-y)/5) calculates how many round birthdays there were before 1950.
A person born in 1941 needs to skip 1941 and 1946, but has a round birthday in 1951. So that is the difference (9 years) divided by 5, and then actually plus 1 to account for the 0st.
If the person is born after 1950 the number is negative, and greatest(-1,...)+1 gives 0, starting at the actual birthday year.
But actually it should be
select * from bday ,
lateral( select generate_series( greatest(-1,(1950-y)/5)+1, (2010-y)/5)*5 + y as year
from (select date_part('year',dob)::integer as y) as t2
) as t1;
(you may be doing greatest(0,...)+1 if you want to start at age 5)

get data for first 3 months that have claims

I have a table of members and their claims value, I'm interested in getting the claims values for the first 3 months for each member. Here's what I've tried so far:
WITH START as
(SELECT [HEALTH_ID]
,MIN([CLM_MONTH]) as DOS
FROM [TEST]
GROUP BY
[HEALTH_PLAN_ID])
SELECT HEALTH_ID
,DOS
,FORMAT(DATEADD(month, +1, DOS), 'MM/dd/yyyy')
,FORMAT(DATEADD(month, +2, DOS), 'MM/dd/yyyy')
FROM START
My plan is to get the dates of the first 3 months with claims then join the claim amounts to ID and dates. The problem here is not every member has claims in consecutive months and the dateadd function gives me consecutive months. For example if a member has claims in jan, feb, april, may etc...I'm interested in the claims for jan, feb and april since there were no claims in march. Using the dateadd function would give me dates jan, feb, march excluding april.
In summary, I need help getting the first 3 months that have claims values(months may or may not be consecutive).
Using dense_rank() to rank the months, partitioned by Health_Id, in order to filter for the first three months of each Health_Id.
;with cte as (
select *
, dr = dense_rank() over (
partition by Health_ID
order by dateadd(month, datediff(month, 0, CLM_Month) , 0) /* truncate to month */
)
from test
)
select *
from cte
where dr < 4 -- dense rank of 1-3
test data:
create table test (health_id int, clm_month date)
insert into test values
(1,'20170101'),(1,'20170201'),(1,'20170301'),(1,'20170401')
,(2,'20170101'),(2,'20170201'),(2,'20170401'),(2,'20170501') -- no March
,(3,'20170101'),(3,'20170115'),(3,'20170201'),(3,'20170215') -- Multiple per month
,(3,'20170401'),(3,'20170415'),(3,'20170501'),(3,'20170515')
rextester demo: http://rextester.com/MTZ16877
returns:
+-----------+------------+----+
| health_id | clm_month | dr |
+-----------+------------+----+
| 1 | 2017-01-01 | 1 |
| 1 | 2017-02-01 | 2 |
| 1 | 2017-03-01 | 3 |
| 2 | 2017-01-01 | 1 |
| 2 | 2017-02-01 | 2 |
| 2 | 2017-04-01 | 3 |
| 3 | 2017-01-01 | 1 |
| 3 | 2017-01-15 | 1 |
| 3 | 2017-02-01 | 2 |
| 3 | 2017-02-15 | 2 |
| 3 | 2017-04-01 | 3 |
| 3 | 2017-04-15 | 3 |
+-----------+------------+----+

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

Add a column of Averages in Access

I have written the below query to show total calls (from phone system) coming in for individual days of the week. What I now need is to show the average of the total calls coming in for these days.
My query look like this:
SELECT WeekdayName(Weekday([Calls Volume].Weekday),False,1) AS [Day of the week], Sum([Calls Volume].Offered) AS [Calls Offered]
FROM [Calls Volume]
GROUP BY WeekdayName(Weekday([Calls Volume].Weekday),False,1), [Calls Volume].Weekday
ORDER BY [Calls Volume].Weekday;
Current Output:
Day of the week | Calls Offered
--------------------------------
Monday | 100
Tuesday | 200
Wednesday | 300
Desired output:
Day of the week | Calls Offered | Average Calls for the day of the week
-------------------------------------------------------------------------
Monday | 100 | 30
Tuesday | 200 | 20
Wednesday | 300 | 15
Thanks
Sample data:
DateTime | Calls Offered
------------------------
1/08/2014 9AM | 12
1/08/2014 10AM | 10
2/08/2014 9AM | 9
2/08/2014 11AM | 12
and so forth..