How to group sub strings in Teradata? - teradata

I have the following table in Teradata 14 , however I am not allowed to write procedures and functions myself
id property
1 1234X (Yel), 2345Y (Red), 1234X (Gre),
2 2222Y (Pin), 2222Y (Red), 2222Y (Gre),
3 3454E (Yel), 4565Y (Whi), 3454E (Red),
All rows are in the same fashion. E.g. row 1 : 1234X is an object that has attributes (Yel) and (Gre) . Whereas 2345Y has Red
How can I group the above table so that each object would have all attributes listed in one brackets
id property
1 1234X (Yel Gre), 2345Y (Red),
2 2222Y (Pin Red Gre ),
3 3454E (Yel Red), 4565Y (Whi),

WITH chunk(id,property,a,b,c,combined) AS
(SEL id,
property,
STRTOK(property, ',', 1) AS a,
STRTOK(property, ',', 2) AS b,
STRTOK(property, ',', 3) AS c,
CASE WHEN SUBSTRING(TRIM(a),1,5)=SUBSTRING(TRIM(b),1,5) AND SUBSTRING(TRIM(a),1,5) <>SUBSTRING(TRIM(c),1,5)
THEN SUBSTRING(TRIM(a),1,10) || ' ' || SUBSTRING(TRIM(b),8,3)||')'||','||c||','
WHEN SUBSTRING(TRIM(a),1,5)=SUBSTRING(TRIM(c),1,5) AND SUBSTRING(TRIM(a),1,5)<>SUBSTRING(TRIM(b),1,5)
THEN SUBSTRING(TRIM(a),1,10) || ' ' || SUBSTRING(TRIM(c),8,3)||')' ||','||TRIM(b)||','
WHEN SUBSTRING(TRIM(a),1,5)=SUBSTRING(TRIM(b),1,5) AND SUBSTRING(TRIM(a),1,5)=SUBSTRING(TRIM(c),1,5)
THEN SUBSTRING(TRIM(a),1,10) || ' ' || SUBSTRING(TRIM(b),8,3)||' '||SUBSTRING(TRIM(c),8,4)||','
ELSE 'Condition failed'
END AS combined
FROM Table2)
SELECT id,combined FROM chunk
ORDER BY id ;
OUTPUT #
id combined
1 1234X (Yel Gre),2345Y (Red),
2 2222Y (Pin Red Gre),
3 3454E (Yel Red),4565Y (Whi),
Dynamic way :
Is it possible to group string within a string in Teradata?
Modified#
SEL id
, property
, SUBSTRING (property FROM 1 FOR INSTR(property, ',', 1, 1)-1 ) AS a
, SUBSTRING (property FROM INSTR(property, ',', 1, 1)+1 FOR INSTR(property, ',', 1, 2) -INSTR(property, ',', 1, 1)-1 ) AS b
, SUBSTRING (property FROM INSTR(property, ',', 1, 2)+1 FOR INSTR(property, ',', 1, 3) -INSTR(property, ',', 1, 2)-1 ) AS c
,CASE
WHEN SUBSTRING(TRIM(a),1,5)=SUBSTRING(TRIM(b),1,5) AND SUBSTRING(TRIM(a),1,5)<>SUBSTRING(TRIM(c),1,5)
THEN SUBSTRING(TRIM(a),1,10) || ' ' || SUBSTRING(TRIM(b),8,3)||')'||','||c||','
WHEN SUBSTRING(TRIM(a),1,5)=SUBSTRING(TRIM(c),1,5) AND SUBSTRING(TRIM(a),1,5)<>SUBSTRING(TRIM(b),1,5)
THEN SUBSTRING(TRIM(a),1,10) || ' ' || SUBSTRING(TRIM(c),8,3)||')' ||','||TRIM(b)||','
WHEN SUBSTRING(TRIM(a),1,5)=SUBSTRING(TRIM(b),1,5) AND SUBSTRING(TRIM(a),1,5)=SUBSTRING(TRIM(c),1,5)
THEN SUBSTRING(TRIM(a),1,10) || ' ' || SUBSTRING(TRIM(b),8,3)||' '||SUBSTRING(TRIM(c),8,4)||','
ELSE 'Condition failed'
END AS combined
FROM table2 ;

Related

SQLite convert single row to multiple rows

SQLite
I want to convert single row value seperate by ',' to multiple rows
Example :
Single_Row
6,7,8,9,10,11,12,13,14,15,16
Result must be :
MultipleRows
6
7
8
9
10
12
13
14
15
16
I tried doing it with substr function but getting unexpected result
select
numbers.n,
substr(CbahiHSSpecialtyUnits.units,numbers.n,1)
from
numbers inner join CbahiHSSpecialtyUnits
on LENGTH(CbahiHSSpecialtyUnits.units)
- LENGTH(REPLACE(CbahiHSSpecialtyUnits.units, ',', ''))>=numbers.n-1
WHERE HsSubStandardID=22 and SpecialtyID=2 and numbers.n>0
order by numbers.n;
One good thing is I'm getting number of rows correct.. But the values that should be separated is wrong ..
Please note numbers table is I have created for indexing purpose, with the help of this post.
SQL split values to multiple rows
You can do it with a recursive CTE:
WITH cte AS (
SELECT SUBSTR(Units, 1, INSTR(Units || ',', ',') - 1) col,
SUBSTR(Units, INSTR(Units || ',', ',') + 1) value
FROM CbahiHSSpecialtyUnits
WHERE HsSubStandardID=22 AND SpecialtyID = 2
UNION ALL
SELECT SUBSTR(value, 1, INSTR(value || ',', ',') - 1),
SUBSTR(value, INSTR(value || ',', ',') + 1)
FROM cte
WHERE LENGTH(value) > 0
)
SELECT col
FROM cte
WHERE col + 0 > 0
Or, if you know the upper limit of the numbers is, say 20 and there are no duplicates among the numbers:
WITH cte AS (SELECT 1 col UNION ALL SELECT col + 1 FROM cte WHERE col < 20)
SELECT c.col
FROM cte c INNER JOIN CbahiHSSpecialtyUnits u
ON ',' || u.Units || ',' LIKE '%,' || c.col || ',%'
WHERE HsSubStandardID=22 AND SpecialtyID = 2
See the demo.
Results:
col
6
7
8
9
10
11
12
13
14
15
16
I got the solution
http://www.samuelbosch.com/2018/02/split-into-rows-sqlite.html
WITH RECURSIVE split(predictorset_id, predictor_name, rest) AS (
SELECT CbahiHSSpecialtyUnits.SpclUnitSerial, '', units || ',' FROM CbahiHSSpecialtyUnits WHERE HsSubStandardID=22 and SpecialtyID=2
UNION ALL
SELECT predictorset_id,
substr(rest, 0, instr(rest, ',')),
substr(rest, instr(rest, ',')+1)
FROM split
WHERE rest <> ''

Select multiple columns using decode

I have 6 columns with same value as either of 0,1,2,3. I want to display the result such as 0 represents SUCCESS, 1 or 2 represent failure and 3 represents NOT APPLICABLE. So if in DB the values are :
col A | col B | col C | col D | col E | col F
0 | 1 | 2 | 0 | 3 | 2
Output should be :
col A | col B | col C | col D | col E | col F
S | F | F | S | NA | F
Is it possible to do it through decode by selecting all the columns at once rather than selecting them individually?
If I understand your question correctly, it sounds like you just need a case expression (or decode, if you prefer, but that's less self-documenting than a case expression), along the lines of:
case when some_col = 0 then 'S'
when some_col in (1, 2) then 'F'
...
else some_col -- replace with whatever you want the output to be if none of the above conditions are met
end
or maybe:
case some_col
when 0 then 'S'
when 1 then 'F'
...
else some_col -- replace with whatever you want the output to be if none of the above conditions are met
end
So your query would look something like:
select case ...
end col_a,
...
case ...
end col_f
from your_table;
Is it possible to do it through decode by selecting all the columns at once rather than selecting them individually?
No
However, besides using pivot, the only solution I see would be using PL/SQL:
1.This is how I simulated your table
SELECT *
FROM (WITH tb1 (col_a, col_b, col_c, col_d, col_e, col_f) AS
(SELECT 0, 1, 2, 0, 3, 2 FROM DUAL)
SELECT *
FROM tb1)
2.I would append the columns together with a comma between them and save them into a table of strings
SELECT col_a || ',' || col_b || ',' || col_c || ',' || col_d || '.' || col_e || ',' || col_f
FROM (WITH tb1 (col_a, col_b, col_c, col_d, col_e, col_f) AS (SELECT 0, 1, 2, 0, 3, 2 FROM DUAL)
SELECT *
FROM tb1)
3.Then I would use REGEXP_REPLACE to replace your values one row at a time
SELECT REPLACE (REGEXP_REPLACE (REPLACE ('0,1,2,0,3,2', 0, 'S'), '[1-2]', 'F'), 3, 'NA') COL_STR
FROM DUAL
4. Using dynamic SQL I would update the table using rowid or whatever you intend to do. I made this SQL which will separate the string into columns
SELECT REGEXP_SUBSTR (COL_STR, '[^,]+', 1, 1) AS COL_A,
REGEXP_SUBSTR (COL_STR, '[^,]+', 1, 2) AS COL_B,
REGEXP_SUBSTR (COL_STR, '[^,]+', 1, 3) AS COL_C,
REGEXP_SUBSTR (COL_STR, '[^,]+', 1, 4) AS COL_D,
REGEXP_SUBSTR (COL_STR, '[^,]+', 1, 5) AS COL_E,
REGEXP_SUBSTR (COL_STR, '[^,]+', 1, 6) AS COL_F
FROM tst1)
All of this is very tedious and it could take some time. Using DECODE or CASE would be easier to look at and interpret and thus easier to maintain.

How to use sum and joins within group_concat

I have two tables, CustomerCategories and Articles. Both tables have a column called VatPercentage and VatPrice.
Scenarios:
In case of same vatpercentage exists in both tables i want to sum the vatprice from both tables and add it to the string.
In case of vatpercentage only exists in CustomerCategories table i want to sum the vatprice from here and add it to the string.
In case of vatpercentage only exists in Articles table i want to sum the vatprice from here and add it to the string.
Example tables:
Articles:
ArticleId TotalPrice VatPercentage VatPrice
1 100 25.0000000000 25
2 80 25.0000000000 20
3 50 8.0000000000 4
4 70 8.0000000000 5.6
5 20 0 0
6 0 0 0
CustomerCategories:
CustomerCategoryId TotalPrice VatPercentage VatPrice
2 163 8.0000000000 13
2 163 13.0000000000 13
2 163 0 0
2 150 25.0000000000 37.5
The result i want back from the Query in this case:
{esc}{40h}25 %{esc}{41h}82.5 NOK{lf}{esc}{40h}8 %{esc}{41h}22.6 NOK{lf}{esc}{40h}13 %{esc}{41h}13 NOK{lf}
The code i've trying without any positive results is:
SELECT GROUP_CONCAT(Result, '|') Results
FROM (
select case when cc.VatPercentage = a.VatPercentage
then
SELECT '{esc}{40}' || CAST(cc.VatPercentage AS INTEGER) || '% ' ||
(SUM(cc.VatPrice) + SUM(a.VatPrice)) || ' NOK' || '{lf}' Result end
else
(
case when cc.VatPercentage <> a.VatPercentage
then
SELECT '{esc}{40}' || CAST(cc.VatPercentage AS INTEGER) || '% ' ||
(SUM(cc.VatPrice) + SUM(a.VatPrice)) || ' NOK' || '{lf}' ||
SELECT '{esc}{40}' || CAST(a.VatPercentage AS INTEGER) || '% ' ||
(SUM(a.VatPrice)) || ' NOK' || '{lf}' Result
end
)
FROM CustomerCategories cc
LEFT JOIN Articles a
on cc.VatPercentage = a.VatPercentage
WHERE
cc.VatPercentage != '0'
AND a.VatPercentage != '0'
AND cc.TotalPrice != '0'
AND a.TotalPrice != '0'
GROUP BY
cc.VatPercentage OR a.VatPercentage) x
Help would be appreciated.
Fiddle
First, combine both tables:
SELECT VatPercentage, VatPrice FROM CustomerCategories
UNION ALL
SELECT VatPercentage, VatPrice FROM Articles
VatPercentage VatPrice
8.0000000000 13
13.0000000000 13
0 0
25.0000000000 37.5
25.0000000000 25
25.0000000000 20
8.0000000000 4
8.0000000000 5.6
0 0
0 0
Then do a simple GROUP BY over that:
SELECT VatPercentage,
SUM(VatPrice) AS PriceSum
FROM (SELECT VatPercentage, VatPrice FROM CustomerCategories
UNION ALL
SELECT VatPercentage, VatPrice FROM Articles)
WHERE VatPercentage != '0'
GROUP BY VatPercentage
Then do the escape characters mess over the result of that:
SELECT GROUP_CONCAT('{esc}{40h}' || VatPercentage || ' %' ||
'{esc}{41h}' || VatPrice || ' NOK{lf}',
'')
FROM (SELECT VatPercentage,
SUM(VatPrice) AS PriceSum
FROM (SELECT VatPercentage, VatPrice FROM CustomerCategories
UNION ALL
SELECT VatPercentage, VatPrice FROM Articles)
WHERE VatPercentage != '0'
GROUP BY VatPercentage)

SQL count all of the column that has a value greater than 10 and sum it up

I want to count all of the column in my table that has value >= 10.
here is my table :
Date ##### || Value1 || Value2 || Value3
23/04/2014 || __ 1,2 || __ 12,3 ||__ 10 ||
23/04/2014 ||__ 11,2 || ____ 3 || __ 10,3 ||
24/04/2014 || __ 10,9 || ____ 3 || __ 1 ||
I want it to display:
Date ##### || Count ||
23/04/2014 || __ 4 ||
24/04/2014 || __ 1 ||
Assume that I have a lot of date, I want it to display only the last 3 rows.
here is my first code :
Dim strCommand As String = "Select Date, count(*) as tcount from tbBooth having count(*) >= 10 group by date"
already changed based on the solution from Collapsar into this:
Dim strCommand As String = "Select t.d, sum(t.valcount) cnt from (select [date] AS d, CASE WHEN t1.ManualAssists1 >= 10 THEN 1 ELSE 0 END + CASE WHEN t1.ManualAssists2 >= 10 THEN 1 ELSE 0 END + CASE WHEN t1.ManualAssists3 >= 10 THEN 1 ELSE 0 END AS valcount from tbBooth t1) t group by t.d"
it's works, but I want to display only the last 3 row based on ASC order.
Is there anyway how to do it?
Thanks in advances....
try
select t.d
, sum(t.valcount) cnt
from (
select [date] AS d
, CASE WHEN t1.value1 >= 10 THEN 1 ELSE 0 END
+ CASE WHEN t1.value2 >= 10 THEN 1 ELSE 0 END
+ CASE WHEN t1.value3 >= 10 THEN 1 ELSE 0 END
AS valcount
from table t1
) t
group by t.d
;
SELECT
D,
SUM(one + two + three) AS tcount
FROM
(
SELECT
[Date] AS D,
CASE WHEN Value1 >= 10 THEN 1 ELSE 0 END AS one,
CASE WHEN Value2 >= 10 THEN 1 ELSE 0 END AS two,
CASE WHEN Value3 >= 10 THEN 1 ELSE 0 END AS three
FROM
tbBooth
)
GROUP BY
D

Oracle: Script similar to describe command

I'm being asked to create a script that basically does the same thing as the describe command.
I have figured out how to write the script and get the output I want, but the second part of the assignment is to "duplicate the format of the describe command" I'm stumped, is there really a way to simply duplicate that format?
Assuming your query is something like (note that I'm not bothering to handle every different data type)
select column_name "Name",
(case when nullable = 'N'
then 'NOT NULL'
else null
end) "Null?",
(case when data_type = 'DATE'
then data_type
when data_type = 'NUMBER' and data_scale > 0
then data_type || '(' || data_precision || ',' || data_scale || ')'
when data_type = 'NUMBER' and data_scale = 0
then data_type || '(' || data_precision || ')'
when data_type = 'VARCHAR2'
then data_type || '(' || data_length || ')'
end) "Type"
from dba_tab_cols
where table_name = 'EMP'
order by column_id
You can issue some SQL*Plus commands to format the output
SQL> column "Nmae" format a30;
SQL> column "Null?" format a8;
SQL> column "Type" format a30;
and then the output of your query will match up with the output of the DESCRIBE command
SQL> ed
Wrote file afiedt.buf
1 select column_name "Name",
2 (case when nullable = 'N'
3 then 'NOT NULL'
4 else null
5 end) "Null?",
6 (case when data_type = 'DATE'
7 then data_type
8 when data_type = 'NUMBER' and data_scale > 0
9 then data_type || '(' || data_precision || ',' || data_scale || ')'
10 when data_type = 'NUMBER' and data_scale = 0
11 then data_type || '(' || data_precision || ')'
12 when data_type = 'VARCHAR2'
13 then data_type || '(' || data_length || ')'
14 end) "Type"
15 from dba_tab_cols
16 where table_name = 'EMP'
17* order by column_id
SQL> /
Name Null? Type
------------------------------ -------- ------------------------------
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)
8 rows selected.

Resources