How to extract month from a String representing a date in TSQL - tsql

In my SQL Server database I have the dates stored as char(12) in the following format:
yyyymmddhhmm
I didn't create the definition and I cannot modify it. I always dealt with this string at application level, by using C#.
Now I need to perform a task in TSQL and I need to group by month. Therefore I need to extract the month. Is there any TSQL function available for this task?
In case there is not, is it a good solution to create a stored procedure, getMonth(stringDate) that takes the string and extract the 4th and 5th characters from it? Can I use the clause:
group by getMonth(stringDate)
in my query? Thanks

You can;
SUBSTRING(fld, 5, 2)
Personally I would not create a UDF for something so simple (which is what you would consider rather than an SP) unless you find yourself needing to cast that string to DATETIMEs

You can use the following to get your month, since month is always 2 characters after the 4 character year.
declare #date char(12)
set #date = '201203220906'
select substring(#date, 5, 2)
results: 03
or another way to get it is, then you can group by the results in either query:
declare #date char(12)
set #date = '201203220906'
select Month(cast(left(#date, 8) as datetime))

Assuming
CREATE TABLE #Table(
DateValue char(12),
Value int)
INSERT INTO #Table VALUES ('20120110833', 1)
INSERT INTO #Table VALUES ('20120110833', 2)
INSERT INTO #Table VALUES ('20120110833', 3)
INSERT INTO #Table VALUES ('20120210833', 4)
INSERT INTO #Table VALUES ('20120210833', 5)
You can simply do this:
select
MONTH(CAST(LEFT(DateValue, 8) as datetime)) Month,
SUM(value)
FROM
#Table
GROUP BY
MONTH(CAST(LEFT(DateValue, 8) as datetime))
trim the hour/minute part, cast as datetime and apply MONTH function

For this specific case (date in char type with format yyyymmddhhmm), you can use in your query the next functions:
substring (to extract yyyymmdd),
convert (to get datetime value),
datepart (to get month component)
...then you can group by month (or whatever date component), change datecolumnname and tablename with appropiate values
select datepart(month,convert(datetime,substring(datecolumnname,1,8),112)),
count(datepart(month,convert(datetime,substring(datecolumnname,1,8),112)))
from tablename
group by datepart(month,convert(datetime,substring(datecolumnname,1,8),112))

Related

Redshift: milliseconds to timestamp

Let us say we have have two tables:
CREATE TABLE IF NOT EXISTS tech_time(
ms_since_epoch BIGINT
);
CREATE TABLE IF NOT EXISTS readable_time(
ts timestamp without time zone,
);
Let us say tech_time has data and we would like to populate readable_time.
So in Postgres you could use to_timestamp(double precision) and do something like
INSERT INTO readable_time(ts)
SELECT DISTINCT to_timestamp(ms_since_epoch::float / 1000) AS ts,
FROM tech_time;
No such function seems to exist in Amazon Redshift:
function to_timestamp(double precision) does not exist
My question is: how do I properly populate readable_time, while losing the least amount of precision?
We can try using DATEADD and add the ms_since_epoch to January 1, 1970:
INSERT INTO readable_time (ts)
SELECT DATEADD(ms, ms_since_epoch, 'epoch')
FROM tech_time;

How to query from the result of a changed column of a table in postgresql

So I have a string time column in a table and now I want to change that time to date time type and then query data for selected dates.
Is there a direct way to do so? One way I could think of is
1) add a new column
2) insert values into it with converted date
3) Query using the new column
Here I am stuck with the 2nd step with INSERT so need help with that
ALTER TABLE "nds".”unacast_sample_august_2018"
ADD COLUMN new_date timestamp
-- Need correction in select statement that I don't understand
INSERT INTO "nds".”unacast_sample_august_2018” (new_date)
(SELECT new_date from_iso8601_date(substr(timestamp,1,10))
Could some one help me with correction and if possible a better way of doing it?
Tried other way to do in single step but gives error as Column does not exist new_date
SELECT *
FROM (SELECT from_iso8601_date(substr(timestamp,1,10)) FROM "db_name"."table_name") AS new_date
WHERE new_date > from_iso8601('2018-08-26') limit 10;
AND
SELECT new_date = (SELECT from_iso8601_date(substr(timestamp,1,10)))
FROM "db_name"."table_name"
WHERE new_date > from_iso8601('2018-08-26') limit 10;
Could someone correct these queries?
You don't need those steps, just use USING CAST clause on your ALTER TABLE:
CREATE TABLE foobar (my_timestamp) AS
VALUES ('2018-09-20 00:00:00');
ALTER TABLE foobar
ALTER COLUMN my_timestamp TYPE timestamp USING CAST(my_timestamp AS TIMESTAMP);
If your string timestamps are in a correct format this should be enough.
Solved as follows:
select *
from
(
SELECT from_iso8601_date(substr(timestamp,1,10)) as day,*
FROM "db"."table"
)
WHERE day > date_parse('2018-08-26', '%Y-%m-%d')
limit 10

tsql convert string into date when possible

I've got a column to import into an Azure SQL DB that is supposed to be made of dates only but of course contains errors.
In TSQL I would like to do something like: convert to date if it's possible otherwise null.
Does anyone know a statement to test the convertibility of a string into a date?
use TryCast or Isdate
select
try_Cast('test' as date)
select try_Cast('4' as date)
select case when ISDATE('test')=1 then cast('test' as date) else null end
TryCast will fail if the expression is not in expected format ..ie.,if the explicit conversion of expression is not permitted
select
try_cast( 4 as xml)
select try_Cast(4 as date)
You could use TRY_PARSE:
Returns the result of an expression, translated to the requested data type, or null if the cast fails. Use TRY_PARSE only for converting from string to date/time and number types.
SELECT TRY_PARSE('20129901' AS DATE)
-- NULL
Additionaly you could add culture:
SELECT TRY_PARSE('10/25/2015' AS DATE USING 'en-US')
And importing:
INSERT INTO target_table(date_column, ...)
SELECT TRY_PARSE(date_string_column AS DATE) ...
FROM source_table
...

Extract year from date within WHERE clause

I need to include EXTRACT() function within WHERE clause as follow:
SELECT * FROM my_table WHERE EXTRACT(YEAR FROM date) = '2014';
I get a message like this:
pg_catalog.date_part(unknown, text) doesn't exist**
SQL State 42883
Here is my_table content (gid INTEGER, date DATE):
gid | date
-------+-------------
1 | 2014-12-12
2 | 2014-12-08
3 | 2013-17-15
I have to do it this way because the query is sent from a form on a website that includes a 'Year' field where users enter the year on a 4-digits basis.
The problem is that your column is of data type text, while EXTRACT() only works for date / time types.
You should convert your column to the appropriate data type.
ALTER TABLE my_table ALTER COLUMN date TYPE date;
That's smaller (4 bytes instead of 11 for the text), faster and cleaner (disallows illegal dates and most typos).
If you have non-standard format add a USING clause with a conversion expression. Example:
Alter character field to date
Also, for your queries to be fast with a plain index on date you should rather use sargable predicates. Like:
SELECT * FROM my_table
WHERE date >= '2014-01-01'
AND date < '2015-01-01';
Or, to go with your 4-digit input for the year:
SELECT * FROM my_table
WHERE date >= to_date('2014', 'YYYY')
AND date < to_date('2015', 'YYYY');
You could also be more explicit:
to_date('2014' || '0101', 'YYYYMMNDD')
Both produce the same date '2014-01-01'.
Aside: date is a reserved word in standard SQL and a basic type name in Postgres. Don't use it as identifier.
This happens because the column has a text or varchar type, as opposed to date or timestamp. This is easily reproducible:
SELECT 1 WHERE extract(year from '2014-01-01'::text)='2014';
yields this error:
ERROR: function pg_catalog.date_part(unknown, text) does not exist
LINE 1: SELECT 1 WHERE extract(year from '2014-01-01'::text)='2014';
^ HINT: No function matches the given name and argument types. You might need to add explicit type casts.
extract or is underlying function date_part does not exist for text-like datatypes, but they're not needed anyway. Extracting the year from this date format is equivalent to getting the 4 first characters, so your query would be:
SELECT * FROM my_table WHERE left(date,4)='2014';

TSQL Cannot create index on view - the view uses an implicit conversion from string to datetime

SQL SERVER 2008 r2
I'm trying to Create an Indexed view however I'm getting the following error
Cannot create index on view '' because the view uses an implicit conversion from string to datetime or smalldatetime. Use an explicit CONVERT with a deterministic style value.
The issue is with an INT column [GPSTime] that records the number of seconds from '1970-01-01 00:00:00' and I'm trying to CONVERT/CAST this is to a DATETIME, eg
CAST(DATEADD(SS,[GPSTime],'1970-01-01' ) AS DATETIME)
or
CONVERT(VARCHAR,DATEADD(SS,[GPSTime],'1970-01-01' ),113)
or
CONVERT(DATETIME,DATEADD(SS,[GPSTime],'1970-01-01' ),113)
Each of the three options above gives me the error I mentioned earlier.
Is the way around this?
Going to make a guess that the issue is actually on the '1970-01-01', try this:
Dateadd(ss, gpsTime, convert(datetime, '1970-01-01', 101))
Or you could keep the datetime value in another table (as a datetime to avoid convert) or write a deterministic function to return your datetime as such:
create function [dbo].[UnixEpoch]
()
returns datetime
with schemabinding
as
begin
RETURN convert(datetime, '1970-01-01', 101)
end
go
select objectproperty(object_id('[dbo].[UnixEpoch]'), 'IsDeterministic')
SELECT dbo.unixEpoch()
EDIT:
note the datetime style applied to the convert(datetime, '1970-01-01', 101)
according to documentation at http://msdn.microsoft.com/en-us/library/ms178091.aspx :
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.
i got the same error and fixed it by not only using convert:
CONVERT(DATETIME, firstdate, 102) AS firstdate
On the SELECT clause, but also in the WHERE clause as:
WHERE firstdate >= CONVERT(DATETIME,'20150101',102)
I hope this solution helps!