Converting a numerical code into a word string right-to-left - sql

I am trying to use an SQL select expression to convert the following from 1st column, into the 2nd.
Code Outcome
88881133 Species 1, 2, 3, 4 sick
88888888 NULL
88888833 Species 1, 2 sick
88888811 Species 1, 2 sick
88888111 Species 1, 2, 3 sick
88888881 Species 1 sick
Code should be read from right to left.
1 or 3 means that the Species is sick.
8 means Species is not sick.
I suppose it involves some CASE expression, but I couldn't go very further than:
SELECT
CASE WHEN RIGHT(Code, 1) = 1 OR WHEN RIGHT(Code, 1) = 3
THEN 'Species 1 sick' END AS Outcome
FROM table
I use the Vertica database

Here is another method just using like and case. I'm just translating 1 and 3 to 1, and 8 to 0. Mostly because I was going to do a binary method but this seemed simpler. The real reason is just to keep the case statement simple (else you have to check both 1 and 3 cases).
The rtrim has a second parameter meaning to trim only that extra comma space. It's a simple trick to remove the last one. The outer case is just making sure there are species (otherwise it'll return null).
Hope it helps.
with translated_mytable as (
select code, translate(code,'813','011') newcode
from mytable
)
select Code,
case when newcode like '%1%' then
'Species ' ||
rtrim(case when newcode like '_______1' then '1, ' else '' end ||
case when newcode like '______1_' then '2, ' else '' end ||
case when newcode like '_____1__' then '3, ' else '' end ||
case when newcode like '___ 1___' then '4, ' else '' end ||
case when newcode like '___1____' then '5, ' else '' end ||
case when newcode like '__1_____' then '6, ' else '' end ||
case when newcode like '_1______' then '7, ' else '' end ||
case when newcode like '1_______' then '8, ' else '' end,
', ') || ' sick'
end Outcome
from translated_mytable

Please, try that query - it should do the trick - please just change t_tab into your_table_name and it should work
WITH
t_tab2 AS
(
SELECT t.code,
CASE WHEN SUBSTR(t.code,1,1) IN (1,2,3) THEN 8 END Out1,
CASE WHEN SUBSTR(t.code,2,1) IN (1,2,3) THEN 7 END Out2,
CASE WHEN SUBSTR(t.code,3,1) IN (1,2,3) THEN 6 END Out3,
CASE WHEN SUBSTR(t.code,4,1) IN (1,2,3) THEN 5 END Out4,
CASE WHEN SUBSTR(t.code,5,1) IN (1,2,3) THEN 4 END Out5,
CASE WHEN SUBSTR(t.code,6,1) IN (1,2,3) THEN 3 END Out6,
CASE WHEN SUBSTR(t.code,7,1) IN (1,2,3) THEN 2 END Out7,
CASE WHEN SUBSTR(t.code,8,1) IN (1,2,3) THEN 1 END Out8
FROM t_tab t
)
SELECT tt.code,
CASE WHEN tt.out1||tt.out2||tt.out3||tt.out4||
tt.out5||tt.out6||tt.out7||tt.out8 IS NULL THEN NULL
ELSE REGEXP_REPLACE(
REGEXP_REPLACE(RTRIM('Species' || ' ' || tt.out8 || ', ' || tt.out7|| ', '
|| tt.out6 || ', ' || tt.out5 || ', '
|| tt.out4 || ', ' || tt.out3 || ', '
|| tt.out2 || ', ' || tt.out1, ', ')
|| ' sick', ', | ,', ','), ',{1,}', ', ') END AS Outcome
FROM t_tab2 tt
It's giving me the result:
1 88881133 Species 1, 2, 3, 4 sick
2 88888888
3 88888833 Species 1, 2 sick
4 88888811 Species 1, 2 sick
5 88888111 Species 1, 2, 3 sick
6 88888881 Species 1 sick

Related

How to take where clause conditions from table column in oracle SQL or plsql

How to take where clause conditions from table column in oracle plsql.
E.g. data in table
Condition
1.sourceSystemId = 'SN'
2.AND(coverageType='AD',amountType1='PREMIUM',premiumFrequency='REGULAR',yearOfPremium='1')
e.g query:
select * from xyz where rule='abc' and "sourceSystemId = 'SN'"
select * from xyz where rule='abc' AND(coverageType='AD',amountType1='PREMIUM',premiumFrequency='REGULAR',yearOfPremium='1')
Not entirely sure what you're asking here, but I would imagine that
select * from xyz where rule='abc' AND(coverageType='AD',amountType1='PREMIUM',premiumFrequency='REGULAR',yearOfPremium='1')
would become
select * from xyz
where rule='abc'
AND coverageType='AD'
and amountType1='PREMIUM'
and premiumFrequency='REGULAR'
and yearOfPremium='1'
I suppose you want something like :
DECLARE
l_query VARCHAR2(2000) := 'select * from xyz where rule=''abc''';
l_result xyz%ROWTYPE;
l_cursor SYS_REFCURSOR;
BEGIN
dbms_output.put_line(l_query);
FOR clause IN (SELECT condition
FROM conditions)
LOOP
l_query := l_query||' AND '||clause.condition;
END LOOP;
OPEN l_cursor FOR l_query;
LOOP
FETCH l_cursor INTO l_result;
EXIT WHEN l_cursor%NOTFOUND;
..
-- your processing
END LOOP;
CLOSE l_cursor;
END;
Here is example of SQL solution. I used justt first and last condition but you can get them all...
WITH
xyz As
(
Select 1 "ID", 'abc' "RULE", 'AD' "COVERAGETYPE", 'PREMIUM' "AMOUNTTYPE1", 'REGULAR' "PREMIUMFREQUENCY", '1' "YEAROFPREMIUM" From Dual
UNION
Select 2 "ID", 'abc' "RULE", 'BF' "COVERAGETYPE", 'ORDINARY' "AMOUNTTYPE1", 'EXTRA' "PREMIUMFREQUENCY", '2' "YEAROFPREMIUM" From Dual
UNION
Select 3 "ID", 'abc' "RULE", 'AD' "COVERAGETYPE", 'PREMIUM' "AMOUNTTYPE1", 'REGULAR' "PREMIUMFREQUENCY", '1' "YEAROFPREMIUM" From Dual
),
conditions As
(
SELECT UPPER('coverageType=AD,amountType1=PREMIUM,premiumFrequency=REGULAR,yearOfPremium=1') "CND" From Dual
)
SELECT
x.ID, x.RULE, x.COVERAGETYPE, x.AMOUNTTYPE1, x.PREMIUMFREQUENCY, x.YEAROFPREMIUM
FROM
xyz x
INNER JOIN
conditions c ON(1=1)
WHERE
x.RULE = 'abc' And
x.COVERAGETYPE = CASE WHEN InStr(c.CND || ',', 'COVERAGETYPE=') = 0 THEN x.COVERAGETYPE
ELSE SubStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'COVERAGETYPE=') + Length('COVERAGETYPE=')), 1, InStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'COVERAGETYPE=') + Length('COVERAGETYPE=') + 1), ',')) END And
x.YEAROFPREMIUM = CASE WHEN InStr(c.CND || ',', 'YEAROFPREMIUM=') = 0 THEN x.YEAROFPREMIUM
ELSE SubStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'YEAROFPREMIUM=') + Length('YEAROFPREMIUM=')), 1, InStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'YEAROFPREMIUM=') + Length('YEAROFPREMIUM=') + 1), ',')) END
Result:
ID RULE COVERAGETYPE AMOUNTTYPE1 PREMIUMFREQUENCY YEAROFPREMIUM
1 abc AD PREMIUM REGULAR 1
3 abc AD PREMIUM REGULAR 1

Requesting help converting DB2 sql to Oracle

Looking for a little help converting a query from DB2 to Oracle. I'm using an existing SQL query to add to a new report, but that report query has been written in DB2 SQL. I am trying to convert it to Oracle, and having issues with how the dates are setup.
trunc_timestamp(CASE ......
ELSE ((
CASE
WHEN
TRFRDATE IS NULL OR
TRFRTIME IS NULL
THEN
NULL
ELSE timestamp(substr(char(TRFRDATE), 1, 4) || '-' ||
substr(char(TRFRDATE), 5, 2) || '-' || substr(char(TRFRDATE), 7, 2)
|| '-' || substr(digits(TRFRTIME), 1, 2) || '.' ||
substr(digits(TRFRTIME), 3, 2) || '.' || substr(digits(TRFRTIME), 5, 2)
|| '.000000')
END) + (-1) DAY)
END, 'dd') AS "NewOrderDate",
As you can see above, I have a case statement that will be converted to a timestamp, the difficult part is the last part, where after calculating the timestamp, I need to subtract -1 day, and that's where I keep falling into one error or the other.
Just to be clear, the ELSE part of the above query is just concatenating the date and time and converting to timestamp. Any help figuring this out would be great.
EDIT: My query now is this, and im getting the following error: hour must be between 1 and 12
SELECT CASE
WHEN
CASE
WHEN
CARRSERV IN ('1DYT','1PRT','SATN')
THEN 1
WHEN
CARRSERV IN ('2DYT','SAT2')
THEN 2
ELSE 3
END = 1 AND
TO_CHAR(
CASE
WHEN TFRDATE IS NULL OR TFRTIME IS NULL THEN NULL
ELSE TO_TIMESTAMP(substr(TFRDATE, 1, 2) || '-' || substr(TFRDATE, 4, 3) || '-' ||
substr(TFRDATE, 8, 2) || ' ' || substr(TFRTIME, 1, 2) || '.' ||
substr(TFRTIME, 3, 2) || '.' || substr(TFRTIME, 5, 2))
END,'hh24:mi:ss') > TO_CHAR('17:00:00','hh24:mi:ss')
THEN
CASE
WHEN TFRDATE IS NULL OR TFRTIME IS NULL THEN NULL
ELSE TO_TIMESTAMP(substr(TFRDATE, 1, 2) || '-' || substr(TFRDATE, 4, 3) || '-' ||
substr(TFRDATE, 8, 2) || ' ' || substr(TFRTIME, 1, 2) || '.' ||
substr(TFRTIME, 3, 2) || '.' || substr(TFRTIME, 5, 2))
END
END AS NEW_DATE from table
If I get this right you're truncating any hour/minute/second/... portion anyway so just ignore it from the beginning.
You can simply use to_date() to convert a string into a date:
...
to_date(trfrdate, 'YYYYMMDD') - 1 AS "NewOrderDate"
...
But you should really consider to use appropriate data types and strings types aren't appropriate for date/times, date/time types are. You could for example have one date column instead of trfrdate and trfrtime.
And it's a CASE expression you have there, not a statement. SQL knows no control flow statements at all.

Oracle SQL query. How to obtain string tokens from a string using 'space' as a delimiter, then display selective tokens?

E.g. I have a table - USERS, with column NAME1 varchar2(30). Records currently in it are:
NAME1:
Benjamin Barker
Alexis Jacob Alexander Cruise
Christopher James Lee
How do I create a function or write a query where I can get the output as follows:
Benjamin ****
Alexis **** Cruise
Christopher **** Lee
The function/query will calculate the name string and return E.g. 'Benjamin barker' as 2 tokens, but only display the first token. While if the name has three or more tokens, e.g. 'Christopher James Lee' or 'Alexis Jacob Alexander Cruise', it will only display the first and the last token.
You can use instr to locate the spaces and substr to extract the tokens, with some conditional logic:
-- CTE for your sample data
with users (name1) as (
select 'Benjamin Barker' from dual
union all select 'Alexis Jacob Alexander Cruise' from dual
union all select 'Christopher James Lee' from dual
union all select 'Madonna' from dual
)
-- actual query
select case
when instr(name1, ' ') = 0
then name1
else substr(name1, 1, instr(name1, ' ') - 1)
end
|| case
when instr(name1, ' ', 1, 2) > 0
then substr(name1, instr(name1, ' ', -1))
end
as result
from users;
RESULT
----------------------------------------------------------
Benjamin
Alexis Cruise
Christopher Lee
Madonna
If you actually want the **** as shown in the question you can concatenate that in the first else clause:
select case
when instr(name1, ' ') = 0
then name1
else substr(name1, 1, instr(name1, ' ') - 1) || ' ****'
end
|| case
when instr(name1, ' ', 1, 2) > 0
then substr(name1, instr(name1, ' ', -1))
end
as result
from users;
RESULT
---------------------------------------------------------------
Benjamin ****
Alexis **** Cruise
Christopher **** Lee
Madonna
or if you want to add + Masked as you said in a comment, only to those that are actually changed, you can just concatenate a third case expression:
select case
when instr(name1, ' ') = 0
then name1
else substr(name1, 1, instr(name1, ' ') - 1)
end
|| case
when instr(name1, ' ', 1, 2) > 0
then substr(name1, instr(name1, ' ', -1))
end
|| case
when instr(name1, ' ', 1, 1) > 0
then ' + Masked'
end
as result
from users;
RESULT
-------------------------------------------------------------------
Benjamin + Masked
Alexis Cruise + Masked
Christopher Lee + Masked
Madonna
If you want it in a function, just use the same case expressions:
create or replace function short_name (p_name varchar2)
return varchar2 as
begin
return case
when instr(p_name, ' ') = 0
then p_name
else substr(p_name, 1, instr(p_name, ' ') - 1)
end
|| case
when instr(p_name, ' ', 1, 2) > 0
then substr(p_name, instr(p_name, ' ', -1))
end
|| case
when instr(p_name, ' ', 1, 1) > 0
then ' + Masked'
end;
end short_name;
/
select short_name(name1) as result from users;
RESULT
------------------------------
Benjamin + Masked
Alexis Cruise + Masked
Christopher Lee + Masked
Madonna
The easiest way is to use regexp_replace:
regexp_replace(<text>,'\s+((\S+$)|(.*(\s+\S+$)))',' xxxx\4')
I don't want to go into detail how this exactly works, but you can read any guide about regular expressions to learn more.
create or replace function get_token
(in_str varchar2, in_token varchar2, in_separator varchar2 default ' ') return varchar2
as
begin
return regexp_substr (in_str, '[^' || in_separator || ']+', 1, in_token);
end;
/
select get_token('Christopher James Lee',1) || '****'
|| get_token('Christopher James Lee',3) from dual;

SQL return multiple rows as a single row

In our SQL-DB our four Limits are stored as separate rows.
I want to get the Limits back as a single row, with the four Limits as columns.
The Data looks like:
TABLE A
lsequence operator1 value1 operator2 value2
1 < 10.5 {NULL} {NULL}
2 >= 11.5 <= 12.5
3 >= 10.5 <= 13.5
4 > 13.5 {NULL} {NULL}
TABLE B
lsequence limittypeid
1 LowerFail
2 Pass
3 Warning
4 UpperFail
Wanted Return Value:
LowerFail Pass Warning UpperFail
< 10.5 >= 11.5 || <= 12.5 >= 10.5 || <= 13.5 > 13.5
With Case function bases on 'limittypeid' i get the 4 colums... But still 4 rows..
Current Return
COLUMN1 COLUMN2 COLUMN3 COLUMN4
< 10.5 ||
>= 11.5 || <= 12.5
>= 10.5 || <= 13.5
> 13.5 ||
Used Code:
SELECT
CASE
WHEN a.limittypeid = 'LowerFail'
THEN concat (b.operator1 , ' ' , b.value1 , ' || ' , b.operator2, ' ' , b.value2)
END,
CASE
WHEN a.limittypeid = 'Pass'
THEN concat (b.operator1 , ' ' , b.value1 , ' || ' , b.operator2, ' ' , b.value2)
END,
CASE
WHEN a.limittypeid = 'Warning'
THEN concat (b.operator1 , ' ' , b.value1 , ' || ' , b.operator2, ' ' , b.value2)
END,
CASE
WHEN a.limittypeid = 'UpperFail'
THEN concat (b.operator1 , ' ' , b.value1 , ' || ' , b.operator2 , ' ' , b.value2)
END
FROM
b
INNER JOIN b.lsequence = a.lsequence
WHERE ......conditions........
I know it must be possible.
You are just missing the GROUP BY. Use those column(s) that are unique for the expected rows.
More about this pivot technique: http://modern-sql.com/use-case/pivot
Use aggregation:
SELECT MAX(CASE WHEN a.limittypeid = 'LowerFail'
THEN concat(b.operator1 , ' ' , b.value1 , ' || ' , b.operator2, ' ' , b.value2)
END),
MAX(CASE WHEN a.limittypeid = 'Pass'
THEN concat(b.operator1 , ' ' , b.value1 , ' || ' , b.operator2, ' ' , b.value2)
END),
MAX(CASE WHEN a.limittypeid = 'Warning'
THEN concat(b.operator1 , ' ' , b.value1 , ' || ' , b.operator2, ' ' , b.value2)
END),
MAX(CASE WHEN a.limittypeid = 'UpperFail'
THEN concat(b.operator1 , ' ' , b.value1 , ' || ' , b.operator2 , ' ' , b.value2)
END)
FROM b INNER JOIN
a
ON b.lsequence = a.lsequence
WHERE ......conditions........;
The use of aggregations functions (MAX()) in the SELECT turns this into an aggregation query. With no GROUP BY, the query returns exactly one row.

Remove substring within aggregate

I am working in a data warehouse and combining 3 columns with the following:
CAST(
ISNULL(PORCH_TYPE_1,'') ||
CASE WHEN PORCH_TYPE_2 IS NULL THEN '' ELSE ', ' END ||
ISNULL(PORCH_TYPE_2,'') ||
CASE WHEN PORCH_TYPE_3 IS NULL THEN '' ELSE ', ' END ||
ISNULL(PORCH_TYPE_3,'') AS VARCHAR(250)
) AS PORCH_TYPE,
This is working, except in the results, I can end up with something that looks like:
Open Porch, None, None
or
None, None, Open Porch
What I'm needing to do is remove both
None
and
,None
How would I go about doing that within this same column/statement?
One method is to concatenate the comma to the end of each valid porch type. Then remove the final trailing comma using TRIM():
TRIM(TRAILING ',' FROM
((CASE WHEN PORCH_TYPE_1 <> 'None' THEN PORCH_TYPE_1 || ',' END) ||
(CASE WHEN PORCH_TYPE_2 <> 'None' THEN PORCH_TYPE_2 || ',' END) ||
(CASE WHEN PORCH_TYPE_3 <> 'None' THEN PORCH_TYPE_3 || ',' END)
)