Teradata LIKE for range for values - (regular expression?) - teradata

In Teradata I need a condition to select only records:
starting in numbers between 0 and 4
followed by string ABCD
followed by anything
I can use substring and it works. But this is not a nice piece of code.
SELECT
'4ABCDXXX' AS T
, CASE WHEN
Cast (Substring (T, 1,1) AS SMALLINT) BETWEEN 0 AND 4
AND Substring (T, 2,4) = 'ABCD'
THEN 'OK' ELSE 'NOK' END
I tried
LIKE '[0-4]ABCD%'
But this does not seem to be working...
How can this be elegantly achieved?
Thanks.

I don't think that Teradata supports the enhanced LIKE syntax which are you attempting. But, in lieu of this, we can use REGEXP_SIMILAR:
SELECT
'4ABCDXXX' AS T,
CASE WHEN REGEXP_SIMILAR('4ABCDXXX', '^[0-4]ABCD.*$', 'c')
THEN 'OK' ELSE 'NOK' END AS label
FROM yourTable;

I've never been able to make negative lookaheads work in Teradata, so I would use two tests:
select
'4ABCD123' as t,
case when
regexp_similar(t,'^[0-4]ABCD') = 1 -- starts with 0-4 followed by ABCD
and t like '%ABCD' -- does not end with ABCD
then 'nok' else 'ok' end,

Related

BigQuery SQL - Change 0 to NULL, change NUMERIC to STRING type and PARSE DATETIME (single query)

I have a requirement where the current type is NUMERIC but I need it to be DATETIME, I am currently working with the data owner to get them to convert the data type so I will not have to perform these steps.
As stated above, the NUMERIC type needs to be changed to DATETIME but I have an issue where zero values exist. I have currently written two SQL queries to achieve the result but I was hoping to be able to do this in a single query.
See the below two queries:
Query 1
SELECT
MATERIAL,DESC,NUMBER,
CASE
WHEN START_ACTUAL = 0 THEN NULL
ELSE START_ACTUAL
END AS START_ACTUAL,
CASE
WHEN END_ACTUAL = 0 THEN NULL
ELSE END_ACTUAL
END AS END_ACTUAL,
FROM `SAMPLEFILE1`
Query 2
SELECT
MATERIAL,DESC,NUMBER,
PARSE_DATETIME('%Y%m%d%H%M%S', CAST(START_ACTUAL AS STRING)) AS START_ACTUAL,
PARSE_DATETIME('%Y%m%d%H%M%S', CAST(END_ACTUAL AS STRING)) AS END_ACTUAL,
FROM `SAMPLEFILE1_VIEW`
I'm sure someone will put me right straightaway and it is very simple :)
Thanks in advance
You could wrap your case statements in the CAST and PARSE_DATETIME, but you could just use nullif:
SELECT
MATERIAL,DESC,NUMBER,
PARSE_DATETIME('%Y%m%d%H%M%S', CAST(NULLIF(START_ACTUAL,0) AS STRING)) AS START_ACTUAL,
PARSE_DATETIME('%Y%m%d%H%M%S', CAST(NULLIF(END_ACTUAL,0) AS STRING)) AS END_ACTUAL,
FROM `SAMPLEFILE1_VIEW`

REGEXP_SUBSTR return all matches (mariaDB)

I need to get all the matches of a regular expression in a text field in a MariaDB table. As far as I know REGEXP_SUBSTR is the way to go to get the value of the match of a regular expression in a text field, but it always returns after the first match and I would like to get all matches.
Is there any way to do this in MariaDB?
An example of the content of the text field would be:
#Generation {
// 1
True =>
`CP?:24658` <= `CPV?:24658=57186`;
//`CP?23432:24658` <= `CPV?:24658=57186`
// 2
`CP?:24658` <> `CPV?:24658=57178` =>
`CP?:24656` <> `CPV?:24656=57169`;
And the select expression that I'm using right now is:
select REGEXP_SUBSTR(textfield,'CP\\?(?:\\d*:)*24658') as my_match
from table
where id = 1243;
Which at the moment returns just the first match:
CP?:24658
And I would like it to return all matches:
CP?:24658
CP?23432:24658
CP?:24658
Use just REGEXP to find the interesting rows. Put those into a temp table
Repeatedly process the temp table -- but remove the SUBSTR as you use it.
What will you be doing with each substr? Maybe that will help us devise a better approach.

Getting ORA-22922 (nonexistent LOB value) or no result at all with wm_concat()

(Using Oracle 11.2)
I have a rather complicated SQL with something like
wm_concat( distinct abc )
that is expected to return some varchar2(4000) compatible result.
It causes ORA-00932: inconsistent datatypes in my select used in some coalesce( some_varchar_col, wm_concat( ... ) ).
So I tried casting it via two different methods:
dbms_lob.substr( ..., 4000 ) -- L) tried even with 3000 in case of "unicode byte blow-up"
cast( ... as varchar2(4000)) -- C) tried even with 3000 in case of "unicode byte blow-up"
(The are used in a view, but playing around with it suggests, it is not related to the views)
Depending on the column and other operators I either get N) no result or O) ORA-22922:
select * from view_with_above_included where rownum <= 100
N) My Eclipse Data Explorer JDBC connection returns without any result (no columns without results, no (0 rows effected), only the query time statistics). (It could be an internal exception not treated as such?)
O)
ORA-22922: nonexistent LOB value
ORA-06512: in "SYS.DBMS_LOB", line 1092
ORA-06512: in line 1
Strangely the following test queries work:
-- rownum <= 100 would already cause the above problems
select * from view_with_above_included where rownum <= 10
or
select * from view_with_above_included
but looking at the actual aggregated data does not show aggregated data that would exceed 1000 characters in length.
Luckily, it works with the listagg( ... ) function provided since 11.2 (we are already running on), so we did not have to investigate further:
listagg( abc, ',' ) within group ( order by abc )
(Where wm_concat(...) is, as one should know, some internal and officially unsupported function.)
a rather nice solution (because it is not so bloated) to implement the distinct functionality is via self-referencing regexp functionality which should work in many cases:
regexp_replace(
listagg( abc, ',' ) within group ( order by abc )
, '(^|,)(.+)(,\2)+', '\1\2' )
(Maybe/Hopefully we will see some working listagg( distinct abc ) functionality in the future, which would be very neat and cool like the wm_concat syntax. E.g. this is no problem since a long time with Postgres' string_agg( distinct abc )1 )
-- 1: postgres sql example:
select string_agg( distinct x, ',' ) from unnest('{a,b,a}'::text[]) as x`
If the list exceeds 4000 characters, one cannot use listagg anymore (ORA-22922 again).
But luckily we can use the xmlagg function here (as mentioned here).
If you want to realize a distinct on a 4000-chars-truncated result here, you could outcomment the (1)-marked lines.
-- in smallercase everything that could/should be special for your query
-- comment in (1) to realize a distinct on a 4000 chars truncated result
WITH cfg AS (
SELECT
',' AS list_delim,
'([^,]+)(,\1)*(,|$)' AS list_dist_match, -- regexp match for distinct functionality
'\1\3' AS LIST_DIST_REPL -- regexp replace for distinct functionality
FROM DUAL
)
SELECT
--REGEXP_REPLACE( DBMS_LOB.SUBSTR( -- (1)
RTRIM( XMLAGG( XMLELEMENT( E, mycol, listdelim ).EXTRACT('//text()')
ORDER BY mycol ).GetClobVal(), LIST_DELIM )
--, 4000 ), LIST_DIST_MATCH, LIST_DIST_REPL ) -- (1)
AS mylist
FROM mytab, CFG

REGEXP_REPLACE replacing text with the same text in lower case

I am trying to use REGEXP_REPLACE in PL/SQL to replace some text with the same text in lower case. Actually, the rule is that I want all text between "()" that has only one char to be in lower case.
Here is an example :
SELECT REGEXP_REPLACE(
'i want what what is between <> in lower case : I am a test(E) (A) (HELLO)'
, '(\(\D\))', '<\1>'
) FROM DUAL
Result :
I want what is between <> in lower case : I am a test(e) (a) (HELLO)
or this because I am a little confuse about my exercice:
I want what is between <> in lower case : I am a test<(e)> <(a)> (HELLO)
How can I get my text in lower case ? I tried in several ways but I can't get out with it. I don't know hot to tell REGEXP_REPLACE to put "\1" content in lower case.
Thanks you for your help.
Best regards.
MS
(with Oracle11g) Here is how to replace the first occurrence:
Use REGEXP_instr and REGEXP_substr to be able to apply lower to the matched pattern
SELECT substr(it, 1 , REGEXP_instr( it, '(\(\D\))')-1)
||lower( REGEXP_substr(it, '(\(\D\))') )
||substr(it, REGEXP_instr( it, '(\(\D\))')+3, length(it))
FROM (SELECT 'i want what what is between <> in lower case : I am a test(E) (A) (HELLO)' it from dual) ;
and if you want the weird <> around it:
SELECT substr(it, 1 , REGEXP_instr( it, '(\(\D\))')-1)
|| '<'
||lower( REGEXP_substr(it, '(\(\D\))') )
|| '>'
||substr(it, REGEXP_instr( it, '(\(\D\))')+3, length(it))
FROM (SELECT 'i want what what is between <> in lower case : I am a test(E) (A) (HELLO)' it from dual) ;
I think you cannot have recursive regexp in Oracle. So if you want to be able to replace 2 occurrences:
SELECT substr(rit, 1 , REGEXP_instr( rit, '(\([[:upper:]]{1}\))')-1)
||lower( REGEXP_substr(rit, '(\([[:upper:]]{1}\))') )
||substr(rit, REGEXP_instr( rit, '(\([[:upper:]]{1}\))')+3, length(rit))
from (
(SELECT substr(it, 1 , REGEXP_instr( it, '(\([[:upper:]]{1}\))')-1)
||lower( REGEXP_substr(it, '(\([[:upper:]]{1}\))') )
||substr(it, REGEXP_instr( it, '(\([[:upper:]]{1}\))')+3, length(it)) rit
FROM (SELECT 'i want what what is between <> in lower case : I am a test(E) (A) (HELLO)' it from dual))
) ;
(+ I replace the \D by [[:upper:]]{1} which is more accurate)
To bad this has to be such a difficult problem! Seems like it would be easy.
To handle a variable number of occurrences of the pattern, you need to loop through the string looking for them. Maybe someone will come up with a slick solution using CONNECT BY or something but in the meantime and since you are using PL/SQL why don't you go old-school and create a function that does it? It will arguably be easier to maintain and will be wrapped up in a reusable unit available for all to use too. Pass it a string and have it return the cleaned up version.
SQL> select lower_single_letters('I want what is between in lower case : I am a test(E) (A) (HELLO)') text
from dual;
TEXT
--------------------------------------------------------------------------------
I want what is between in lower case : I am a test(e) (a) (HELLO)
SQL>
Here's some sample code since I wanted an example for use in my utility package:
CREATE OR REPLACE function lower_single_letters(string_in varchar2) return varchar2 is
tmp_string varchar2(1000) := string_in; -- Holds the string
regex_pattern constant varchar2(20) := '\([[:upper:]]\)'; -- Pattern to look for '(A)'
letter_offset integer; -- Offset of the pattern
letter varchar2(1); -- The letter to lower()
BEGIN
-- Loop while the pattern is found in the string passed in
while regexp_like(tmp_string, regex_pattern)
loop
-- Get the offset in the string
letter_offset := regexp_instr(tmp_string, regex_pattern)+1;
-- Get the letter
letter := substr(tmp_string, letter_offset, 1);
-- Replace it in the string
tmp_string := regexp_replace(tmp_string, '.', lower(letter), 1, letter_offset);
end loop;
-- Return it when the pattern is no longer found
return(tmp_string);
END lower_single_letters;

SQL SERVER CASE STATEMENT CLARIFICATION

I have to execute a statement like ( i need and keyword along with when ).
select
'Is Allowed'= case A.Column
when
A.Column='XXXX' and Isnull(A.AnotherColumn,'')<>'' then 'Yes'
else
'No' end from TableName
I am getting syntax error,how to rewrite it without affecting the condition.
Try:
select case when A.Column='XXXX' and Isnull(A.AnotherColumn,'')<>'' then 'Yes'
else 'No' end as 'Is Allowed'
from TableName
SELECT
CASE A.Column
WHEN 'Is Allowed THEN 'First'
WHEN 2 THEN 'Second'
WHEN 3 THEN 'Third'
ELSE 'Other'
END
Is the general way of making a CASE (which is your question). However, your query/logic looks a bit convoluted. More detailed answer / query is possible, but would perhaps use more statements/ nested CASE.
Have a closer look at CASE (Transact-SQL)
SELECT CASE
WHEN some boolean expression
THEN value
ELSE default value
END
or
SELECT CASE value to check
WHEN vlue to check agains
THEN value
ELSE default value
END

Resources