Split record with delimited value - oracle

I need to separate delimited string value into separate rows
What I need is:
FAILUREID TNO
1 t01
1 t02
1 t03
2 t04
2 t05
But using the code below I receided
1 t01
1 t02
1 t03
1 t03
1 t03
1 t02
1 t03
2 t04
2 t05
2 t05
Some lines are duplicated. Where is the bug in the code below, How to fix it ? ( distinct is not a solution)
with data as
( select 1 as FailureID
,'t01;t02;t03' as Tickets
from dual
union
select 2
,'t04;t05'
from dual
)
select FailureID
,regexp_substr(Tickets, '[^;]+', 1, level) as TNO
from data
connect by regexp_substr(tickets, '[^;]+', 1, level) is not null
order by failureid

Here's how (the difference begins at line #13):
SQL> with data as
2 ( select 1 as FailureID
3 ,'t01;t02;t03' as Tickets
4 from dual
5 union
6 select 2
7 ,'t04;t05'
8 from dual
9 )
10 select FailureID
11 ,regexp_substr(Tickets, '[^;]+', 1, column_value) as TNO
12 from data
13 cross join table(cast(multiset(select level from dual
14 connect by level <= regexp_count(tickets, ';') + 1
15 ) as sys.odcinumberlist))
16 order by failureid;
FAILUREID TNO
---------- -----------
1 t01
1 t02
1 t03
2 t04
2 t05
SQL>

Related

How to generate oracle rank and dense_rank function in Talend?

SQL> select ID,rank() over(order by ID) RANK , dense_rank() over(order by ID) DENSE_RANK from a;
ID RANK DENSE_RANK
1 1 1
1 1 1
2 3 2
3 4 3
3 4 3
4 6 4
5 7 5
5 7 5
6 9 6
7 10 7

Sum all columns in a row

How can I get a total results of all my rows? (for ORACLE)
SELECT
NAME,
SUM(CASE WHEN ASSIST_1 = 'YES' THEN 1 END) WEEK1,
SUM(CASE WHEN ASSIST_2 = 'YES' THEN 1 END) WEEK2,
SUM(CASE WHEN ASSIST_3 = 'YES' THEN 1 END) WEEK3,
FROM TABLE_NAME
WHERE GROUP BY NAME;
I have this results:
Name week1 week2 week3
Anne 1 2 3
Bob 3 1 0
Charlie 4 5 1
I want this result:
Anne 1 2 3
Bob 3 1 0
Charlie 4 5 1
Total 8 8 4
How can I get a total results of all my rows?
By using rollup() extension of the group by clause. Something like this(just an example):
-- sample of date from your question
with t1(uname, c1, c2, c3) as(
select 'Anne' , 1, 2, 3 from dual union all
select 'Bob' , 3, 1, 0 from dual union all
select 'Charlie', 4, 5, 1 from dual
)
-- actual query
select case grouping(uname)
when 0 then uname
else 'Total' end
as uname1
, sum(c1) as c1
, sum(c2) as c2
, sum(c3) as c3
from t1
group by rollup(uname)
order by grouping(uname)
Result:
UNAME1 C1 C2 C3
------- ---------- ---------- ----------
Anne 1 2 3
Bob 3 1 0
Charlie 4 5 1
Total 8 8 4
4 rows selected.
Use UNION ALL with SUM values
WITH t1(name, week1, week2, week3) AS
( SELECT 'Anne', 1, 2, 3 FROM dual
UNION ALL
SELECT 'Bob', 3, 1, 0 FROM dual
UNION ALL
SELECT 'Charlie', 4, 5, 1 FROM dual
),
s AS
(SELECT 'Total' name,
SUM(week1) week1,
SUM(week2) week2,
SUM(week2) week3
FROM t1
)
SELECT * FROM t1
UNION ALL
SELECT * FROM s;
Result:
NAME WEEK1 WEEK2 WEEK3
Anne 1 2 3
Bob 3 1 0
Charlie 4 5 1
Total 8 8 8
Base on #Nicholas answer:
SELECT
CASE GROUPING(NAME) WHEN 0 THEN NAME ELSE 'TOTAL' END AS NAME,
SUM (WEEK1) AS WEEK1,
SUM (WEEK2) AS WEEK2,
SUM (WEEK3) AS WEEK3
FROM (
SELECT
NAME,
SUM(CASE WHEN ASSIST_1 = 'YES' THEN 1 END) WEEK1,
SUM(CASE WHEN ASSIST_2 = 'YES' THEN 1 END) WEEK2,
SUM(CASE WHEN ASSIST_3 = 'YES' THEN 1 END) WEEK3,
FROM TABLE_NAME
WHERE GROUP BY (NAME)
GROUP BY ROLLUP(NAME)
ORDER BY GROUPING(NAME);
Give this result:
Anne 1 2 3
Bob 3 1 0
Charlie 4 5 1
Total 8 8 4

Oracle Connect By seems to produce too many rows

Oracle Database 12c Enterprise Edition Release 12.1.0.2.0
I expect I'm just missing something, but if I run this query without the "connect by", I get 2 rows. When I add "connect by level <= 4", I would expect to get each of those 2 rows 4 times. The actual result is different.
Can anyone help me understand what's happening here? I'm not looking for a solution that only repeats each row 4 times - I've already got that. I'm just looking to understand what's happening and why.
with alpha as (
select 1 as id
from dual
),
beta as (
select 1 as alpha_id,
1 as beta_no
from dual
union all
select 1 as alpha_id,
2 as beta_no
from dual
)
select a.id,
b.beta_no,
level as the_level
from alpha a
inner join beta b
on b.alpha_id = a.id
connect by level <= 4
order by a.id,
b.beta_no,
level
;
ID BETA_NO THE_LEVEL
1 1 1
1 1 2
1 1 2
1 1 3
1 1 3
1 1 3
1 1 3
1 1 4
1 1 4
1 1 4
1 1 4
1 1 4
1 1 4
1 1 4
1 1 4
1 2 1
1 2 2
1 2 2
1 2 3
1 2 3
1 2 3
1 2 3
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
30 rows selected
Many thanks to mathguy. The second link he provided in the answer below had exactly what I was looking for. Specifically:
1 with t as (select 1 as id from dual union all
2 select 2 from dual)
3 --
4 select id, level
5 ,prior id
6 ,sys_connect_by_path(id,'=>') as cpath
7 from t
8* connect by level <= 3
SQL> /
ID LEVEL PRIORID CPATH
---------- ---------- ---------- --------------------------------------------------
1 1 =>1
1 2 1 =>1=>1
1 3 1 =>1=>1=>1
2 3 1 =>1=>1=>2
2 2 1 =>1=>2
1 3 2 =>1=>2=>1
2 3 2 =>1=>2=>2
2 1 =>2
1 2 2 =>2=>1
1 3 1 =>2=>1=>1
2 3 1 =>2=>1=>2
2 2 2 =>2=>2
1 3 2 =>2=>2=>1
2 3 2 =>2=>2=>2
14 rows selected.
It's clear to me from that example, but I'd be hard-pressed to succinctly put it into words.
With no condition other than "level <= 4", every row from the original table, view etc. (from the join, in this case) will produce two rows at level 2, then four more rows at level 3, and 8 more at level 4. "Connect by" is essentially a succession of joins, and you are doing cross joins if you have no condition with the PRIOR operator.
You probably want to add "and prior a.id = a.id". This will lead to Oracle complaining about cycles (because Oracle decides a cycle is reached when it sees the same values in the columns subject to PRIOR). That, in turn, is solved by adding a third condition, usually "and prior sys_guid() is not null".
(Edited; the original answer made reference to NOCYCLE, which is not needed when using the "prior sys_guid() is not null" approach.)
This has been discussed recently on OTN: https://community.oracle.com/thread/3999985
Same question discussed here: https://community.oracle.com/thread/2526535
To illustrate Mathguy's answer, you are missing some predicates out of your CONNECT BY clause:
with alpha as (
select 1 as id
from dual
),
beta as (
select 1 as alpha_id,
1 as beta_no
from dual
union all
select 1 as alpha_id,
2 as beta_no
from dual
)
select a.id,
b.beta_no,
level as the_level
from alpha a
inner join beta b
on b.alpha_id = a.id
connect by level <= 4
AND PRIOR a.id = a.id
AND PRIOR b.beta_no = b.beta_no
AND PRIOR sys_guid() IS NOT NULL
order by a.id,
b.beta_no,
LEVEL;
ID BETA_NO THE_LEVEL
---------- ---------- ----------
1 1 1
1 1 2
1 1 3
1 1 4
1 2 1
1 2 2
1 2 3
1 2 4
An alternative would be to use the recursive with clause:
with alpha as (
select 1 as id
from dual
),
beta as (
select 1 as alpha_id,
1 as beta_no
from dual
union all
select 1 as alpha_id,
2 as beta_no
from dual
),
multiply (id, beta_no, rn) AS (SELECT a.id,
b.beta_no,
1 rn
FROM alpha a
INNER JOIN beta b
ON a.id = b.alpha_id
UNION ALL
SELECT ID,
beta_no,
rn + 1
FROM multiply
WHERE rn + 1 <= 4)
SELECT ID,
beta_no,
rn AS the_level
FROM multiply
order by id,
beta_no,
rn;
ID BETA_NO THE_LEVEL
---------- ---------- ----------
1 1 1
1 1 2
1 1 3
1 1 4
1 2 1
1 2 2
1 2 3
1 2 4

add a new column for unique ID in hive table

i have a table in hive with two columns: session_id and duration_time like this:
|| session_id || duration||
1 14
1 10
1 20
1 10
1 12
1 16
1 8
2 9
2 6
2 30
2 22
i want to add a new column with unique id when:
the session_id is changing or the duration_time > 15
i want the output to be like this:
session_id duration unique_id
1 14 1
1 10 1
1 20 2
1 10 2
1 12 2
1 16 3
1 8 3
2 9 4
2 6 4
2 30 5
2 22 6
any ideas how to do that in hive QL?
thanks!
SQL tables represent unordered sets. You need a column specifying the ordering of the values, because you seem to care about the ordering. This could be an id column or a created-at column, for instance.
You can do this using a cumulative sum:
select t.*,
sum(case when duration > 15 or seqnum = 1 then 1 else 0 end) over
(order by ??) as unique_id
from (select t.*,
row_number() over (partition by session_id order by ??) as seqnum
from t
) t;

Want to generate o/p as Below in Oracle

I need an o/p as below.
1,1
2,1
2,2
3,1
3,2
3,3
4,1
4,2
4,3
4,4
... and so on.
I tried to write the query as below. But throwing error. SIngle row subquery returns more than one row.
with test1 as(
SELECT LEVEL n
FROM DUAL
CONNECT BY LEVEL <59)
select n,(
SELECT LEVEL n
FROM DUAL
CONNECT BY LEVEL <n) from test1
Appreciate your help in solving the same.
Here is one of the methods how you could get the desired result:
SQL> with t1(col) as(
2 select level
3 from dual
4 connect by level <= 5
5 )
6 select a.col
7 , b.col
8 from t1 a
9 join t1 b
10 on a.col >= b.col
11 ;
COL COL
---------- ----------
1 1
2 1
2 2
3 1
3 2
3 3
4 1
4 2
4 3
4 4
5 1
5 2
5 3
5 4
5 5
15 rows selected

Resources