Need to sort by Date then Hour, then output Date, text Day of week , range of hours SQL Server 2008 R2 - sql-server-2008-r2

NEWBIE at work! I am trying to create a simple summary that counts the number of customer visits and groups by 1) date and 2) hour, BUT outputs this:
Date Day of Wk Hour #visits
8/12/2013 Monday 0 5
8/12/2013 Monday 1 7
8/12/2013 Monday 6 10
8/13/2013 Tuesday 14 25
8/13/2013 Tuesday 16 4
We are on military time, so 14 = 2:00 pm
Select
TPM300_PAT_VISIT.adm_ts as [Date]
,TPM300_PAT_VISIT.adm_ts as [Day of Week]
,TPM300_PAT_VISIT.adm_ts as [Hour]
,count(TPM300_PAT_VISIT.vst_ext_id) as [Total Visits]
From
TPM300_PAT_VISIT
Where
TPM300_PAT_VISIT.adm_srv_cd='22126'
and TPM300_PAT_VISIT.adm_ts between '07-01-2013' and '08-01-2013'
Group by
cast(TPM300_PAT_VISIT.adm_ts as DATE)
,datepart(weekday,TPM300_PAT_VISIT.adm_ts)
,datepart(hour,TPM300_PAT_VISIT.adm_ts)
Order by
CAST(TPM300_PAT_VISIT.adm_ts as DATE)
,DATEPART(hour,TPM300_PAT_VISIT.adm_ts)

This should solve the problem:
; With Streamlined as (
SELECT
DATEADD(hour,DATEDIFF(hour,'20010101',adm_ts),'20010101') as RoundedTime,
vst_ext_id
from
TPM300_PAT_VISIT
where
adm_srv_cd='22126' and
adm_ts >= '20130701' and
adm_ts < '20130801'
)
Select
CONVERT(date,RoundedTime) as [Date],
DATEPART(weekday,RoundedTime) as [Day of Week],
DATEPART(hour,RoundedTime) as [Hour],
count(vst_ext_id) as [Total Visits]
From
Streamlined
Group by
RoundedTime
Order by
CONVERT(date,RoundedTime),
DATEPART(hour,RoundedTime)
In the CTE (Streamlined)'s select list, we floor each adm_ts value down to the nearest hour using DATEADD/DATEDIFF. This makes the subsequent grouping easier to specify.
We also specify a semi-open interval for the datetime comparisons, which makes sure we include everything in July (including stuff that happened at 23:59:59.997) whilst excluding events that happened at midnight on 1st August. This is frequently the correct type of comparison to use when working with continuous data (floats, datetimes, etc), but means you have to abandon BETWEEN.
I'm also specifying the dates as YYYYMMDD which is a safe, unambiguous format. Your original query could have been interpreted as either January 7th - January 8th or 1st July - 1st August, depending on the settings of whatever account you use to connect to SQL Server. Better yet, if these dates are being supplied by some other (non-SQL) code, would be for them to be passed as datetimes in the first place, to avoid any formatting issues.

Related

Condition not applied properly in quarterly lookup in postgresql

SELECT (outbound.data_bas_year||outbound.data_bas_month) as year,
EXTRACT(QUARTER from to_date(outbound.data_bas_year||outbound.data_bas_month, 'YYYYMM')) AS quarter,
count(outbound.call_time) as col_1_0_
FROM cfk_dashboard.if_outbnd_call_dtl outbound
WHERE outbound.data_bas_year||outbound.data_bas_month between '20210101' and '20211231'
AND outbound.conn_call_number = 1
GROUP BY year,quarter
I wrote a query to look up January through December quarterly, but no data for January is aggregated.
In other words, only February and March are counted except for January in the first quarter.
However, if I change the condition start date from 20210101 to 20201231, I get the result I want.
Why?
Function to_date generates date for you, if you have not day value then default value of day will be -01.
But in your query after command WHERE you are used outbound.data_bas_year||outbound.data_bas_month, this is gets only 202101 and you compare this with 20211231 or with 20210101, this will not work correctly. For example, you can use outbound.data_bas_year||outbound.data_bas_month||'01' or to_date(outbound.data_bas_year||outbound.data_bas_month, 'YYYYMM') between '20210101'::date and '20211231'::date

How can I always get the full period when grouping by week in PostgreSQL?

I'm used to do the following syntax when analysing weekly data:
select week(creation_date)::date as week,
count(*) as n
from table_1
where creation_date > current_date - 30
group by 1
However, by doing this I will get just part of the first week.
Is there any smart way to alway get a whole week in the beginning?
Like get the first day of the week I would get half of.
First off you need to define what you mean by "week". This is more difficult than it appears. While humans have an intuitive since of a week, computers are just not that smart. There are 2 common conventions: the ISO-8601 Standard and, for lack of a better term, Traditional. ISO-8601 defines a week as always beginning on Monday and always containing 7 days. Traditional weeks begin on Sunday (usually) but may have weeks with less than 7 days. This results from having the 1st week of the year beginning on 1-Jan regardless of day of week. Thus the 1st and/or last weeks may have less than 7 days. ISO-8601 throws it own curve into the mix: the 1st week of the year begins on the week containing 4-Jan. Thus the last days of Dec may be in week 1 of the next year and the first days Jan may be in week 52/53 of the prior year.
All the below assume the ISO-8061.
Secondly there is no week function in Postgres. In you need extract function. So for this particular case:
select extract(week from creation_date)::integer as week, ...
Finally, your predicate (current_date - 30) ensures you will unusually not begin on the 1st of the week. To get the correct date take that result back 1 week, then go forward to the next Monday.
with days_to_monday (day_adj) as
( values ('{7,6,5,4,3,2,1}'::int[]) )
select current_date - 30
, current_date - 30 - 7 + day_adj[extract (isodow from current_date - 30 )]
from table_1 cross join days_to_monday;
The CTE establishes an array which for a given day of the week contains the number of days need to the next Monday. That main query extracts the day of week of current date and uses that to index the array. The corresponding value is added to get the proper date.
Putting that together with your original query to arrive at:
with next_week (monday) as
( values (current_date - 30 - 7
+ ('{7,6,5,4,3,2,1}'::int[])[extract (isodow from current_date - 30 )])
)
select extract(week from creation_date) as week,
count(*) as n
from table_1
where creation_date >= (select monday from next_week)
group by 1
order by 1;
For full example see fiddle.

TSQL ISO Month Week Number for ISO Year Week Number

Using TSQL I need to get the ISO Week Number in a Month for a give ISO Year Week Number.
For example: The following code will give me Week #1 for 12/31/2001, which is correct. It is the first Monday in 2002 and the first day of the ISO Year 2002.
select DATEPART(ISO_WEEK, '12-31-2001'); --Week 1 January 2002
My question is how do I...
(1) Take the ISO Week Number Example: ISO Year Week Number: 14 for April 4, 2016 (April Week #1).
(2) Now Take ISO Year Week Number 14 and return April Month Week Number = 1 for the example above.
There seems to be nothing in SQL Server to get the ISO Month Week# from the ISO Year Week Number. I have a function I wrote but it is has some hacks to get it to work, but not 100%.
I think you want something like this... but am not sure why you need the ISO_WEEK. Just replace getdate() with your column.
select datepart(wk, getdate()) - datepart(wk,dateadd(m, DATEDIFF(M, 0, getdate()), 0)) + 1
After attempting to handle getting ISO Month Week Number in functions I decided an easier solution was to create an ISO_Calendar table in SQL Sever.
We know in TSQL you can get the ISO Year Week Number and some a bit of work the ISO Year Number. The ISO Month Week Number is another story.
I build the table shown below with data from 2000 to 2040 by populating all the columns other than the ISO Month number. Then on a second pass I looped through the table and set the ISO Month number based on the Month# in the Monday Date.
Now if I want to get the ISO Month number for a date I check #Date between Monday and Sunday. In my case I am only concerned with dates between Monday and Friday since this is for a stock analysis site.
select #ISOMonthWeekNo = c.ISOMonthWeekNo
from ISO_Calendar c
where #TransDate between c.Monday and c.Sunday;
The advantage is the table is a one time build and easier to verify the accuracy of the data.

How to get total experience in terms of date object

I have a condition here in which I will have total experience in terms of month and year. For example, two drop down will be there for asking total number of experience in month and year. So if I am working from 1 Jan 2012, then I will write total experience as 3 year and 11 months. Now I have to convert this 3 year and 11 months into date format so that I can save this into database
You could use java.util.Calendar:
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, month);
calendar.add(Calendar.YEAR, year);
Date date = calendar.getTime();
As a word of caution, the day field would be set to today's date. Check the intended behaviour if the current day is outside of the bounds for the target month. For example, setting the month to February when calendar has a day field of 30. It might be wise to set the day to a known, valid value for every month (eg: 1) before setting the month and year.
Use DATE_SUB() function:
Try this:
SELECT DATE_SUB(DATE_SUB(CURRENT_DATE(), INTERVAL 3 YEAR), INTERVAL 11 MONTH);
You can use mysql's date_sub() function or <date> - interval <expression> unit syntax to subtract an interval from a date.
select date_sub(curdate(),interval '3-11' YEAR_MONTH) as start_date
UPDATE:
Following the conversation between the OP and #eggyal, the OP need to replace the period in the incoming data with - and construct an insert statement as follows:
insert into mytable (...,join_date,...) values (...,date_sub(curdate(),interval '3-11' YEAR_MONTH),...)

SQL DateDiff Weeks - Need and alternative

The MS SQL DateDiff function counts the number of boundaries crossed when calculating the difference between two dates.
Unfortunately for me, that's not what I'm after. For instance, 1 June 2012 -> 30 June 2012 crosses 4 boundaries, but covers 5 weeks.
Is there an alternative query that I can run which will give me the number of weeks that a month intersects?
UPDATE
To try and clarify exactly what I'm after:
For any given month I need the number of weeks that intersect with that month.
Also, for the suggestion of just taking the datediff and adding one, that won't work. For instance February 2010 only intersects with 4 weeks. And the DateDiff calls returns 4, meaning that simply adding 1 would leave me the wrong number of weeks.
Beware: Proper Week calculation is generally trickier than you think!
If you use Datepart(week, aDate) you make a lot of assumptions about the concept 'week'.
Does the week start on Sunday or Monday? How do you deal with the transition between week 1 and week 5x. The actual number of weeks in a year is different depending on which week calculation rule you use (first4dayweek, weekOfJan1 etc.)
if you simply want to deal with differences you could use
DATEDIFF('s', firstDateTime, secondDateTime) > (7 * 86400 * numberOfWeeks)
if the first dateTime is at 2011-01-01 15:43:22 then the difference is 5 weeks after 2011-02-05 15:43:22
EDIT: Actually, according to this post: Wrong week number using DATEPART in SQL Server
You can now use Datepart(isoww, aDate) to get ISO 8601 week number. I knew that week was broken but not that there was now a fix. Cool!
THIS WORKS if you are using monday as the first day of the week
set language = british
select datepart(ww, #endofMonthDate) -
datepart(ww, #startofMonthDate) + 1
Datepart is language sensistive. By setting language to british you make monday the first day of the week.
This returns the correct values for feburary 2010 and june 2012! (because of monday as opposed to sunday is the first day of the week).
It also seems to return correct number of weeks for january and december (regardless of year). The isoww parameter uses monday as the first day of the week, but it causes january to sometimes start in week 52/53 and december to sometimes end in week 1 (which would make your select statement more complex)
SET DATEFIRST is important when counting weeks. To check what you have you can use select ##datefirst. ##datefirst=7 means that first day of week is sunday.
set datefirst 7
declare #FromDate datetime = '20100201'
declare #ToDate datetime = '20100228'
select datepart(week, #ToDate) - datepart(week, #FromDate) + 1
Result is 5 because Sunday 28/2 - 2010 is the first day of the fifth week.
If you want to base your week calculations on first day of week is Monday you need to do this instead.
set datefirst 1
declare #FromDate datetime = '20100201'
declare #ToDate datetime = '20100228'
select datepart(week, #ToDate) - datepart(week, #FromDate) + 1
Result is 4.