Casting invalid string date to date in Snowflake - snowflake-cloud-data-platform

I have a column with invalid date strings in snowflake and I need to cast them to date. I tried with TRY_CAST, TRY_DATE, IS_DATE but nothings seems to work, i.e.
select * from (values (1, TRY_CAST('1985-02-30' as date)));
Invalid expression [TRY_CAST('1985-02-30' AS DATE)] in VALUES clause
Is there an easy way to do a validation on the date itself?

The VALUES requires simple expression or constants. The alternative is SELECT:
select * from (values (1, TRY_CAST('1985-02-30' as date)));
=>
select * from (select 1, TRY_CAST('1985-02-30' as date));

Related

How to convert nvarchar to numeric

I have fields with decimal values but imported in database as nvarchar(50) data type, that look like this:
Time
(Ordered product sales)
(Units ordered)
2022-01-01T00:00:00
$55.60
4
2022-01-03T00:00:00
$652.54
13
Goal: I wanted to aggregate (SUM) these fields to get the sum of orders and total number of units ordered
I tried to cast these values as numeric(10,2) because I wanted to aggregate these fields (SUM):
SELECT
[Time],
SUM(CAST([Ordered_product_sales] AS NUMERIC(10, 2))) AS Sales_per_day,
SUM(CAST([Units_ordered] AS INT)) AS num_of_units_ordered
FROM
[dbo].[salesDashboard]
WHERE
Ordered_product_sales <> '0.00'
AND Ordered_product_sales IS NOT NULL
GROUP BY
Time
However, I am getting a following error:
Error converting data type nvarchar to numeric.
The issue causing your error is that the data strings in the [Ordered_product_sales] column contain a character that cannot be converted to a numeric data type. You must first sanitize the strings to remove all characters that cannot be converted, specifically the $ present in your sample data, prior to performing the CAST function.
This should work:
SELECT
[Time]
,SUM(CAST(REPLACE([Ordered_product_sales], '$', '') AS NUMERIC(10, 2)))
AS Sales_per_day,
,SUM(CAST([Units_ordered] AS INT)) AS num_of_units_ordered
FROM [dbo].[salesDashboard]
And you should put some thought and effort into improving the design of your table and columns with respect to datatypes.

how to insert random timestamp in snowflake timestamp field

I am trying the following SQL but I get an error:
CREATE TABLE slipstream( visit_timestamp time);
INSERT INTO slipstream values(dateadd(second, uniform(1, 10, random()), current_time()));
Error:
Invalid expression [DATE_ADDSECONDSTOTIME(CAST(UNIFORM(1, 10, RANDOM()) AS NUMBER(2,0)), '12:52:29.050000000')] in VALUES clause
Please advise
Using INSERT - SELECT pattern:
INSERT INTO slipstream (visit_timestamp)
SELECT dateadd(second, uniform(1, 10, random()), current_time());
Output:
The VALUES requires constants and allows for simple casting that the SQL parser can do, thus in the values line you can have '2022-06-21'::date and that will correctly cast to DATE.
SELECT column1, system$typeof(column1) FROM VALUES
('2022-06-21'::date),
('2022-05-21'::date);
gives:
COLUMN1
SYSTEM$TYPEOF(COLUMN1)
2022-06-21
DATE[SB4]
2022-05-21
DATE[SB4]
And thus for this workflow it would have been valid to use:
INSERT INTO slipstream VALUES
('2022-06-21'::timestamp),
('2022-05-21'::timestamp);
number of rows inserted
2
But complex function calls need to be executed SQL, thus as Lukasz mentioned the need for the INSERT/SELECT pattern.
Now you can be clever and put a VALUES on the SELECT to data drive the parameters to those functions (I was hoping to be clever as using the values to uniform, but those need to be constants, so settled for an offset)
CREATE TABLE slipstream( visit_timestamp time);
INSERT INTO slipstream
SELECT dateadd(second, uniform(1, 10, random() ) + column1, current_time() )
FROM VALUES
(0),
(-10),
(-20);
number of rows inserted
3
SELECT * FROM slipstream;
VISIT_TIMESTAMP
16:18:04
16:17:55
16:17:42

Convert VARCHAR in format YYMMDD to YYYYMMDD and ignore invalid date formats

I have a table with a VARCHAR field called ArrivalDate in format yymmdd (such as 170202).
I am writing a query which converts it to yyyymmdd so it should become 20170202.
However my problem is that I need to cater for the case when inappropriate data is entered into the field, and my query needs to exclude that data. I am achieving this exclusion by using the ISDATE function of TSQL. I also need to select the least recent entry (I'm using order by asc for this).
I am using a variety of converts to write this query, below is my implementation with a sample table and data.
Declare #tmp TABLE (theDates VARCHAR(MAX))
INSERT INTO #tmp VALUES('170202')
SELECT TOP 1 t.theDates
WHEN (ISDATE(t.theDates) = 1) THEN CONVERT( VARCHAR(max),CONVERT(datetime t.theDates), 112)
FROM #tmp t
WHERE (ISDATE(t.theDates) = 1)
ORDER BY CAST(t.theDates as DATE)
However I do not like my approach and it occasionally fails conversion and throws an error with values such as 02/02/02 which breaks the query. Can someone please show me a better way of writing this functionality.
Much appreciated!
You can use TRY_CONVERT and CONVERT to get the correct format and convert the value. Then check that the string is exactly 6 character to prevent other formats from being returned.
SELECT
convert(char(10),convert(date, theDates, 12),112)
FROM
(values('02/02/02'),('170202')) x(theDates)
WHERE
try_convert(date, theDates, 12) is not null
and len(theDates) = 6
You can use cast(#date as datetime)
declare #date varchar(max);
set #date='170202';
select
CASE WHEN (ISDATE(cast(#date as datetime)) = 1)
THEN CONVERT(VARCHAR(max), CONVERT(datetime, cast(#date as datetime)), 112) end
from table
set #date='02/02/02';
select
CASE WHEN (ISDATE(cast(#date as datetime)) = 1)
THEN CONVERT(VARCHAR(max), CONVERT(datetime, cast(#date as datetime)), 112) end
from table
please use create function for check dateformat is Valid or not and use this fun in your query inside cash clouse.
ALTER FUNCTION dbo.f_CheckDate
(#InDate nvarchar(25))
RETURNS DATE
AS
BEGIN
declare #Return DATETIME
select #return = CASE WHEN ISDATE(#InDate) = 1
THEN #InDate
ELSE NULL
END
return #return
END
You could use TRY_CAST or TRY_CONVERT if value cannot be cast it will return NULL.
SELECT
TRY_CAST('20170228' AS DATETIME),
TRY_CAST('170228' AS DATETIME),
TRY_CONVERT(DATETIME, '20170228'),
TRY_CONVERT(DATETIME, '170228')
This works for SQL Server 2012 and newer.

adding '0,' before every column

I'm trying an 0, before every column in my sql
select TemporaryStock * '0,'+ cast( VAT as varchar(50)) from Market
i get error Msg 8114, Level 16, State 5, Line 1
Error converting data type varchar to float.
You don't need to cast... you just need to move the decimal.
select TemporaryStock * (VAT * 0.01) from Market
If you want every value to be like 0.###### then you can use:
select TemporaryStock * convert(decimal(38,37),'0.' + convert(varchar,VAT))
If you want to add '0' before the VAT then use CONCAT(args1, args2) method:
select CONCAT('0',VAT) from ExpressMarket;
Note: Both the arguments should be of string type.
Or else you can refer the following to know more about how to concatenate and aliasing it.
MySQL select with CONCAT condition

TSQL Date Conversion Failure - My Inability to understand result sets

I've got a staging area that I'm trying to validate data in, going through multiple iterations of validation. Currently, I'm fighting some issues with a nvarchar(50) column that I'm attempting to convert to a date.
I'm aware of the common pitfall of poorly formed strings failing date conversion, so here's what I'm doing.
SELECT *
FROM ( SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1)
WHERE CAST(DATE_COL AS DATE) < GETDATE()
... this results in the standard "Conversion failed when converting date and/or time from character string."
But here's where things get weird for me. If I change the above statement to the following:
SELECT CAST(DATE_COL AS DATE)
FROM ( SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1)
... all is well, and all I've done is moved the cast from the where clause to the select clause. I think I'm missing something at a fundamental level.
FWIW, if I were to pull all records from STAGE_TABLE without the WHERE ISDATE clause, I would have poorly formed date strings.
Any insights greatly appreciated!
You should find that the first query merges the two WHERE clauses into one, and works out the CAST before the ISDATE (fail).
The 2nd query clearly has to process the WHERE first, so the CAST never sees bad data
I have just tested and can verify:
create table STAGE_TABLE ( date_col nvarchar(50) )
insert into STAGE_TABLE select 'a'
insert into STAGE_TABLE select '20100101'
First query
SELECT *
FROM ( SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1) X
WHERE CAST(DATE_COL AS DATE) < GETDATE()
First plan
|--Filter(WHERE:(isdate([tempdb].[dbo].[STAGE_TABLE].[date_col])=(1)))
|--Table Scan(OBJECT:([tempdb].[dbo].[STAGE_TABLE]), WHERE:(CONVERT(date,[tempdb].[dbo].[STAGE_TABLE].[date_col],0)<getdate()))
Second query
SELECT CAST(DATE_COL AS DATE)
FROM ( SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1) X
Second plan
|--Compute Scalar(DEFINE:([Expr1004]=CONVERT(date,[tempdb].[dbo].[STAGE_TABLE].[date_col],0)))
|--Filter(WHERE:(isdate([tempdb].[dbo].[STAGE_TABLE].[date_col])=(1)))
|--Table Scan(OBJECT:([tempdb].[dbo].[STAGE_TABLE]))
There does not seem to be a hint/option to fix the first query (since it gets rolled into one WHERE clause), but you can use this which processes both conditions in one scan pass.
SELECT *
FROM (SELECT * FROM STAGE_TABLE) X
WHERE CAST(CASE WHEN ISDATE(DATE_COL) = 1 THEN DATE_COL ELSE NULL END AS DATE) < GETDATE()

Resources