I have this SQL statement to create a table that stores the JSON string data and the event time found in that JSON string.
CREATE TABLE [dbo].[EventLog]
(
[EventID] INT NOT NULL IDENTITY(1,1),
[EventTime] AS CAST(JSON_VALUE(RawEvent, '$.EventTime') AS DATETIME ) PERSISTED,
[RawEvent] NVARCHAR(MAX) NOT NULL
)
However I get the following error below when I run this, I assume SQL Server does not know if the value fits DATETIME? is there a way to get this column defined?
Msg 4936, Level 16, State 1, Line 26
Computed column 'EventTime' in table 'Event' cannot be persisted because the column is non-deterministic.
You can use CONVERT with dates and have deterministic behavior as long as you specify certain date styles. As per the docs here, with the most common JavaScript date formats (since you are converting from JSON), you can use style 126 or 127, which are ISO8601 and ISO8601 with time zone. Your table, then, could be specified like this:
CREATE TABLE [dbo].[EventLog]
(
[EventID] INT NOT NULL IDENTITY(1,1),
[EventTime] AS CONVERT(DATETIME, JSON_VALUE(RawEvent, '$.EventTime'), 126) PERSISTED,
[RawEvent] NVARCHAR(MAX) NOT NULL
)
Alas, this is explained in the documentation:
CAST Deterministic unless used with datetime, smalldatetime, or sql_variant.
You may be able to parse the date and reconstruct the value using datefromparts() or datetimefromparts().
Related
I'm trying to filter some data - I have a column which looks like it is mainly smallint/int. Is there anyway I can run a where statement to say where not int or where not small int??
Microsoft SQL Server manager.
If you want a where clause that can tell you if the column contain information that can't be converted to int or smallint, you can use try_cast:
SELECT *
FROM <TableName>
WHERE TRY_CAST(<ColumnName> AS Int) IS NULL
You can change the int to smallint to get values that can't be converted to smallint but might be convertible to int.
Don't forget to replace <TableName> and <ColumnName> to the names of the relevant table and column.
The Try_Cast built in function will return null if the value in <ColumnName> is null or if it can't be converted to int (and since all smallint values can also be converted to int, it also can't be converted to smallint).
I am relatively new to SQL Server so I was wondering how to convert the data type from varchar to date format? I have a few thousands records so I need a query to help to convert the varchar to date in a single query.
I have the date in this format: yyyymmdd, in varchar(8) and I want to convert this into yyyymmdd, in date format.
Is there any queries to help me with this?
For various conversions between VARCHAR and DATETIME have a look at this link.
Actually in your case, since your VARCHAR is in yyyymmdd format, you could just:
convert(datetime, YourVarcharDateField, 112)
Simply Use this Inbuilt CONVERT Function, and Check this Link for formatting Dates
-- Use 101 if you have divider in your date
SELECT convert(datetime, '2014-01-02',101) as [DateTime]
-- Use 112 if you don't have divider in your date
SELECT convert(datetime, '20140131',112) as [DateTime]
Edited:
UPDATE yourTable SET field = convert(datetime, 'yourFieldName',112)
--This will update all of your field regardless of any particular row
--If you want to update any particular set of rows use `WHERE` clause
if you have more various formats goto to the given link.
Data types can be converted either implicitly or explicitly.
Implicit conversions are not visible to the user. SQL Server automatically converts the data from one data type to another. For example, when a smallint is compared to an int, the smallint is implicitly converted to int before the comparison proceeds.
Explicit conversions use the CAST or CONVERT functions.
The CAST and CONVERT functions convert a value (a local variable, a column, or another expression) from one data type to another
convert(datetime, '2013-05-04',101)
CAST ( expression AS data_type )
ALTER TABLE [dbo].[table] ADD ConvertedDate Date
UPDATE [dbo].[SysData] SET ConvertedDate = CAST(VarCharDate as Date)
ALTER TABLE [dbo].[table] DROP COLUMN VarCharDate
Use CAST OR CONVERT function to convert string to date
Try this:
SELECT CAST('20140102' AS DATE) AS convertedDate;
SELECT CAST(colName AS DATE) AS convertedDate FROM tableA; -- Replace column name and table name
OR
SELECT CONVERT(DATE, '20140102', 112) AS convertedDate;
SELECT CONVERT(DATE, colName, 112) AS convertedDate FROM tableA; -- Replace column name and table name
OUTPUT of both queries:
|convertedDate|
|-------------|
|2014-01-02 |
In SQL SERVER, there are two types of built in conversion techniques.
Convert
Cast
Convert having its own defaults so it will be outdated in upgraded version of SQL SERVER
better make use of CAST Conversion technique
In your scenario.Already having the date with datatype of Varchar(8) trying to Convert into Date
Solve in systematic manner.
Adding the one new Column in the existing table.
Alter Table Table_name Add changedDataTypeDate Date
Update the values in varchar datatype to Date Datatype
UpDate Table_name Set ChangedDataTypeDate = CAST(OriginalDataTypeDate as Date)
Again change the new column name into old column name.
Sp_Rename 'Tablename.changedDataTypeDate','OriginalDataTypeDate','COLUMN'
Its done.
Based on u r requirement.
Alter Table customer Add Purchase_Changedtype Date
Update Customer set Purchase_changedtype = CAST(Purchase_date as Date)
(If u need Time also replace Datetime istead of Date)
Alter table Customer Drop column Purchase_date
Sp_Rename 'Customer.Purchase_ChangedType','Purchase_Date','Column'
I want to enter 30/10/1988 as the date to a DOB column in a table using a procedure
alter procedure addCustomer
#userName varchar(50),
#userNIC varchar(50),
#userPassword varchar(100),
#userDOB datetime,
#userTypeID int,
#userEmail varchar(50),
#userTelephone int,
#userAddress char(100),
#userCityID int,
#status int output
as
declare #userID int
declare #eid int
declare #tid int
declare #aid int
execute getLastRaw 'userID','tblUserParent', #userID output
insert into tblUserParent values (#userID, #userName, #userNIC, #userPassword, #userDOB, #userTypeID)
execute getLastRaw 'addressID','tblAddress', #aid output
insert into tblAddress values (#aid, #userAddress, #userID, #userCityID)
execute getLastRaw 'emailID','tblEmail', #eid output
insert into tblEmail values (#eid, #userEmail, #userID)
execute getLastRaw 'telephoneID','tblTelephoneNO', #tid output
insert into tblTelephoneNO values (#tid, #userTelephone , #userID)
insert into tblUserCustomer values (#userID, #eid , #tid, #aid)
...but it gives an error when i enter like this '30/10/1988'
Msg 8114, Level 16, State 5, Procedure addCustomer, Line 0 Error converting data type varchar to datetime.
...but when I enter like only the 30/10/1988
Incorrect syntax near '/'
How do I fix this?
If you would truly like to avoid the possibility of ambiguous dates based, then you should always enter it in one of the two unambiguous date formats Answer has already been selected and it's valid but I'm a believer in spreading the knowledge ;)
As noticed by #cloud and my post representing a younger, and less wise me with a link only answer, I'll pop the contents of the archive of Jamie Thompson's answer for unambiguous date formats in TSQL
tl;dr;
yyyy-MM-ddTHH24:mi:ss
yyyyMMdd HH24:mi:ss
One of the most commonly used data types in SQL Server is [datetime]
which unfortunately has some vagaries around how values get casted. A
typical method for defining a [datetime] literal is to write it as a
character string and then cast it appropriately. The cast syntax looks
something like this: DECLARE #dt NVARCHAR(19) = '2009-12-08 18:00:00';
SELECT CAST(#dt AS datetime);
Unfortunately in SQL Server 2005 the result of the cast operation may
be dependent on your current language setting. You can discover your
current language setting by executing: SELECT ##LANGUAGE To
demonstrate how your language setting can influence the results of a
cast take a look at the following code: ALTER DATABASE tempdb
SET COMPATIBILITY_LEVEL = 90 ; --Behave like SQL Server 2005
USE tempdb
GO
DECLARE #t TABLE (
dateString NVARCHAR(19)
);
INSERT #t (dateString)
VALUES ('2009-12-08 18:00:00') --'yyyy-MM-dd hh24:mi:ss'
, ('2009-12-08T18:00:00') --'yyyy-MM-ddThh24:mi:ss'
, ('20091208 18:00:00') --'yyyyMMdd hh24:mi:ss'
SET LANGUAGE french;
SELECT 'french' AS lang
, DATENAME(MONTH,q.[dt]) AS mnth
, q.[dt]
FROM (
SELECT CAST(dateString AS DATETIME) AS dt
FROM #t
)q;
SET LANGUAGE us_english;
SELECT 'us_english' AS lang
, DATENAME(MONTH,q.[dt]) AS mnth
, q.[dt]
FROM (
SELECT CAST(dateString AS DATETIME) AS dt
FROM #t
)q; We are taking the value which can be described in words as “6pm on 8th December 2009”, defining it in three different ways, then
seeing how the ##LANGUAGE setting can affect the results. Here are
those results: french language datetime Notice how the interpretation
of the month can change depending on ##LANGUAGE. If
##LANGUAGE=’french’ then the string '2009-12-08 18:00:00' is
interpreted as 12th August 2009 (‘août’ is French for August for those
that don’t know) whereas if ##LANGUAGE=’us_english’ it is interpreted
as 8th December 2009. Clearly this is a problem because the results of
our queries have a dependency on a server-level or connection-level
setting and that is NOT a good thing. Hence I recommend that you only
define [datetime] literals in one of the two unambiguous date formats:
yyyy-MM-ddTHH24:mi:ss yyyyMMdd HH24:mi:ss That was going to be the end
of this blog post but then I found out that this behaviour changed
slightly in SQL Server 2008. Take the following code (see if you can
figure out what the results will be before I tell you): ALTER
DATABASE tempdb
SET COMPATIBILITY_LEVEL = 100 ; --Behave like SQL Server 2008
GO
USE tempdb
GO
SET LANGUAGE french;
DECLARE #dt NCHAR(10) = '2009-12-08 18:00:00'; --Ambiguous date
format
SELECT CAST(#dt AS datetime) AS [ExplicitCast]
, DATENAME(MONTH,#dt) AS [MonthFromImplicitCast]
, DATENAME(MONTH,CAST(#dt AS datetime)) AS
[MonthFromExplicitCast]; Here we are doing three different things with
our nchar literal: explicitly cast it as a [datetime] extract the
month name from the char literal using the DATENAME function (which
results in an under-the-covers implicit cast) extract the month name
from the char literal using the DATENAME function after it has been
explicitly casted as a [datetime] Note that the compatibility level is
set to SQL Server 2008 and ##LANGUAGE=’french’. Here are the results:
image (Were you correct?) Let’s take a look at what is happening here.
The behaviour when we are explicitly casting as [datetime] hasn’t
changed, our nchar literal is still getting interpreted as 12th August
rather than 8th December when ##LANGUAGE=’french’. The
[MonthFromExplicitCast] field is interesting though, it seems as
though the implicit cast has resulted in the desired value of 8th
December. Why is that? To get the answer we can turn to BOL’s
description of the DATENAME function syntax: image The implicit cast
is not casting to [datetime] at all, it is actually casting to [date]
which is a new datatype in SQL Server 2008. The new date-related
datatypes in SQL Server 2008 (i.e. [date], [datetime2], [time],
[datetimeoffset]) disregard ##LANGUAGE and hence we get behaviour that
is more predictable and, frankly, better. These new behaviours for SQL
Server 2008 were unknown to me when I began this blog post so I have
learnt something in the course of authoring it, I hope it has helped
you too. No doubt someone somewhere is going to get nastily burnt by
this at some point, make sure that it isn’t you by always using
unambiguous date formats: yyyy-MM-ddTHH24:mi:ss yyyyMMdd HH24:mi:ss
regardless of which version you are on!
The following works in both SQL Server and MySql without ambiguity: yyyy-mm-dd, like so:
INSERT INTO TableName(DateColumn) VALUES ('1988-10-30');
...as an added benefit there's no question of whether it's a US or European style date on days like the fourth of March...
See if there is a culture setting that you can change to allow you to use dd/mm/yyyy. I believe it is expecting mm/dd/yyyy.
A potentially easy way around the problem is to use a date format with no ambiguity between mm/dd/yyyy and dd/mm/yyyy such as dd-mmm-yyyy, eg: 30-OCT-1988
Select
cast(ltrim(rtrim(Substring(string,charindex('my',string)+len('my')+5,
charindex('for the company',string)-charindex('my',string)+len('my')-9))) as datetime)
from table
Select
cast(ltrim(rtrim(Substring(string,charindex('company',string)+len('company')+1,
len(String)-charindex('company',string)+len('company')-9)))as varchar)
from description
this 2 queries has a set of rows as output.
I want to insert these values to another table using single insert.
What i did is:
insert into table2(orderid,orderdate)
Select
cast(ltrim(rtrim(Substring(String, len('The order number')+1,
CHARINDEX ( 'as been created at', String) - len ('as been created at')))) as int)
,
cast(ltrim(rtrim(Substring(string,charindex('at',string)+len('at')+5,
charindex('for the company',string)-charindex('at',string)+len('at')-9))) as datetime)
from description
but its not inserted..its showing error like The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value..
Is there any another way to insert this?
when inserting a datetime you should specify a string that is SQL compliant i.e.
'YYYY-MM-DD HH:MM:SS'
I suspect that the CAST function cant convert the type specified. However you dont need to convert to a datetime, you can simply insert the string representation of the datetime.
Other issues you may encounter are the casting of ltrim(rtrim()) to an int. LTRIM, RTRIM both return a varchar. CHARINDEX already returns an int.
Ensure your types are consistent
To insert output from your two queries into a single table, the data types and number of columns from these queries should match with that of the table. You can use convert
CONVERT(
DATETIME,ltrim(rtrim(Substring(
string,charindex('at',string)+len('at')+5,
charindex('for the company',string)-charindex('at',string)+len('at')-9)))
,112)
for your datetime column and try (provided your target table has a datetime column for OrderDate).
I have an XML column in a table; I want to "promote" a certain value in that XML as a computed column and index it for faster searching. I have a function that takes in the XML information and outputs the element of interest, like this:
CREATE FUNCTION [dbo].[fComputeValue] (#data XML)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
RETURN #data.value('(/Metadata/Value[#Key="StartDate"])[1]', 'datetime')
END
However when I try to create the computed column:
ALTER TABLE dbo.CustomMetadataTable ADD [StartDate] AS ([dbo].[fComputeValue]([CustomMetadataColumn])) PERSISTED
I get the following error:
Msg 4936, Level 16, State 1, Line 2
Computed column
'StartDate'
in table 'CustomMetadataTable' cannot be
persisted because the column is
non-deterministic.
It works if I:
work with varchar, int, double (i.e. other than datetime) values
remove the PERSISTED keyword (but then I can't create an index on the column)
I should also mention that datetime values are in XSD datetime format.
Any ideas? Thanks.
What about:
CREATE FUNCTION [dbo].[fComputeValue] (#data XML)
RETURNS varchar(50)
WITH SCHEMABINDING
AS
BEGIN
RETURN #data.value('(/Metadata/Value[#Key="StartDate"])[1]', 'varchar(50)')
END
and:
ALTER TABLE dbo.CustomMetadataTable ADD [StartDate] AS (convert(datetime,([dbo].[fComputeValue]([CustomMetadataColumn]), 127)) PERSISTED
or:
return convert(datetime, #data.value('(/Metadata/Value[#Key="StartDate"])[1]', 'varchar(50)'), 127)
From books online:
CONVERT is Deterministic unless one
of these conditions exists:
Source type is sql_variant.
Target type is sql_variant and its
source type is nondeterministic.
Source or target type is datetime or
smalldatetime, the other source or
target type is a character string, and
a nondeterministic style is specified.
To be deterministic, the style
parameter must be a constant.
Additionally, styles less than or
equal to 100 are nondeterministic,
except for styles 20 and 21. Styles
greater than 100 are deterministic,
except for styles 106, 107, 109 and
113.
It might help if you use CONVERT with style 127