Flatten Feed logic in oracle - sql

I have a table with the below data,
id cd_used
1 trl
1 upf
2 upf
3 trl
3 trl
I have to apply flatten feed logic and derive the below output.
id cd_used
1 trlupf
2 upfonly
3 trlonly
One of the method was filter the table using cd_used and for for two subqueries, and the result of intersect can be added to trlupf, any other methods for implementing this?

WITH tab_temp
AS (SELECT 1 AS id, 'trl' AS cd_used FROM DUAL
UNION ALL
SELECT 1 AS id, 'upf' AS cd_used FROM DUAL
UNION ALL
SELECT 2 AS id, 'upf' AS cd_used FROM DUAL
UNION ALL
SELECT 3 AS id, 'trl' AS cd_used FROM DUAL
UNION ALL
SELECT 3 AS id, 'trl' AS cd_used FROM DUAL)
SELECT t.id,
LISTAGG (t.cd_used, '') WITHIN GROUP (ORDER BY t.cd_used DESC)
"cd_used"
FROM (SELECT DISTINCT
id,
CASE
WHEN COUNT (DISTINCT cd_used) OVER (PARTITION BY id) = 1
THEN
cd_used || 'Only'
ELSE
cd_used
END
cd_used
FROM tab_temp) t
GROUP BY t.id;

WITH tab_temp
AS (SELECT 1 AS id, 'trl' AS cd_used FROM DUAL
UNION ALL
SELECT 1 AS id, 'upf' AS cd_used FROM DUAL
UNION ALL
SELECT 2 AS id, 'upf' AS cd_used FROM DUAL
UNION ALL
SELECT 3 AS id, 'trl' AS cd_used FROM DUAL
UNION ALL
SELECT 3 AS id, 'trl' AS cd_used FROM DUAL)
, aggage as
(
select id, listagg (cd_used) within group (order by cd_used) as new_cd
from (select distinct id, cd_used from tab_temp)
group by id
)
select id, case
when new_cd in (select cd_used from tab_temp) then new_cd||'only'
else new_cd
end as cd_used
from aggage

Related

create date range from day based data

i have following source data...
id date value
1 01.08.22 a
1 02.08.22 a
1 03.08.22 a
1 04.08.22 b
1 05.08.22 b
1 06.08.22 a
1 07.08.22 a
2 01.08.22 a
2 02.08.22 a
2 03.08.22 c
2 04.08.22 a
2 05.08.22 a
and i would like to have the following output...
id date_from date_until value
1 01.08.22 03.08.22 a
1 04.08.22 05.08.22 b
1 06.08.22 07.08.22 a
2 01.08.22 02.08.22 a
2 03.08.22 03.08.22 c
2 04.08.22 05.08.22 a
Is this possible with Oracle SQL? Which functions do I need for this?
Based on the link provided by #astentx, try this solution:
SELECT
id, MIN("date") AS date_from, MAX("date") AS date_until, MAX(value) AS value
FROM (
SELECT
t1.*,
ROW_NUMBER() OVER(PARTITION BY id ORDER BY "date") -
ROW_NUMBER() OVER(PARTITION BY id, value ORDER BY "date") AS rn
FROM yourtable t1
)
GROUP BY id, rn
See db<>fiddle
WITH CTE (id, dateD,valueD)
AS
(
SELECT 1, TO_DATE('01.08.22','DD.MM.YY'), 'a' FROM DUAL UNION ALL
SELECT 1, TO_DATE('02.08.22','DD.MM.YY'), 'a'FROM DUAL UNION ALL
SELECT 1, TO_DATE('03.08.22','DD.MM.YY'), 'a'FROM DUAL UNION ALL
SELECT 1, TO_DATE('04.08.22','DD.MM.YY'), 'b'FROM DUAL UNION ALL
SELECT 1, TO_DATE('05.08.22','DD.MM.YY'), 'b'FROM DUAL UNION ALL
SELECT 2, TO_DATE('01.08.22','DD.MM.YY'), 'a'FROM DUAL UNION ALL
SELECT 2, TO_DATE('02.08.22','DD.MM.YY'), 'a'FROM DUAL UNION ALL
SELECT 2, TO_DATE('03.08.22','DD.MM.YY'), 'c'FROM DUAL
)
SELECT C.ID,C.VALUED,MIN(C.DATED)AS MIN_DATE,MAX(C.DATED)AS MAX_DATE
FROM CTE C
GROUP BY C.ID,C.VALUED
ORDER BY C.ID
https://dbfiddle.uk/?rdbms=oracle_18&fiddle=47c87d60445ce262cd371177e31d5d63

How to count distinct flags in the sql

BELOW IS SNIPPET OF MY DATA
Here is the sample creation code of testing.
CREATE TABLE MYGROUP ( Category,PERSON,Flag ) AS
SELECT 'Cat1','A','1' FROM DUAL
UNION ALL SELECT 'Cat1','A','0' FROM DUAL
UNION ALL SELECT 'Cat1','A','1' FROM DUAL
UNION ALL SELECT 'Cat1','B','1' FROM DUAL
UNION ALL SELECT 'Cat1','B','0' FROM DUAL
UNION ALL SELECT 'Cat2','A','0' FROM DUAL
UNION ALL SELECT 'Cat2','A','0' FROM DUAL
UNION ALL SELECT 'Cat2','A','0' FROM DUAL
UNION ALL SELECT 'Cat2','B','1' FROM DUAL
UNION ALL SELECT 'Cat2','B','1' FROM DUAL
UNION ALL SELECT 'Cat2','B','0' FROM DUAL
UNION ALL SELECT 'Cat3','X','0' FROM DUAL
UNION ALL SELECT 'Cat3','Y','0' FROM DUAL;
Desired Output:
Category - Count of Distinct Persons with Flag = 1
Cat1 - 2
Cat2 - 1
Cat3 - 0
I need to get my code in Big query to get distinct counts of persons. It shouldnt double count.
You can use conditional aggregation
SELECT
Category,
COUNT(DISTINCT CASE WHEN Flag = 1 THEN PERSON END)
FROM MYGROUP
GROUP BY Category;

converting comma separated value to multiple rows

I have a table like this:
ID NAME Dept_ID
1 a 2,3
2 b
3 c 1,2
Department is another table having dept_id and dept_name as columns. i want result like,
ID Name Dept_ID
1 a 2
1 a 3
2 b
3 c 1
3 c 2
any help please?
You can do it as:
--Dataset Preparation
with tab(ID, NAME,Dept_ID) as (Select 1, 'a', '2,3' from dual
UNION ALL
Select 2, 'b','' from dual
UNION ALL
Select 3, 'c' , '1,2' from dual)
--Actual Query
select distinct ID, NAME, regexp_substr(DEPT_ID,'[^,]+', 1, level)
from tab
connect by regexp_substr(DEPT_ID,'[^,]+', 1, level) is not null
order by 1;
Edit:
based on which column i need to join? in one table i have comma
separated ids and in other table i have just ids
with tab(ID, NAME,Dept_ID) as (Select 1, 'a', '2,3' from dual
UNION ALL
Select 2, 'b','' from dual
UNION ALL
Select 3, 'c' , '1,2' from dual) ,
--Table Dept
tbl_dept (dep_id,depname) as ( Select 1,'depa' from dual
UNION ALL
Select 2,'depb' from dual
UNION ALL
Select 3,'depc' from dual
) ,
--Seperating col values for join. Start your query from here using with clause since you already have the two tables.
tab_1 as (select distinct ID, NAME, regexp_substr(DEPT_ID,'[^,]+', 1, level) col3
from tab
connect by regexp_substr(DEPT_ID,'[^,]+', 1, level) is not null
order by 1)
--Joining table.
Select t.id,t.name,t.col3,dt.depname
from tab_1 t
left outer join tbl_dept dt
on t.col3 = dt.dep_id
order by 1
with tmp_tbl as(
select
1 ID,
'a' NAME,
'2,3' DEPT_ID
from dual
union all
select
2 ID,
'b' NAME,
'' DEPT_ID
from dual
union all
select
3 ID,
'c' NAME,
'1,2' DEPT_ID
from dual)
select
tmp_out.ID,
tmp_out.NAME,
trim(tmp_out.DEPT_ID_splited)
from(
select
tmp.ID,
tmp.NAME,
regexp_substr(tmp.DEPT_ID,'[^,]+', 1, level) DEPT_ID_splited
from
tmp_tbl tmp
connect by
regexp_substr(tmp.DEPT_ID,'[^,]+', 1, level) is not null) tmp_out
group by
tmp_out.ID,
tmp_out.NAME,
tmp_out.DEPT_ID_splited
order by
tmp_out.ID,
tmp_out.DEPT_ID_splited

How to count consecutive duplicates in a table?

I have below question:
Want to find the consecutive duplicates
SLNO NAME PG
1 A1 NO
2 A2 YES
3 A3 NO
4 A4 YES
6 A5 YES
7 A6 YES
8 A7 YES
9 A8 YES
10 A9 YES
11 A10 NO
12 A11 YES
13 A12 NO
14 A14 NO
We will consider the value of PG column and I need the output as 6 which is the count of maximum consecutive duplicates.
It can be done with Tabibitosan method. Run this, to understand it:
with a as(
select 1 slno, 'A' pg from dual union all
select 2 slno, 'A' pg from dual union all
select 3 slno, 'B' pg from dual union all
select 4 slno, 'A' pg from dual union all
select 5 slno, 'A' pg from dual union all
select 6 slno, 'A' pg from dual
)
select slno, pg, newgrp, sum(newgrp) over (order by slno) grp
from(
select slno,
pg,
case when pg <> nvl(lag(pg) over (order by slno),1) then 1 else 0 end newgrp
from a
);
Newgrp means a new group is found.
Result:
SLNO PG NEWGRP GRP
1 A 1 1
2 A 0 1
3 B 1 2
4 A 1 3
5 A 0 3
6 A 0 3
Now, just use a group by with count, to find the group with maximum number of occurrences:
with a as(
select 1 slno, 'A' pg from dual union all
select 2 slno, 'A' pg from dual union all
select 3 slno, 'B' pg from dual union all
select 4 slno, 'A' pg from dual union all
select 5 slno, 'A' pg from dual union all
select 6 slno, 'A' pg from dual
),
b as(
select slno, pg, newgrp, sum(newgrp) over (order by slno) grp
from(
select slno, pg, case when pg <> nvl(lag(pg) over (order by slno),1) then 1 else 0 end newgrp
from a
)
)
select max(cnt)
from (
select grp, count(*) cnt
from b
group by grp
);
with test as (
select 1 slno,'A1' name ,'NO' pg from dual union all
select 2,'A2','YES' from dual union all
select 3,'A3','NO' from dual union all
select 4,'A4','YES' from dual union all
select 6,'A5','YES' from dual union all
select 7,'A6','YES' from dual union all
select 8,'A7','YES' from dual union all
select 9,'A8','YES' from dual union all
select 10,'A9','YES' from dual union all
select 11,'A10','NO' from dual union all
select 12,'A11','YES' from dual union all
select 13,'A12','NO' from dual union all
select 14,'A14','NO' from dual),
consecutive as (select row_number() over(order by slno) rr, x.*
from test x)
select x.* from Consecutive x
left join Consecutive y on x.rr = y.rr+1 and x.pg = y.pg
where y.rr is not null
order by x.slno
And you can control output with condition in where.
where y.rr is not null query returns duplicates
where y.rr is null query returns "distinct" values.
Just for completeness, here's the actual Tabibitosan method:
with sample_data as (select 1 slno, 'A1' name, 'NO' pg from dual union all
select 2 slno, 'A2' name, 'YES' pg from dual union all
select 3 slno, 'A3' name, 'NO' pg from dual union all
select 4 slno, 'A4' name, 'YES' pg from dual union all
select 6 slno, 'A5' name, 'YES' pg from dual union all
select 7 slno, 'A6' name, 'YES' pg from dual union all
select 8 slno, 'A7' name, 'YES' pg from dual union all
select 9 slno, 'A8' name, 'YES' pg from dual union all
select 10 slno, 'A9' name, 'YES' pg from dual union all
select 11 slno, 'A10' name, 'NO' pg from dual union all
select 12 slno, 'A11' name, 'YES' pg from dual union all
select 13 slno, 'A12' name, 'NO' pg from dual union all
select 14 slno, 'A14' name, 'NO' pg from dual)
-- end of mimicking a table called "sample_data" containing your data; see SQL below:
select max(cnt) max_pg_in_queue
from (select count(*) cnt
from (select slno,
name,
pg,
row_number() over (order by slno)
- row_number() over (partition by pg
order by slno) grp
from sample_data)
where pg = 'YES'
group by grp);
MAX_PG_IN_QUEUE
---------------
6
SELECT MAX(consecutives) -- Block 1
FROM (
SELECT t1.pg, t1.slno, COUNT(*) AS consecutives -- Block 2
FROM test t1 INNER JOIN test t2 ON t1.pg = t2.pg
WHERE t1.slno <= t2.slno
AND NOT EXISTS (
SELECT * -- Block 3
FROM test t3
WHERE t3.slno > t1.slno
AND t3.slno < t2.slno
AND t3.pg != t1.pg
)
GROUP BY t1.pg, t1.slno
);
The query calculates the result in following way:
Extract all couples of records that don't have a record with different value of PG in between (blocks 2 and 3)
Group them by PG value and starting SLNO value -> this counts the consecutive values for any [PG, (starting) SLNO] couple (block 2);
Extract Maximum value from query 2 (block 1)
Note that the query may be simplified if the slno field in table contains consecutive values, but this seems not your case (in your example record with SLNO = 5 is missing)
Only requiring a single aggregation query and no joins (the rest of the calculation can be done with ROW_NUMBER, LAG and LAST_VALUE):
SELECT MAX( num_before_in_queue ) AS max_sequential_in_queue
FROM (
SELECT rn - LAST_VALUE( has_changed ) IGNORE NULL OVER ( ORDER BY ROWNUM ) + 1
AS num_before_in_queue
FROM (
SELECT pg,
ROW_NUMBER() OVER ( ORDER BY slno ) AS rn,
CASE pg WHEN LAG( pg ) OVER ( ORDER BY slno )
THEN NULL
ELSE ROW_NUMBER() OVER ( ORDER BY sl_no )
END AS change
FROM table_name
)
WHERE pg = 'Y'
);
Try to use row_number()
select
SLNO,
Name,
PG,
row_number() over (partition by PG order by PG) as 'Consecutive'
from
<table>
order by
SLNO,
NAME,
PG
This is should work with minor tweaking.
--EDIT--
Sorry, partiton by PG.
The partitioning tells the row_number when to start a new sequence.

Find count value for a different group with reference with single column (Oracle)

I have the below scenario data. I need a count for column 'c1' with different set of data. total count should be based on unique no of data from column c1 and e1.
with t as
(
select 'cab1' as c1, 'ae1' as e1 from dual
union all
select 'cab1' , 'ae2' from dual
union all
select 'cab1' , 'ae3' from dual
union all
select 'cab1' , 'ae4' from dual
union all
select 'cab3' , 'ae1' from dual
union all
select 'cab3' , 'ae1' from dual
union all
select 'cab2' , 'ae' from dual
)
select
c1,e1, COUNT(*) OVER (partition by c1 order by c1,e1 ) as p1
from t;
my result should be
c1 e1 count
-----------------------
cab1 ae3 4
cab1 ae2 4
cab1 ae1 4
cab1 ae4 4
cab2 ae 1
cab3 ae1 1
Can anyone help on this.
SqlFiddleDemo
with t as
(
select 'cab1' as c1, 'ae1' as e1 from dual
union all
select 'cab1' , 'ae2' from dual
union all
select 'cab1' , 'ae3' from dual
union all
select 'cab1' , 'ae4' from dual
union all
select 'cab3' , 'ae1' from dual
union all
select 'cab3' , 'ae1' from dual
union all
select 'cab2' , 'ae' from dual
)
SELECT
c1,
e1,
COUNT(*) OVER (partition by c1) as p1
FROM t
GROUP BY c1, e1