How do i extract a Date out of a string in SQL? - sql

I can't seems to find out how to extract the date from a string in a column. e.g:
2015-03-30T04:04:26+0200 -> 30.3.2015
I tried to look for a regex query but it didn't work for me.

The following will work in a lot of databases:
select cast(left(col, 10) as date)

Option 1: Pure SQL Solution
i.e. MySQL
since you are asking SQL here, how about:
SELECT DATE_FORMAT(DATE("2015-03-30T04:04:26+0200"),"%d.%m.%Y")
which returns
30.03.2015
i.e. Oracle
If you want to run this query on Oracle, then you will have to adapt the query:
SELECT TO_CHAR(TO_DATE(SUBSTR('2015-03-30T04:04:26+0200', 1, 10),'YYYY-MM-DD'),'DD.MM.YYYY') myDate FROM dual
i.e. PostgreSQL
Also here a few differences in the query. Actually quite the same as Oracle. I cheated here and moved the 0200 at the end into US which is actually for microseconds, but gives us a valid parse format string without having to use SUBSTR:
SELECT TO_CHAR(TO_DATE('2015-03-30T04:04:26+0200','YYYY-MM-DD"T"HH24:MI:SS+US'),'DD.MM.YYYY')
i.e. SQLite
Now here a completely different function. SQLite uses strftime() to format dates. But here i use substr() again:
SELECT STRFTIME('%d.%m.%Y',DATE(SUBSTR('2015-03-30T04:04:26+0200',1,10)))
Now i could go on with MS SQL Server and more but i reckon with these alternatives you should find a way of translating the problem to your DBMS SQL syntax.
Option 2: Pure RegEx Solution
PCRE RegEx (Python, PHP, etc.)
or if you want to use plain regex:
(\d+)-(\d+)-(\d+)T.*
which you substitute with
\3.\2.\1
This you can play around with here:
RegEx Fiddle Demonstration
Javascript, Java, etc.
Depending on your programming language, you might need to change your RegEx to:
([0-9]+)-([0-9]+)-([0-9]+)T.*
and your replacement string to
$3.$2.$1f

Related

Wildcard Search for a numeric range

I am trying to filter out a column (plan_name) which have internet plans of customers. Eg (200GB Fast Unlimited,Free Additional Mailbox,Unlimited VDSL...). I specifically want to filter out plans which do not have any numbers in them. The column is of type varchar2 and I'm querying an Oracle database. I have written the following code:
SELECT *
FROM plans
WHERE plan_name NOT LIKE '%[0-9]%'
However, this code still returns plans like 200GB fast that have numbers in them? Can anyone explain why this is?
Oracle's like syntax does not support the kind of pattern matching you are trying. This is SQL Server syntax. Oracle interprets the pattern as a litteral '[0-9]' (which, obviously, something like '200GB'does not match).
However, unlike SQL Server, Oracle has proper suport for regular expression, through the regexp_* functions. If you want values that contain no digit, you can do:
where not regexp_like(plan_name, '\d')

Problems with BETWEEN dates operator

I am practising and experimenting with different syntax of SQL BETWEEN operator in regards to dates from the "https://www.w3schools.com/sql/sql_between.asp"
This is the Order table in my database:
LINK: https://www.w3schools.com/sql/sql_between.asp
The query is fetching the orderdates between a given condition of 2 dates.
These are the two main syntax versions (according to w3schools):
SELECT *
FROM Orders
WHERE OrderDate BETWEEN #01/07/1996# AND #31/07/1996#;
and:
SELECT *
FROM Orders
WHERE OrderDate BETWEEN '1996-07-01' AND '1996-07-31';
The output that we get on typing the above two queries from the Orders table
Number of Records: 22 (out of 196 records). Yes this is correct.
Now I am experimenting with this syntax versions.
CASE #1:
SELECT *
FROM Orders
WHERE OrderDate BETWEEN #1996/07/01# AND #1996/07/31#;
Result of case #1: 22 (same as the above syntax)
In the SQL try it out editor(https://www.w3schools.com/sql/trysql.asp?filename=trysql_select_between_date&ss=-1) they are stating that this SQL statement is not supported in the WebSQL database.The example still works, because it uses a modified version of SQL.
WHY SO?
If you're using the W3Schools Tryit editor in Chrome, you're using WebSQL, which is basically SQLite.
SQLite doesn't have a date/time format, so is probably storing the date values as strings formatted in the ISO-8601 format (see this answer for more information).
Other database systems (e.g. Oracle, Microsoft SQL Server, Postgres, MySQL) have built-in date formats, and you generally represent them as strings (enclosed in single quotes). For example: '1997-07-01' (depending on the specific RDBMS, there might be more specific considerations).
The format that uses pound signs (e.g. #7/1/1997#) is unique to Microsoft Access (see this answer for more information).
Bottom line: Dates are generally enclosed in single quotes. You're best off sticking to the ISO-8601 standard (e.g. 1997-07-01).
If you're learning SQL, there are other resources out there besides W3Schools. I would recommend downloading an open-source RDBMS like Postgres or MySQL, setting up a sample database, and working on some queries. Challenge sites like codewars might also be helpful
One more thing: Don't use BETWEEN for dates. Use >= and <, to make sure you're not excluding dates with a time portion. For more information, read this blog.

Are there any performance downsides to using ODBC date string-literals in SQL Server? Is it better than a regular string date literal?

I have a TSQL view that processes multiple gigabytes of data in a SQL Server 2016 environment. In this view, there are multiple times where I am comparing if a DateTime value is before/after a static date, traditionally represented as a string literal like '2018-07-11'.
An example comparison would be:
SELECT MyId, MyValue FROM MyTable WHERE MyDate = '2018-07-11'
While looking for a way to use a DateTime literal instead of a string, I came across examples using ODBC DateTime strings like so:
SELECT MyId, MyValue FROM MyTable WHERE MyDate = {d '2018-07-11'}
When I compare the query plan I get the same result, even when I make up more advanced queries.
I started using this format in an attempt to prevent the auto-conversion of string to DateTime in queries, but I haven't been able to find any good documentation explaining any side effects of using ODBC functions. I'm not sure if this acts the same way as a string literal or if it is interpreted as a date.
If this was a UDF or Stored Procedure, I'd have the ability to declare a DateTime variable for use in the query, but in a VIEW this is not possible, nor would it be feasible because there are a lot of DateTime literals in the actual version of the query.
So in conclusion, does someone have any concrete reasons for or against using this {d '2018-07-11'} format (besides it potentially not being valid in a non SQL Server environment)?
I want to ensure that I'm not shooting myself in the foot here on a code review.
PS: I apologize for the vague examples and semi-open-ended question, I am not allowed to disclose any actual source code.
Thanks!
EDIT: I forgot to mention that I could also use DATEFROMPARTS(2018, 07, 11), but I wasn't sure if this would be looked at weirdly by the query optimizer.
The ODBC literal has the slight advantage that it can never be interpreted as YYYY-DD-MM, which is possible with one internationalization setting.
You can avoid ambiguity by using 'YYYYMMDD' format. This format is not affected by settings.
I prefer not using the ODBC, just because it seems to involve more clutter in the query. I admit to also preferring the hyphenated form (consistent with the ISO standard and other databases). But you have three alternatives. Possibly the safest for general purpose, SQL-Server-only code is the unhyphenated form.
A literal is a literal. It is transformed into a value during parsing. The value is used later.
Here is the list of DateTime literals that SQL Server supports. ODBC is a supported format.
So, if only using SQL Server then there is no difference. Different SQL flavors may reject the ODBC syntax. I do not believe it is ANSI SQL, so "less standard"?

Firebird SQL test if string contains DATE in WHERE clause

Is there any way to test if a string contains a DATE like 31.12.2018 ?
Like
SELECT date_string FROM table where date_string LIKE '%.*.*%'
Or something like that?
You can try to use the SIMILAR TO comparison predicate, which uses SQL regular expressions. However depending on the size of the text, this might not be very efficient.
The following predicate will work:
date_string similar to '%[[:DIGIT:]]{2}.[[:DIGIT:]]{2}.[[:DIGIT:]]{4}%'
See the language reference on SIMILAR TO for details on the syntax.
You may want to rethink your design and use explicit columns with an actual SQL DATE if you need to apply query logic on them, instead of relying on parsing things within text columns.

extracting special character from a string in oracle sql

I need a query to remove all alphanumeric characters from a string and give me only special characters.
If string is '##45gr##3' query should give me '####'.
SELECT REGEXP_REPLACE('##45gr##3','[^[:punct:]'' '']', NULL) FROM dual;
The old-fashioned way, with a replace() call:
select translate(upper(txt)
, '.1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ'
, '.') as spec_txt
from t42
/
With a replace() solution is better to type all the characters we want to exclude. Yes that is the larger set (probably) but at least it's well-defined. We don't want to keep revising the code to handle new characters in the input string.
Obviously regex solution is more compact and who can deny the elegance of #venkatesh solution? However, evaluating regular expressions is more expensive than more focused SQL functions, so it's worth knowing alternative ways of doing things, for those cases when performance is an issue.
Everything written in comments is most probably very true (especially the 5th one that talks about exceptions, special cases etc.). My feeling is that Jörg knows more about regular expressions than I'll ever know.
Anyway, to cut a long story short, in its very simple appearance, regarding the question posted ("remove all numbers and letters"), something like this might work:
SQL> select regexp_replace('a##45gr##3$.', '[[:digit:]]+|[[:alpha:]]+', '') result
2 from dual;
RESULT
------
####$.
SQL>