Display rows in SQL where the difference between columns is 1 day - sql

I have joined 3 tables to provide a date of birth and a date of death. I now need to filter these results to display when the elapsed time between Birth and Death is 1 day, 2 days etc.
I am struggling to work out how I can do this. The date format is 2007-12-07 so I can't do a multiple of seconds on this.

Maybe this is what you are looking at with the limited information provided. This is specific to SQL Server.
DECLARE #Date TABLE
(
[DoB] date,
[DoD] date
)
INSERT INTO #Date
VALUES('2007-12-07','2007-12-08'),('2007-12-07','2007-12-10'),('2008-05-17','2020-07-02'),('2009-10-07','2015-12-25')
SELECT [DoB],
[DoD],
DATEDIFF (d, [DoB], [DoD]) AS NumOfDays
FROM #Date
ORDER BY NumOfDays

Related

How to retrieve data for last 2 hrs from a specific Datetime

I am trying to extract last two hours records from a specific datetime. That means, I need to find out if there's any transaction occurred before 2019-11-20 18:00:00. I have 100 records against which I need to extract 2 hrs prior activities.
Can I know how to formulate a sql query to fetch 2 hrs prior records?
This is how I was trying to formulate my code;
select distinct
ID,
START_DTTM,
from table1
where START_DTTM between dateadd(hour,-2,getdate()) and getdate();
I tried this between DATEADD(hour, -2 , CAST('2019-11-20 18:00:00' AS DATETIME)) and CAST('2019-11-20 18:00:00' AS DATETIME). returning only 20.
Also tried this; WHERE START_DTTM > DATEADD(hour, -2 , CAST('2019-11-20 18:00:00' AS DATETIME)). This one returns 200 records.
which one would be best approach.
It is very hard to answer this question because you don't tell us anything about the data model but if you want to get the last two hours of records and you have a column with a timestamp just add a where clause onto the select statement that says
WHERE datetimecolum > DATEADD(hour, -2 , GETDATE())

Calculate Recurring User For 12 Months with SQL

I'm trying to see if there is a better way to achieve what I am doing right now. For example, I need to know total number of users who have logged in for the past 12 months. So each user who has logged in at least once a month, for twelve months in a row would count towards the total.
The way I am doing this right now is: I query my table and get all user ids and timestamps of when they were active and return them to my c# code. Then with bunch of loops and LINQ I calculate the value (Its too much code to dump into this question and since I'm trying to get away from doing it in c# I don't believe there is a need for it).
Now this takes some time to run and I'm sure there has to be a better way to do this with SQL. I've searched but haven't found any SQL functions that let you count based on a recurring condition.
For an answer I'm hoping to either get an example or a link to a similar SO question or an article that talks about achieving this.
An example of MyUsersTable:
UserId | Timestamp
1 | '2018-12-23 00:00:00.000'
1 | '2018-11-23 00:00:00.000'
1 | '2018-10-23 00:00:00.000'
EDIT: I did thought of using SUM(CASE WHEN month = 1 and month = 2 and month = 3) but that seems also like not a great solution.
Expected Result:
Total number of users who were active at least once a month in the last 12 months.
If you need users who logged in every month in 2018:
select ut.userid
from MyUsersTable ut
where timestamp >= '2018-01-01' and timestamp < '2019-01-01'
group by ut.userid
having count(distinct month(timestamp)) = 12;
I'd count the distinct number of months a user logged in on:
SELECT userid
FROM mytable
WHERE YEAR(timestamp) = 2018
GROUP BY userid
HAVING COUNT(DISTINCT MONTH(timestamp)) = 12
To get userIDs who logged in for a specific number of consecutive months, you can use:
/* These are your input values */
DECLARE #searchDate date = '2018-12-15' ;
DECLARE #monthsToSearch int = 12 ;
/* First day of search month */
DECLARE #EndDate date = DATEADD(month, DATEDIFF(month, 0, #searchDate), 0) ;
/* First day of month to search from */
DECLARE #StartDate date = DATEADD(month, -#monthsToSearch, #EndDate) ;
SELECT userID --, #StartDate AS startDate, #EndDate AS endDate
FROM (
SELECT userID, ( (YEAR(userLoginDT)*100)+MONTH(userLoginDT) ) AS datePoint /* YYYYMM */
FROM t1
WHERE userLoginDT >= #StartDate
AND userLoginDT < #EndDate
) s1
GROUP BY userID
HAVING count(distinct(datePoint)) = #monthsToSearch
;
See the db<>fiddle here for my examples.
The fist two declared variables are your input variables. You feed it the date your are running the report on and then telling it how many months you want to go back to. So you can search any number of months. After that, it's pretty much date manipulation and math.
#EndDate essentially takes your declared date and calculates the first day of the month you are currently searching in. You will search for any dates before this date.
#StartDate counts back from your #EndDate to calculate the number of months you want to search.
(YEAR(userLoginDT)*100)+MONTH(userLoginDT) in your sub-select creates an integer variable that you can GROUP BY to get a distinct count of months you're searching over. This part could be sped up with the Calendar Table.
Then you just use the HAVING to pick out how many distinct records your want for #monthsToSearch.
NOTE: As many here can attest, I'm a huge fan of working with Calendar Tables when dealing with date calculations and large amounts of search data. Something like that would likely speed the query up a bit.

Get date for nth day of week in nth week of month

I have a column with values like '3rd-Wednesday', '2nd-Tuesday', 'Every-Thursday'.
I'd like to create a column that reads those strings, and determines if that date has already come this month, and if it has, then return that date of next month. If it has not passed yet for this month, then it would return the date for this month.
Expected results (on 4/22/16) from the above would be: '05-18-2016', '05-10-2016', '04-28-2016'.
I'd prefer to do it mathematically and avoid creating a calendar table if possible.
Thanks.
Partial answer, which is by no means bug free.
This doesn't cater for 'Every-' entries, but hopefully will give you some inspiration. I'm sure there are plenty of test cases this will fail on, and you might be better off writing a stored proc.
I did try to do this by calculating the day name and day number of the first day of the month, then calculating the next wanted day and applying an offset, but it got messy. I know you said no date table but the CTE simplifies things.
How it works
A CTE creates a calendar for the current month of date and dayname. Some rather suspect parsing code pulls the day name from the test data and joins to the CTE. The where clause filters to dates greater than the Nth occurrence, and the select adds 4 weeks if the date has passed. Or at least that's the theory :)
I'm using DATEFROMPARTS to simplify the code, which is a SQL 2012 function - there are alternatives on SO for 2008.
SELECT * INTO #TEST FROM (VALUES ('3rd-Wednesday'), ('2nd-Tuesday'), ('4th-Monday')) A(Value)
SET DATEFIRST 1
;WITH DAYS AS (
SELECT
CAST(DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),N.Number) AS DATE) Date,
DATENAME(WEEKDAY, DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),N.Number)) DayName
FROM master..spt_values N WHERE N.type = 'P' AND N.number BETWEEN 0 AND 31
)
SELECT
T.Value,
CASE WHEN MIN(D.Date) < GETDATE() THEN DATEADD(WEEK, 4, MIN(D.DATE)) ELSE MIN(D.DATE) END Date
FROM #TEST T
JOIN DAYS D ON REVERSE(SUBSTRING(REVERSE(T.VALUE), 1, CHARINDEX('-', REVERSE(T.VALUE)) -1)) = D.DayName
WHERE D.Date >=
DATEFROMPARTS(
YEAR(GETDATE()),
MONTH(GETDATE()),
1+ 7*(CAST(SUBSTRING(T.Value, 1,1) AS INT) -1)
)
GROUP BY T.Value
Value Date
------------- ----------
2nd-Tuesday 2016-05-10
3rd-Wednesday 2016-05-18
4th-Monday 2016-04-25

Update table based on last date of previous month

Please would you advise how I could create a column which showed a timestamp/date for each row indicating the last day of the previous month. For example:
Name Surname DOB Timestamp
John Smith 1970/04/20 2015/02/28
Cindy Smith 1975/03/20 2015/02/28
Now this could be for 5000 people and I've just given 2 rows to show you what I mean.
CREATE table employees (Name NVARCHAR(30),Surname NVARCHAR (30),DOB DATETIME,Timestamp DATETIME)
To tackle the problem of the dates not showing hours,minutes, seconds, I am using
CONVERT(CHAR(10),Timestamp,113)
Do you use a While loop or something to create a column which shows the same timestamp for each row?
Thanks.
I think the easiest way is to just subtract the day of the month from the date:
select t.*, dateadd(day, -day(timestamp), timestamp)
from table t;
EDIT: In an `update:
update t
set timestamp = dateadd(day, -day(dob), dob)
In addition, you shouldn't use convert to remove the time component of a date, you should simply case to date. If dob had a time component (which seems unlikely):
update t
set timestamp = cast(dateadd(day, -day(dob), dob) as date)
Assuming the table have records with Timestamp column as NULL. Then with the following update query will update all records with previous month's last day.
UPDATE employees
SET [Timestamp] = CAST(DATEADD(DAY,-1,DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0))AS DATE)
WHERE [Timestamp] IS NULL
The inner DATEADD will find first day of current month and outer DATEADD decrements the date by one which result in previous month's last date.
When the month in GETDATE() is April, the records with NULL values will be updated with 31-Mar-2015. When the GETDATE() becomes May, the records with NULL values will be updated with 30-Apr-2015 ie, it won't update the records which have already values or which are updated.

Sales Grouped by Week of the year

I have a requirement to output the number sales in a year to date in weekly format where Monday is the first day of the week and Sunday is the last.
The table structure is as follows.
SalesId | Representative | DateOfSale.
Below is what I have tried but it doesn't seem to give me the correct result. The counts don't seem to add up for a given week. The Sunday results are not included in the correct week. I am thinking it has something to do with the date not including 11:59:59.999 for the last day of the week.
SELECT DATEADD(wk, DATEDIFF(wk, 6, Sales.DateOfSale), 6) as [Week Ending], count(SalesID) as Sales,
count(distinct(representative)) as Agents, count(SalesID) / count(distinct(representative)) as SPA
FROM Sales
where DateOfSale >= DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)
GROUP BY DATEADD(wk, DATEDIFF(wk, 6, Sales.DateOfSale), 6)
ORDER BY DATEADD(wk, DATEDIFF(wk, 6, Sales.DateOfSale), 6)
I am hoping to have something like this:
Week Ending | Sales
01/05/2014 | 5
01/12/2014 | 8
01/19/2014 | 11
01/26/2014 | 14
Please excuse the formatting of the table above. I couldn't seem to figure out how to create a pipe/newline based table using the editor.
~Nick
I suggest creating a table or table parameter that has all of your calendar information. In this case, it would need at minimum the column WeekEnding.
For example
DECLARE #MyCalendar TABLE
(
WeekEnding date
);
Populate this with your valid WeekEnding dates. I might also make parameters to limit the amount of sales data, e.g. #BeginDate and #EndDate.
If you join using "<=" on the week ending date, then I believe you will get the return you want:
SELECT
MyCalendar.WeekEnding,
COUNT(Sales.SalesId) Sales,
COUNT(DISTINCT Sales.Representative) Agents,
CAST(COUNT(Sales.SalesId) AS float) / CAST(COUNT(DISTINCT Sales.Representative) AS float) Spa
FROM
Sales
INNER JOIN
#MyCalendar MyCalendar
ON
Sales.DateOfSale <= MyCalendar.WeekEnding
WHERE
Sales.DateOfSale BETWEEN #BeginDate AND #EndDate
GROUP BY
MyCalendar.WeekEnding;
I am assuming you are using SQL 2012, but I believe this will work in 2008 too. I might point out two other things. First, consider your data type when dividing the COUNT of SalesId by the distinct count of Representative. You may not get the return you expect, and that is why I cast as float. Second, you apply count distinct slightly differently than what I use; the extra parenthesis are not needed.
I have a simplified version in SQL Fiddle.