I have two columns; CommencementDate and ExpectedCompletionDate. I would like to insert a column (Days) which gives the number of days between the two date columns in my table.
I'm not sure where to start. I'm on day 5 of writing queries!
You just have to substract ExpectedCompletionDate and CommencementDate and return the days of that.
SELECT DATEDIFF(Day, ExpectedCompletionDate, CommencementDate);
Also you can return the absolute value to ensure this is a positive value.
SELECT ABS(DATEDIFF(Day, ExpectedCompletionDate, CommencementDate));
You can see the documentation in microsft
http://technet.microsoft.com/en-us/library/ms189794.aspx -> Datediff
http://technet.microsoft.com/en-us/library/ms189800.aspx -> ABS
Related
I am looking for a function in PostgreSQL which help me to generate recurring date after every 90 days from created date
for example: here is a demo table of mine.
id date name
1 "2020-09-08" "abc"
2 "2020-09-08" "xyz"
3 "2020-09-08" "def"
I need furure date like 2020-12-08, 2021-03-08, 2021-06-08, and so on
First it's important to note that, if you happen to have a date represented as text, then you can convert it to a date via:
SELECT TO_DATE('2017-01-03','YYYY-MM-DD');
So, if you happen to have a text as an input, then you will need to convert it to date. Next, you need to know that if you have a date, you can add days to it, like
SELECT CURRENT_DATE + INTERVAL '90 day';
Now, you need to understand that you can use dynamic variables, like:
select now() + interval '1 day' * 180;
Finally, you will need a temporary table to generate several values described as above. Read more here: How to return temp table result in postgresql function
Summary:
create a function
that generates a temporary table
where you insert as many records as you like
having the date shifted
and converting text to date if needed
You can create a function that returns a SETOF dates/timestamps. The below function takes 3 parameters: a timestamp, an interval, the num_of_periods desired. It returns num_of_periods + 1 timestamps, as it returns the original timestamp and the num_of_periods each the specified interval apart.
create or replace
function generate_periodic_time_intervals
( start_date timestamp
, period_length interval
, num_of_periods integer
, out gen_timestamp timestamp
)
returns setof timestamp
language sql
immutable strict
as $$
select (start_date + n * period_length)::timestamp
from generate_series(0,num_of_periods) gs(n)
$$;
For your particular case to timestamp/date as necessary. The same function would work for your case with the interval specified as '3 months' or of '90 days'. Just a note the interval specified can be any valid INTERVAL data type. See here. It also demonstrates the difference between 3 months and 90 days.
I am generating a report where I SUM price and cost values per month. I would like to show the same defined time period - 1 year. I'm not clear how to nest this. Would I use a case when statement?
My terrible example.
select month, cost, price from table1 where (define months here in SSRS parameter filter)
I'd like to see:
select month, cost, price, lastyearcost, lastyearprice FROM table1 where (define months here in SSRS parameter filter)
I know that I should be using some variant of GETDATE() -1, but will this include the data range parameters passed when running the report? How do I select the column of cost apply the date filter and then get the result of cost for that period last year?
Hopefully that makes sense?
One way is to use DATEPART() with the correct nesting and pairing.
select
month,
cost,
price,
lastyearcost,
lastyearprice
FROM table1
where
--this is limiting the data to the year passed in, and the previous year
(datepart(year,DateColumn) = #YearParam or datepart(year,DateColumn) = #YearParam-1)
and
--this is limiting the months to the two parameters you pass in as integers
(datepart(month,DateColumn) >= #minMonthParam and datepart(month,DateColumn) <= #maxMonthParam)
TEST DATA
See the DEMO HERE
declare #table1 table (DateColumn date)
insert into #table1 (DateColumn)
values
('1/1/2016'),
('2/1/2016'),
('3/1/2016'),
('4/1/2016'),
('5/1/2016'),
('6/1/2016'),
('7/1/2016'),
('8/1/2016'),
('9/1/2016'),
('10/1/2016'),
('11/1/2016'),
('12/1/2016'),
('1/1/2017'),
('2/1/2017'),
('3/1/2017'),
('4/1/2017'),
('5/1/2017')
declare #YearParam int = 2017
declare #minMonthParam int = 2
declare #maxMonthParam int = 5
select
DateColumn
FROM #table1
where
(datepart(year,DateColumn) = #YearParam or datepart(year,DateColumn) = #YearParam-1)
and
(datepart(month,DateColumn) >= #minMonthParam and datepart(month,DateColumn) <= #maxMonthParam)
Attendence
(
Stu_id int
Att_Id int
Att_Date datetime
Att_Num numeric(15,5)
)
This table basically contains attendence records. I am trying to find the logic to enter the rows for missing dates from 1 Jan 2012 till today.
Assume there is a single attendence record for this period row (1,1,'2012-05-06',1.20000). Then I would like to insert rows for each day from 1 Jan 2012 till today except the existing date with the same values for all the fields except the date field which should be the actual date.
I am trying to bulk insert all the rows but don't know how would I adjust the date field
and check for the existing date.
Thanks.
Try a stored procedure which loops through the dates.
Or better yet, make a dates table and select from that. This will be much faster. Something like:
INSERT INTO Attendence (Stu_id, Att_Id, Att_Date, Att_Num)
SELECT a.Stu_id, a.Att_Id, d.TheDate, a.Att_Num
FROM Attendence a
INNER JOIN Dates d ON d.TheDate BETWEEN '2012-01-01' AND GETDATE()
AND d.TheDate <> a.Att_Date
I would use the DateDiff function to figure out the amount of days inbetween the date in the function and the date in question. Make a DateTime variable and give it the value of 1 Jan 2012. Then set up a while loop that loops the amount of days from the DateDiff function.
In psuedo, the while loop would look something like this.
#DaysTill = DateDiff(days, 1/1/2012, #SomeDate)
While #DaysTill>0
##Check = Select Count(Att_Date) From Attendance where AttDate = DateAdd(days, #DaysTill, Jan 1st 2012)
IF ##Check = 0 THEN Insert Into Attendance VALUES #Stu, #Id, DateAdd(days, #DaysTill, Jan 1st 2012), #numeric
#DaysTill = #DaysTill - 1
END
The main things are understanding DateAdd and DateDiff. After that everything becomes relatively simple.
What's the easiest way to update a table that contains a DATETIME column on TSQL with RANDOM value between 2 dates?
I see various post related to that but their Random values are really sequential when you ORDER BY DATE after the update.
Assumptions
First assume that you have a database containing a table with a start datetime column and a end datetime column, which together define a datetime range:
CREATE DATABASE StackOverflow11387226;
GO
USE StackOverflow11387226;
GO
CREATE TABLE DateTimeRanges (
StartDateTime DATETIME NOT NULL,
EndDateTime DATETIME NOT NULL
);
GO
ALTER TABLE DateTimeRanges
ADD CONSTRAINT CK_PositiveRange CHECK (EndDateTime > StartDateTime);
And assume that the table contains some data:
INSERT INTO DateTimeRanges (
StartDateTime,
EndDateTime
)
VALUES
('2012-07-09 00:30', '2012-07-09 01:30'),
('2012-01-01 00:00', '2013-01-01 00:00'),
('1988-07-25 22:30', '2012-07-09 00:30');
GO
Method
The following SELECT statement returns the start datetime, the end datetime, and a pseudorandom datetime with minute precision greater than or equal to the start datetime and less than the second datetime:
SELECT
StartDateTime,
EndDateTime,
DATEADD(
MINUTE,
ABS(CHECKSUM(NEWID())) % DATEDIFF(MINUTE, StartDateTime, EndDateTime) + DATEDIFF(MINUTE, 0, StartDateTime),
0
) AS RandomDateTime
FROM DateTimeRanges;
Result
Because the NEWID() function is nondeterministic, this will return a different result set for every execution. Here is the result set I generated just now:
StartDateTime EndDateTime RandomDateTime
----------------------- ----------------------- -----------------------
2012-07-09 00:30:00.000 2012-07-09 01:30:00.000 2012-07-09 00:44:00.000
2012-01-01 00:00:00.000 2013-01-01 00:00:00.000 2012-09-08 20:41:00.000
1988-07-25 22:30:00.000 2012-07-09 00:30:00.000 1996-01-05 23:48:00.000
All the values in the column RandomDateTime lie between the values in columns StartDateTime and EndDateTime.
Explanation
This technique for generating random values is due to Jeff Moden. He wrote a great article on SQL Server Central about data generation. Read it for a more thorough explanation. Registration is required, but it's well worth it.
The idea is to generate a random offset from the start datetime, and add the offset to the start datetime to get a new datetime in between the start datetime and the end datetime.
The expression DATEDIFF(MINUTE, StartDateTime, EndDateTime) represents the total number of minutes between the start datetime and the end datetime. The offset must be less than or equal to this value.
The expression ABS(CHECKSUM(NEWID())) generates an independent random positive integer for every row. The expression can have any value from 0 to 2,147,483,647. This expression mod the first expression gives a valid offset in minutes.
The epxression DATEDIFF(MINUTE, 0, StartDateTime) represents the total number of minutes between the start datetime and a reference datetime of 0, which is shorthand for '1900-01-01 00:00:00.000'. The value of the reference datetime does not matter, but it matters that the same reference date is used in the whole expression. Add this to the offset to get the total number of minutes between the reference datetime.
The ecapsulating DATEADD function converts this to a datetime value by adding the number of minutes produced by the previous expression to the reference datetime.
You can use RAND for this:
select cast(cast(RAND()*100000 as int) as datetime)
from here
Sql-Fiddle looks quite good: http://sqlfiddle.com/#!3/b9e44/2/0
I get to dust off my VBScript hat and write some classic ASP to query a SQL Server 2000 database.
Here's the scenario:
I have two datetime fields called fieldA and fieldB.
fieldB will never have a year value that's greater than the year of fieldA
It is possible the that two fields will have the same year.
What I want is all records where fieldA >= fieldB, independent of the year. Just pretend that each field is just a month & day.
How can I get this? My knowledge of T-SQL date/time functions is spotty at best.
You may want to use the built in time functions such as DAY and MONTH. e.g.
SELECT * from table where
MONTH(fieldA) > MONTH(fieldB) OR(
MONTH(fieldA) = MONTH(fieldB) AND DAY(fieldA) >= DAY(fieldB))
Selecting all rows where either the fieldA's month is greater or the months are the same and fieldA's day is greater.
select *
from t
where datepart(month,t.fieldA) >= datepart(month,t.fieldB)
or (datepart(month,t.fieldA) = datepart(month,t.fieldB)
and datepart(day,t.fieldA) >= datepart(day,t.fieldB))
If you care about hours, minutes, seconds, you'll need to extend this to cover the cases, although it may be faster to cast to a suitable string, remove the year and compare.
select *
from t
where substring(convert(varchar,t.fieldA,21),5,20)
>= substring(convert(varchar,t.fieldB,21),5,20)
SELECT *
FROM SOME_TABLE
WHERE MONTH(fieldA) > MONTH(fieldB)
OR ( MONTH(fieldA) = MONTH(fieldB) AND DAY(fieldA) >= DAY(fieldB) )
I would approach this from a Julian date perspective, convert each field into the Julian date (number of days after the first of year), then compare those values.
This may or may not produce desired results with respect to leap years.
If you were worried about hours, minutes, seconds, etc., you could adjust the DateDiff functions to calculate the number of hours (or minutes or seconds) since the beginning of the year.
SELECT *
FROM SOME_Table
WHERE DateDiff(d, '1/01/' + Cast(DatePart(yy, fieldA) AS VarChar(5)), fieldA) >=
DateDiff(d, '1/01/' + Cast(DatePart(yy, fieldB) AS VarChar(5)), fieldB)
Temp table for testing
Create table #t (calDate date)
Declare #curDate date = '2010-01-01'
while #curDate < '2021-01-01'
begin
insert into #t values (#curDate)
Set #curDate = dateadd(dd,1,#curDate)
end
Example of any date greater than or equal to today
Declare #testDate date = getdate()
SELECT *
FROM #t
WHERE datediff(dd,dateadd(yy,1900 - year(#testDate),#testDate),dateadd(yy,1900 - year(calDate),calDate)) >= 0
One more example with any day less than today
Declare #testDate date = getdate()
SELECT *
FROM #t
WHERE datediff(dd,dateadd(yy,1900 - year(#testDate),#testDate),dateadd(yy,1900 - year(calDate),calDate)) < 0