I am using MSSQL SERVER. The questions I am asking might be silly but I want some valid answers. So here is my question:
I have a table with some columns. I have taken default in some column like 0 (for INT column), GETDATE() (for DATE column). Now one of my colleague said that taking Getdate() as default will increase overhead so better to pass datetime by INSERT statement. Is it true?
Is it not applicable to 0 or 1 (for INT column)?
How does it create overhead?
int default 0 or 1 is a value like hardcode.
but, getdate () like function to know the date on the computer server of SQL Server.
so, when the insert statement, the column with the default getdate () will look for the value prior to the server computer before the command insert is run.
Related
I set up a table yesterday with the following code. the code ran with no error messages reported and the table appeared correctly set up in object explorer.
Create Table PriceTable
(Airport_IACO_Code Varchar (4) NOT NULL,
Airline_IACO_Code Varchar (3) NOT NULL,
FlightDate Date NOT NULL Default Getdate(),
DepTime Time NOT NULL Default DATEADD(hour, 6, GETDATE()),
Price Smallmoney,
RouteDiscontinuedOrCommences Varchar (15),
)
GO
However on checking the table today the FlightDate which has the Getdate() default is showing yesterdays date
and
the the DepTime column which has the DateAdd Default is showing an incorrect time of 18:45:02. the current time as I am writing this is 11.04.
Does anyone know what is wrong.
Thanks in advance for any help offered.
You may find the handling of defaults a bit counter-intuitive in SQL Server. The syntax is:
DEFAULT constant_expression
It so happens that SQL Server extends the definition of constant_expression to include non-deterministic scalar functions, such as getdate(). These are functions that return a different value each time they are called, even with the same arguments. The definition in the documentation is:
Only a constant value, such as a character string; a scalar function
(either a system, user-defined, or CLR function); or NULL can be used
as a default.
However, SQL Server does not extend the definition to expressions of such functions. Instead, the expression is evaluated when the table is created and a constant value is inserted.
Unfortunately, one way to accomplish what you want is using a trigger. Alternatively, you could leave the value as NULL and create a computed column to calculate the date six hours hence:
create table . . .
_DepTime time,
DepTime as (cast(dateadd(hour, 6 _DepTime) as time) )
I have two almost identical SELECT statements. I am running them on a SQL Server 2012 with server collation Danish_Norwegian_CI_AS, and database collation Danish_Norwegian_CI_AS. The database runs in compatibility level set to SQL Server 2005 (90).
I run both of the queries on the same client via a SQL Server 2012 Management Studio. The client is a Windows 8.1 laptop.
The puzzling part is, although the statements are almost identical, the resultset is different as shown below (one returns 24-hour format time, the other with AM / PM, which gets truncated tpo P in this case). The only difference is the 'and 1<>2' expression in WHERE clause. I looked up and down, searched in google, digged as deep as I could, cannot find an explanation. Tried COLLATE to force conversion, did not help. If I use 108 to force formatting in CONVERT call, then the resultsets are alike. But not knowing the reason why this does not work is eating me alive.
Issue recreated on SqlFiddle, SQL Server 2008:
http://sqlfiddle.com/#!3/a97f8/1
Have someone an explain for this?
The SQL DDL and statements after results can be used to recreate the issue. The script creates a table with two columns, inserts some rows, and makes two selects.
On my machine the sql without the 1<>2 expression returns:
Id StartTime
----------- ---------
2 2:00P
2 2:14P
The sql with the 1<>2 expression returns:
Id StartTime
----------- ---------
2 14:00
2 14:14
if NOT EXISTS (Select * from sysobjects where name = 'timeVarchar')
begin
create table timeVarchar (
Id int not null,
timeTest datetime not null
)
end
if not exists (select * from timeVarchar)
begin
-- delete from timeVarchar
print 'inserting'
insert into timeVarchar (Id, timeTest) values (1, '2014-04-09 11:37:00')
insert into timeVarchar (Id, timeTest) values (2, '1901-01-01 14:00:00')
insert into timeVarchar (Id, timeTest) values (3, '2014-04-05 15:00:00')
insert into timeVarchar (Id, timeTest) values (2, '1901-01-01 14:14:14')
end
select
Id,
convert ( varchar(5), convert ( time, timeTest)) as 'StartTime'
from
timeVarchar
where
Id = 2
select
Id,
convert ( varchar(5), convert ( time, timeTest)) as 'StartTime'
from
timeVarchar
where
Id = 2 and
1 <> 2
I can't answer why this is happening (at least not at the moment), but setting the conversion format explicitly does solve the issue:
select Id,
convert (varchar(5), convert (time, timeTest), 14) as "StartTime"
from timeVarchar
where Id = 2;
select Id,
convert (varchar(5), convert (time, timeTest), 14) as "StartTime"
from timeVarchar
where Id = 2
and 1 <> 2;
Going through the execution plan, the two queries end up very different indeed.
The first one passes 2 as a parameter and (!) does CONVERT_IMPLICIT of the value. The second one passes it as a part of the query itself!
In the end, the actual query that gets to run in the first case actually explicitly does CONVERT(x, y, 0). For US locale, this is not a problem, since 0 is the invariant (~US) culture. But outside of the US, you're suddenly using 0 instead of e.g. 4 (for Germany).
So, definitely, one thing to take from this is that queries that look very much alike could execute completely differently.
The second thing is - always use convert with a specific format. The defaults don't seem to be entirely reliable.
EDIT: Ah, finally fished the thing out of the MSDN:
http://msdn.microsoft.com/en-us/library/ms187928.aspx
In earlier versions of SQL Server, the default style for CAST and
CONVERT operations on time and datetime2 data types is 121 except when
either type is used in a computed column expression. For computed
columns, the default style is 0. This behavior impacts computed
columns when they are created, used in queries involving
auto-parameterization, or used in constraint definitions.
Since the first query is invoked as a parametrized query, it gets the default style 0, rather than 121. This behaviour is fixed in compatibility level 110+ (i.e. SQL SERVER 2012+) - on those servers, the default is always 121.
It seems the problem is solved in SQL2012
see this link
http://sqlfiddle.com/#!6/a97f8/4
p.s Your mentioned url on sqlfiddle is running on SQL2008
requirement is, both field must be equal, what would you do
declare #var datetime
set #var = getdate()
update table set f1=#var,f2=#var
or simply
update table set f1=getdate(),f2=getdate()
Definitely the first way, because 2 calls to getdate() will most likely return different values.
Original Answer: getdate() seems to be like rand() and only evaluated once in a query. This query took more than a minute to return and all getdate()s are the same.
select getdate()
from sys.objects s1, sys.objects s2, sys.objects s3
Updated But when I looked at the query plan for an update of 2 different columns I could see the compute scalar operator was calling getdate() twice.
I tested doing an update with rand()
CREATE TABLE #t(
[f1] [float] NULL,
[f2] [float] NULL,
)
insert into #t values (1,1)
insert into #t values (2,2)
insert into #t values (3,3)
update #t set f1=rand(),f2=rand()
select * from #t
That Gives
f1 f2
---------------------- ----------------------
0.54168308978257 0.574235819564939
0.54168308978257 0.574235819564939
0.54168308978257 0.574235819564939
Actually, this depends on the version of SQL.
GetDate() was a deterministic function prior to SQL 2005. The answer returned was the same value for the duration of the statement.
In SQL 2005 (and onwards), Getdate() is non-deterministic, which means every time you call it you will get a different value.
Since both GetDate() functions will be evaluated before the update starts, IMO they will come back with the same value.
Not knowing the size of your table and partitions and the load on your server, I would go with option #1
I'm going to go with something other than performance: readability / communication of intent.
Along those lines, option one is probably better. You are, in effect, telling future developers "I am explicitly setting f1 and f2 to the same DateTime." If the requirements change in the future, and (for some reason) f1 and f2 have to be updated at separate times (or something changes and they get evaluated at different times), you still have the same datetime for both.
In option two, all you're saying is that f1 and f2 have to be updated with the current time of whenever their update operations run. Again, if something changes in your requirements and they have to be evaluated in separate statements for some reason, now they won't necessarilly be the same value any more.
While updating a datatime column in a table from another table, i noticed that mnilliseconds value are not shown.. instead it is rounded and the value is updated to nearest seconds.
Example :
Original Value: 2008-06-26 14:06:36.643
Updated Value : 2008-06-26 14:07:00
Please help me getting the actual value including milliseconds
In the case where you're doing a straight update of a datetime in one table with one from another table (i.e. no fiddling with the value), then it sounds like the datatype in the table being updated is not the same.
i.e. in SQL Server world, it could be that you are using SMALLDATETIME column in the table being updated, but a DATETIME field in the table being copied from. SMALLDATETIME is only accurate to the second and so would show this behaviour
In SQL Server;
SELECT CAST('2008-06-26 14:06:36.643' AS SMALLDATETIME)
> 2008-06-26 14:07:00
So the destination table column is probably SMALLDATETIME (or your casting in the query).
The question
Is it possible to ask SSIS to cast a value and return NULL in case the cast is not allowed instead of throwing an error ?
My environment
I'm using Visual Studio 2005 and Sql Server 2005 on Windows Server 2003.
The general context
Just in case you're curious, here is my use case. I have to store data coming from somewhere in a generic table (key/value structure with history) witch contains some sort of value that can be strings, numbers or dates. The structure is something like this :
table Values {
Id int,
Date datetime, -- for history
Key nvarchar(50) not null,
Value nvarchar(50),
DateValue datetime,
NumberValue numeric(19,9)
}
I want to put the raw value in the Value column and try to put the same value
in the DateValue column when i'm able to cast it to Datetime
in the NumberValue column when i'm able to cast it to a number
Those two typed columns would make all sort of aggregation and manipulation much easier and faster later.
That's it, now you know why i'm asking this strange question.
============
Thanks in advance for your help.
You could also try a Derived Column component and test the value of the potential date/number field or simply cast it and redirect any errors as being the NULL values for these two fields.
(1) If you just simply cast the field every time with a statement like this in the Derived Column component: (DT_DATE)[MYPOTENTIALDATE] - you can redirect the rows that fail this cast and manipulate the data from there.
OR
(2) You can do something like this in the Derived Column component: ISNULL([MYPOTENTIALDATE]) ? '2099-01-01' : (DT_DATE)[MYPOTENTIALDATE]. I generally send through '2099-01-01' when a date is NULL rather than messing with NULL (works better with Cubes, etc).
Of course (2) won't work if the [MYPOTENTIALDATE] field comes through as other things other than a DATETIME or NULL, i.e., sometimes it is a word like "hello".
Those are the options I would explore, good luck!
In dealing with this same sort of thing I found the error handling in SSIS was not specific enough. My approach has been to actually create an errors table, and query a source table where the data is stored as varchar, and log errors to the error table with something like the below. I have one of the below statements for each column, because it was important for me to know which column failed. Then after I log all errors, I do a INSERT where I select those records in SomeInfo that do not have an errors. In your case you could do more advanced things based on the ColumnName in the errors table to insert default values.
INSERT INTO SomeInfoErrors
([SomeInfoId]
,[ColumnName]
,[Message]
,FailedValue)
SELECT
SomeInfoId,
'PeriodStartDate',
'PeriodStartDate must be in the format MM/DD/YYYY',
PeriodStartDate
FROM
SomeInfo
WHERE
ISDATE(PeriodStartDate) = 0 AND [PeriodStartDate] IS NOT NULL;
Tru using a conditional split and have the records where the data is a date go along one path and the other go along a different path where they are updated to nullbefore being inserted.