How to calculate days count between 2 date in sql server - sql

I'm creating a system to calculate user working days.
Suppose user 1 has been at work from 2020-02-01 to 2020-02-20.
And user 2 has been at work from 2020-02-10 to 2020-02-15
In Sql Server
I have something similar in the table below
Now i want to calculte count of user working days between 2 date
For Example
Select Sum(DateDiff(Day,StartDate,EndDate)) From Table1 Where StartDate >= '2020-02-08' And EndDate <= '2020-02-12'
Above query returns 0 . But in this date user 1 has 5 working days and user 2 has 3 working days.
How can i calculate this?
I want a similar answer below:

You can use datediff() -- after testing for the limits of the period that you want:
select t.*,
datediff(day,
case when startdate < '2020-02-08' then '2020-02-08' else startdate end),
case when enddate > '2020-02-12' then '2020-02-12' else startdate end)
) + 1
from t;
The + 1 is because you are including the last day in the calculation.
Note: This only works correctly when there is an overlap. You want a filter:
(enddate >= '2020-02-08' or startdate <= '2020-02-12')
Based on the question, I'm not sure if this should be in a WHERE clause or a CASE expression. That is, do you want to filter out non-overlaps or do you want them to appear as 0/NULL?

Related

Get a count and average from a couple rows in the same table?

Using Microsoft SQL Server, I'm trying to get the average days it took someone to complete a transaction in a given month.
Each user has hundreds of transactions so I'm looking for a way to get the count on how many transactions for each person and then their average for the month. I also need to make sure that I remove any NULL returns and convert any negatives to a Zero but keep it accounted for.
Example would look like (Max | 300 | 12.5) for (Person | Transactions | Average).
I've been able to get as far as:
SELECT
[Transaction],
[NAME],
DATEDIFF (d, [Startdate], [Closedate]) AS Days
FROM
[Table]
WHERE
YEAR ([Startdate]) = 2021
AND MONTH ([Closedate]) = 11
AND Closedate IS NOT NULL
I've tried to figure out how to incorporate a CASE statement but it's not working when I tried to do it before the DATEDIFF.
Looks like you can just do a simple GROUP BY with conditional aggregation.
To avoid repeating the DATEDIFF calculation you can stuff it into a CROSS APPLY (VALUES.
Always use date intervals such as >= AND < rather than using functions on date columns
SELECT
t.NAME,
SUM(CASE WHEN v.Days > 0 THEN v.Days ELSE 0 END) AS TotalDays
FROM
[Table] t
CROSS APPLY (VALUES(
DATEDIFF(day, t.Startdate, t.Closedate)
)) v(Days)
WHERE
t.Startdate >= '20211101'
AND t.Startdate < '20211201'
AND t.Closedate IS NOT NULL
GROUP BY
t.NAME;

Flag 2 actual vs benchmark readings every rolling 12 hours in SQL Developer Query

Looking for some help with code in SQL Developer query to flag any 2 temperature readings - every rolling 12 hours - if they are greater than the acceptable benchmark of 101 deg F.
The given data fields are:
Temp Recorded (DT/TM data type ; down to seconds)
Reading Value (number data type)
Patient ID
There are multiple readings taken throughout a patients stay, at random times.
Logically, we can check if two adjacent times total 12 hrs or more & EACH of their temp readings are >101 but not sure how to put it into a CASE statement (unless there's a better SQL syntax).
Will really appreciate if a SQL only solution can be recommended.
Many Thanks
Giving the code below including the CASE statement as provided by #Gordon Linoff underneath. The below sample code is part of a bigger query joining multiple tables:
SELECT CE.PatientID, CE.ReadingValue, CE.TempRecorded_DT_TM,
(case when sum(case when readingvalue > 101 then 1 else 0 end) over (
partition by patientid
order by dt
range between '12' hour preceding and current row
) >= 2
then 'Y' else 'N'
end) as temp_flag
FROM
edw.se_clinical_event CE
WHERE
CE.PatientID = '176660214'
AND
CE.TempRecorded_DT_TM >= '01-JAN-20'
ORDER BY
TempRecorded_DT_TM
If you want two readings in 12 hours that are greater than 101, then you can use a rolling sum with a window frame:
select t.*,
(case when sum(case when readingvalue > 101 then 1 else 0 end) over (
partition by patientid
order by dt
range between interval '12' hour preceding and current row
) >= 2
then 'Y' else 'N'
end) as temp_flag
from t;

sql repeat rows for weekend and holidays

I have a table A that we import based on the day that it lands on a location. We dont receive files on weekend and public holidays, and the table has multiple countries data so the public holidays vary. In essence we looking to duplicate a row multiple times till it encounters the next record for that ID (unless its the max date for that ID). A typical record looks like this:
Account Datekey Balance
1 20181012 100
1 20181112 100
1 20181212 100
1 20181512 100
1 20181712 100
And needs to look like this (sat, sun & PH added to indicate the day of week):
Account Datekey Balance
1 20181012 100
1 20181112 100
1 20181212 100
1 20181312 100 Sat
1 20181412 100 Sun
1 20181512 100
1 20181612 100 PH
1 20181712 100
Also Datekey is numeric and not a date. I tried a couple solutions suggested but found that it simply duplicates the previous row multiple times without stopping when the next dates record is found. I need to run it as an update query that would execute daily on table A and add missing records when its executed (sometimes 2 or 3 days later).
Hope you can assist.
Thanks
This question has multiple parts:
Converting an obscene date format to a date
Generating "in-between" rows
Filling in the new rows with the previous value
Determining the day of the week
The following does most of this. I refuse to regenerate the datekey format. You really need to fix that.
This also assumes that your setting are for English week day names.
with t as (
select Account, Datekey, Balance, convert(date, left(dkey, 4) + right(dkey, 2) + substring(dkey, 5, 2)) as proper_date
from yourtable
),
dates as (
select account, min(proper_date) as dte, max(proper_date) as max_dte
from t
group by account
union all
select account, dateadd(day, 1, dte), max_dte
from dates
where dte < max_dte
)
select d.account, d.dte, t.balance,
(case when datename(weekday, d.dte) in ('Saturday', 'Sunday')
then left(datename(weekday, d.dte), 3)
else 'PH'
end) as indicator
from dates d cross apply
(select top (1) t.*
from t
where t.account = d.account and
t.proper_date <= d.dte
order by t.proper_date desc
) t
option (maxrecursion 0);

Calculating between dates fields from a previous record

Patient Code Unique Visit Code AdmitDate Discharge Date
91260 10146440 7/20/2013 9/16/2013
91260 10217043 9/21/2013 11/2/2013
This is a single patient with 2 different visits to the physician, I need to take the Discharge date of the earliest visit (9/16/2013) and the AdmitDate of the most recent visit (9/21/2013) and determine if it's within a 30 day period. How do I accomplish this in SQL 2008
Try
SELECT PATIENT_CODE,
CASE WHEN DATEDIFF(DAY, MIN(DISCHARGE_DATE), MAX(ADMIT_DATE)) < 30 THEN 1 ELSE 0 END
FROM TABLE1
GROUP BY PATIENT_CODE
The code
CASE WHEN DATEDIFF(DAY, MIN(DISCHARGE_DATE), MAX(ADMIT_DATE)) < 30 THEN 1 ELSE 0 END
will be 1 for those visits which occurs in period less than 30 days.
SQL Fiddle

Calculate items, loop by month, adding month each time through

I have a table of tickets. I am trying to calculate how many tickets were "open" at each month end over the course of the current year. As well, I am pushing this to a bar chart and I am needing out put this into an array through LINQ.
My SQL query to get my calculation is:
SELECT
(SELECT COUNT(*) FROM tblMaintenanceTicket t WHERE (CreateDate < DATEADD(MM, 1, '01/01/2012')))
-
(SELECT COUNT(*) FROM tblMaintenanceTicket t WHERE (CloseDate < DATEADD(MM, 1, '01/01/2012'))) AS 'Open #Month End'
My logic is the following: Count all tickets open between first and end of the month. Subtract that count from the tickets closed before the end of the month.
UPDATED:
I have updated my query with the comments below and it is not working with errors in the GROUP, but I am not truly understanding the logic I guess, my lack of skill in SQL is to blame.
I have added a SQL Fiddle example to show you my query: http://sqlfiddle.com/#!3/c9b638/1
Desired output:
-----------
| Jan | 3 |
-----------
| Feb | 4 |
-----------
| Mar | 0 |
-----------
Your SQL has several erros . . . are grouping by CreateDate but you don't have it as a column from the subqueries. And, you don't have a column alias on the count(*).
I think this is what you are trying to do:
select DATENAME(MONTH,CreateDate), DATEPART(YEAR,CreateDate),
(sum(case when CreateDate < DATEADD(MM, 1, '01/01/2012') then 1 else 0 end) -
sum(case when CloseDate < DATEADD(MM, 1, '01/01/2012') then 1 else 0 end)
)
from tblMaintenanceTicket
group by DATENAME(MONTH,CreateDate), DATEPART(YEAR,CreateDate)
Your comment seems to elucidate what you want clearer than your question (the explanation in the question is a bit buried). What you need is a driver table of months and then join this to your table. Something like:
select mons.yr, mons.mon, count(*) as OpenTickets
from (select month(CreateDate) as mon, year(CreateDate) as yr,
cast(min(CreateDate) as date) as MonthStart,
cast(max(CreateDate) as date) as monthEnd
from tblMaintenanceTicket
group by month(CreateDate), year(CreateDate)
) mons left outer join
tblMaintenanceTicket mt
on mt.CreateDate <= mons.MonthEnd and
(mt.CloseDate > mons.MonthEnd or mt.CloseDate is null)
group by mons.yr, mons.mon
I am assuming records are created on every day. This is a convenience so I don't have to think about getting the first and last day of each month using other SQL functions.
If your query is returning what you need, then simply use DATENAME(MONTH, yourDate) to retrieve the month and group by Month,Year:
SELECT SUM(*), DATENAME(MONTH,yourDate), DATEPART(YEAR,yourDate)
FROM
(
your actual query here
)
GROUP BY DATENAME(MONTH,yourDate), DATEPART(YEAR,yourDate)