Changing the output of Getdate - sql-server

Is it possible to deceive SQL Server to return a different date on GetDate() without actually changing the machine date?
This would be great, since we have a database with old data and I'm trying to test some queries that use getdate().
I can change my machine date but that brings some other problems with other applications...
Any tips?
Thanks!

According to the documentation for getdate():
This value is derived from the
operating system of the computer on
which the instance of SQL Server is
running.
Since it's derived from the OS, I don't think you can change it separately.

You can always wrap GetDate() in a custom function and use that everywhere, although it's not an optimal solution.

No, there is not much you can do other than something like this:
SELECT GETDATE()-7 --get date time 7 days ago

SELECT DATEADD(dd, -7, GETDATE())

One approach is to have an optional fake clock.
Create a single row table (I usually call it dbo.System cos I usually have a number of global parameter values) with a column I call mine CurrentMoment which is datetime2 NULL (so the value can be NULL or a datetime).
Create a function to replace GetDate()
CREATE OR ALTER FUNCTION [dbo].GetDate
RETURNS datetime2
AS
BEGIN
RETURN ISNULL((SELECT CurrentMoment FROM dbo.System), SYSDATETIME());
END
GO
-- Yes the above returns a more accurate clock than GETDATE().
Replace ALL references to GETDATE() with dbo.GetDate() - This does require a small change to existing scripts.
With System.CurrentMoment set to NULL all works as normal, real time. But set a value and you have a fake clock, you have to update it as tests/demo proceed.
If you are concerned about performance, you can modify the function so it either returns SYSDATETIME() or the fake datetime as preferred. But I have not found a performance issue worth worrying about.
Alternatively you could have a column in System which is an offset to the current time, and subtract it from SYSDATETIME() when the function is called. That way the value will move on between function calls.

Related

PB Select TODAY() Into :var From DUMMY

When I get TODAY in SELECT in PB, it returns 1900/1/1
date var
Select TODAY() Into :var From DUMMY
But when I assign to variable TODAY(), it works as expected
date var
var = today()
I use MS SQL Server 2016 and PowerBuilder 12.5.
I've supposed that the problem is in different date formats, but I have changed date format at my Windows locale in the way, that PB TODAY() returns 2018-10-08 and MSSQL GetDate() returns 2018-10-08 18:25:23.207
So date parts have the same formats.
The problem is not in DUMMY table since I have created MS SQL DUMMY table and inserted 1 row in it.
Also I'm wondering if there are any difference in SELECT TODAY() and var = TODAY()?
I suppose that 1st variant returns MS SQL server time but 2nd returns local time. Is not is?
Try below SQL.
Select getdate() into :var From DUMMY;
You provided your own answer: Today() is a PowerScript function, GetDate() is the function on MS SQL. If you’re executing SQL, it needs to be a valid SQL statement for the server you’re executing against (except for the INTO :var part), and can’t include a PowerScript function.
Two other things:
“FROM DUMMY” is an Oracle thing, and I’m pretty sure it won’t work on MS. (You’re capturing your error codes after executing the SQL, right?)
I won’t say this is likely a critical problem, but as you point out, GetDate returns a datetime; I’d recommend that as your data type for the capture variable.
And yes, GetDate() will be your server’s date/time, Today() will be based on the local workstation.
Good luck.

SQL Server 2008R2 alter GETDATE result as a default value

Is there a way to alter the outcome of getdate() while still using it as a default value? E.g. being able to plus or minus x number of hours.
The situation:
a German hosted server (GMT+2) with some end users in Australia (GMT+10). One column is using the default getdate() value therefore is inserting German time. Some code is generating a DateTime based on Australia time so there are 8 hours difference.
The objective:
For several good reasons the aim is to handle this on the database and not touch application code. I would like to add 8 hours onto the German getdate() default database value....... or handle this some other way on the database
you can use default value using DATEADD() function to add 8 hours to the date:
create table dbo.foo
(
dateColumn datetime default (dateadd(hour,8,getdate()))
)
I don't see any such option and it is little dangerous too. You can create a function with the same name GETDATE in your database, but that would require you to prefix with dbo(or schema name) while calling the function.
So, you may need to write your own function and make use of GETUTCDATE() and add delta according to timezone.

Simulate current date on a SQL Server instance?

Is it possible to change the datetime for a particular database on SQL Server?
Is it tied to the operating system's date/time?
We wish to simulate a future datetime for testing purposes i.e. so the GETDATE() returns a date in the future.
It's got to be in a semi-production (staging) environment so unfortunately changing the OS date / time isn't an option for us.
In an ideal world we'd spin up a virtual server, but also not really an option at the moment.
As stated, by others, No.
A really hacky workaround, would be be to write your own function to return the date you want and have it return GETDATE() when you're done testing, and call that function instead. There's probably some slight overhead in doing this, but it'll do what you need.
Unfortunately it is tied to the OS date and time. See here: http://msdn.microsoft.com/en-us/library/ms188383.aspx
This value is derived from the operating system of the computer on
which the instance of SQL Server is running.
You can always use this and adjust accordingly:
SELECT getutcdate()
Please see below for more information
StackOverflow Question
But there is no way to change the results from a GETDATE() without changing the server's date.
Added:
You could do a EXEC xp_cmdshell 'DATE 10/10/2011' if you wish... but it's not advised.
Another workaround I've had some success with is to add an INSTEAD OF trigger to any table where a GETDATE() value is being inserted and modify it there e.g.:
ALTER TRIGGER [dbo].[AccountsPayableReceivable_trg_i] ON [dbo].[AccountsPayableReceivable]
INSTEAD OF INSERT
AS
SET NOCOUNT ON
SELECT *
INTO #tmp_ins_AccountsPayableReceivable
FROM INSERTED
UPDATE #tmp_ins_AccountsPayableReceivable
SET dtPaymentMade = '01-Jan-1900'
WHERE dtPaymentMade between dateadd(ss, -5, getdate()) and dateadd(ss, +5, getdate())
INSERT INTO AccountsPayableReceivable
SELECT *
from #tmp_ins_AccountsPayableReceivable
(Incidentally, the where clause is there because my test script autogenerates these triggers, adding an update for every datetime column, so I only want to update those that look like they are being inserted with a GETDATE() value.)
I believe you can create a user function that would do the calculation for you and apply that.
http://msdn.microsoft.com/en-us/library/ms186755.aspx
Also, it can be used as the default value for a column.
Bind a column default value to a function in SQL 2005

How to convert SQL Server's timestamp column to datetime format

As SQL Server returns timestamp like 'Nov 14 2011 03:12:12:947PM', is there some easy way to convert string to date format like 'Y-m-d H:i:s'.
So far I use
date('Y-m-d H:i:s',strtotime('Nov 14 2011 03:12:12:947PM'))
SQL Server's TIMESTAMP datatype has nothing to do with a date and time!
It's just a hexadecimal representation of a consecutive 8 byte integer - it's only good for making sure a row hasn't change since it's been read.
You can read off the hexadecimal integer or if you want a BIGINT. As an example:
SELECT CAST (0x0000000017E30D64 AS BIGINT)
The result is
400756068
In newer versions of SQL Server, it's being called RowVersion - since that's really what it is. See the MSDN docs on ROWVERSION:
Is a data type that exposes automatically generated, unique binary numbers within a database. rowversion is generally used as a mechanism
for version-stamping table rows. The
rowversion data type is just an incrementing number and does not
preserve a date or a time. To record a date or time, use a datetime2
data type.
So you cannot convert a SQL Server TIMESTAMP to a date/time - it's just not a date/time.
But if you're saying timestamp but really you mean a DATETIME column - then you can use any of those valid date formats described in the CAST and CONVERT topic in the MSDN help. Those are defined and supported "out of the box" by SQL Server. Anything else is not supported, e.g. you have to do a lot of manual casting and concatenating (not recommended).
The format you're looking for looks a bit like the ODBC canonical (style = 121):
DECLARE #today DATETIME = SYSDATETIME()
SELECT CONVERT(VARCHAR(50), #today, 121)
gives:
2011-11-14 10:29:00.470
SQL Server 2012 will finally have a FORMAT function to do custom formatting......
The simplest way of doing this is:
SELECT id,name,FROM_UNIXTIME(registration_date) FROM `tbl_registration`;
This gives the date column atleast in a readable format.
Further if you want to change te format click here.
Using cast you can get date from a timestamp field:
SELECT CAST(timestamp_field AS DATE) FROM tbl_name
Works fine, except this message:
Implicit conversion from data type varchar to timestamp is not allowed. Use the CONVERT function to run this query
So yes, TIMESTAMP (RowVersion) is NOT a DATE :)
To be honest, I fidddled around quite some time myself to find a way to convert it to a date.
Best way is to convert it to INT and compare. That's what this type is meant to be.
If you want a date - just add a Datetime column and live happily ever after :)
cheers mac
My coworkers helped me with this:
select CONVERT(VARCHAR(10), <tms_column>, 112), count(*)
from table where <tms_column> > '2012-09-10'
group by CONVERT(VARCHAR(10), <tms_column>, 112);
or
select CONVERT(DATE, <tms_column>, 112), count(*)
from table where <tms_column> > '2012-09-10'
group by CONVERT(DATE, <tms_column>, 112);
"You keep using that word. I do not think it means what you think it means."
— Inigo Montoya
The timestamp has absolutely no relationship to time as marc_s originally said.
declare #Test table (
TestId int identity(1,1) primary key clustered
,Ts timestamp
,CurrentDt datetime default getdate()
,Something varchar(max)
)
insert into #Test (Something)
select name from sys.tables
waitfor delay '00:00:10'
insert into #Test (Something)
select name from sys.tables
select * from #Test
Notice in the output that Ts (hex) increments by one for each record, but the actual time has a gap of 10 seconds. If it were related to time then there would be a gap in the timestamp to correspond with the difference in the time.
for me works:
TO_DATE('19700101', 'yyyymmdd') + (TIME / 24 / 60 / 60)
(oracle DB)
Robert Mauro has the correct comment. For those who know the Sybase origins, datetime was really two separate integers, one for date, one for time, so timestamp aka rowversion could just be considered the raw value captured from the server. Much faster.
After impelemtation of conversion to integer
CONVERT(BIGINT, [timestamp]) as Timestamp
I've got the result like
446701117
446701118
446701119
446701120
446701121
446701122
446701123
446701124
446701125
446701126
Yes, this is not a date and time, It's serial numbers
Why not try FROM_UNIXTIME(unix_timestamp, format)?
I had the same problem with timestamp eg:'29-JUL-20 04.46.42.000000000 PM'. I wanted to turn it into 'yyyy-MM-dd' format. The solution that finally works for me is
SELECT TO_CHAR(mytimestamp, 'YYYY-MM-DD') FROM mytable;
I will assume that you've done a data dump as insert statements, and you (or whoever Googles this) are attempting to figure out the date and time, or translate it for use elsewhere (eg: to convert to MySQL inserts). This is actually easy in any programming language.
Let's work with this:
CAST(0x0000A61300B1F1EB AS DateTime)
This Hex representation is actually two separate data elements... Date and Time. The first four bytes are date, the second four bytes are time.
The date is 0x0000A613
The time is 0x00B1F1EB
Convert both of the segments to integers using the programming language of your choice (it's a direct hex to integer conversion, which is supported in every modern programming language, so, I will not waste space with code that may or may not be the programming language you're working in).
The date of 0x0000A613 becomes 42515
The time of 0x00B1F1EB becomes 11661803
Now, what to do with those integers:
Date
Date is since 01/01/1900, and is represented as days. So, add 42,515 days to 01/01/1900, and your result is 05/27/2016.
Time
Time is a little more complex. Take that INT and do the following to get your time in microseconds since midnight (pseudocode):
TimeINT=Hex2Int(HexTime)
MicrosecondsTime = TimeINT*10000/3
From there, use your language's favorite function calls to translate microseconds (38872676666.7 µs in the example above) into time.
The result would be 10:47:52.677
Some of them actually does covert to a date-time from SQL Server 2008 onwards.
Try the following SQL query and you will see for yourself:
SELECT CAST (0x00009CEF00A25634 AS datetime)
The above will result in 2009-12-30 09:51:03:000 but I have encountered ones that actually don't map to a date-time.
Not sure if I'm missing something here but can't you just convert the timestamp like this:
CONVERT(VARCHAR,CAST(ZEIT AS DATETIME), 110)

Why is a T-SQL variable comparison slower than GETDATE() function-based comparison?

I have a T-SQL statement that I am running against a table with many rows. I am seeing some strange behavior. Comparing a DateTime column against a precalculated value is slower than comparing each row against a calculation based on the GETDATE() function.
The following SQL takes 8 secs:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
GO
DECLARE #TimeZoneOffset int = -(DATEPART("HH", GETUTCDATE() - GETDATE()))
DECLARE #LowerTime DATETIME = DATEADD("HH", ABS(#TimeZoneOffset), CONVERT(VARCHAR, GETDATE(), 101) + ' 17:00:00')
SELECT TOP 200 Id, EventDate, Message
FROM Events WITH (NOLOCK)
WHERE EventDate > #LowerTime
GO
This alternate strangely returns instantly:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
GO
SELECT TOP 200 Id, EventDate, Message
FROM Events WITH (NOLOCK)
WHERE EventDate > GETDATE()-1
GO
Why is the second query so much faster?
EDITED: I updated the SQL to accurately reflect other settings I am using
After doing a lot of reading and researching, I've discovered the issue here is parameter sniffing. Sql Server attempts to determine how best to use indexes based on the where clause, but in this case it isnt doing a very good job.
See the examples below :
Slow version:
declare #dNow DateTime
Select #dNow=GetDate()
Select *
From response_master_Incident rmi
Where rmi.response_date between DateAdd(hh,-2,#dNow) AND #dNow
Fast version:
Select *
From response_master_Incident rmi
Where rmi.response_date between DateAdd(hh,-2,GetDate()) AND GetDate()
The "Fast" version runs around 10x faster than the slow version. The Response_Date field is indexed and is a DateTime type.
The solution is to tell Sql Server how best to optimise the query. Modifying the example as follows to include the OPTIMIZE option resulted in it using the same execution plan as the "Fast Version". The OPTMIZE option here explicitly tells sql server to treat the local #dNow variable as a date (as if declaring it as DateTime wasnt enough :s )
Care should be taken when doing this however because in more complicated WHERE clauses you could end up making the query perform worse than Sql Server's own optimisations.
declare #dNow DateTime
SET #dNow=GetDate()
Select ID, response_date, call_back_phone
from response_master_Incident rmi
where rmi.response_date between DateAdd(hh,-2,#dNow) AND #dNow
-- The optimizer does not know too much about the variable so assumes to should perform a clusterd index scann (on the clustered index ID) - this is slow
-- This hint tells the optimzer that the variable is indeed a datetime in this format (why it does not know that already who knows)
OPTION(OPTIMIZE FOR (#dNow = '99991231'));
The execution plans must be different, because SQL Server does not evaluate the value of the variable when creating the execution plan in execution time. So, it uses average statistics from all the different dates that can be stored in the table.
On the other hand, the function getdate is evaluated in execution time, so the execution plan is created using statistics for that specific date, which of course, are more realistic that the previous ones.
If you create a stored procedure with #LowerTime as a parameter, you will get better results.

Resources