duplicate column during pivot table - sql

I have a table like
select * from myTable
ID Type Prop1 Prop2 Prop3 Prop4 Prop5
-- ------ ------- ------- ------- ------- -------
1 Hot 10 9 23 32 4
1 Cold 2 24 53 34 5
2 Hot 11 9 23 32 4
2 Cold 22 1 53 30 11
I want to pivot my table like that
select * from myPivotTable
ID HotProp1 HotProp2 HotProp3 HotProp4 HotProp5 ColdProp1 ColdProp2 ColdProp3 ColdProp4 ColdProp5
-- ------- ------- ------- ------- -------- --------- --------- --------- --------- ---------
1 10 9 23 32 4 2 24 53 34 5
2 11 9 23 32 4 22 1 53 30 11
How can I convert myTable to myPivotTable using pivot function in oracle sql?

I think conditional aggregation is a much simpler query than a complex pivot:
select id,
sum(case when type = 'Hot' then Prop1 end) as Hot_Prop1,
sum(case when type = 'Hot' then Prop2 end) as Hot_Prop2,
sum(case when type = 'Hot' then Prop3 end) as Hot_Prop3,
sum(case when type = 'Hot' then Prop4 end) as Hot_Prop4,
sum(case when type = 'Hot' then Prop5 end) as Hot_Prop5,
sum(case when type = 'Cold' then Prop1 end) as Cold_Prop1,
sum(case when type = 'Cold' then Prop2 end) as Cold_Prop2,
sum(case when type = 'Cold' then Prop3 end) as Cold_Prop3,
sum(case when type = 'Cold' then Prop4 end) as Cold_Prop4,
sum(case when type = 'Cold' then Prop5 end) as Cold_Prop5
from myPivotTable
group by id;

If your Oracle version 11g and up you can simply "re-pivot" it(You have already pivoted data) - unpivot it first and then pivot again:
with t1(id1, type1, Prop1, Prop2, Prop3, Prop4, Prop5) as(
select 1, 'Hot' , 10 , 9 , 23,32 , 4 from dual union all
select 1, 'Cold', 2 , 24, 53,34 , 5 from dual union all
select 2, 'Hot' , 11 , 9 , 23,32 , 4 from dual union all
select 2, 'Cold', 22 , 1 , 53,30 , 11 from dual
)
select *
from( select *
from t1
unpivot (
val for col in (prop1, prop2, prop3, prop4, prop5)
)
)
pivot(
max(val) for (col, type1) in (('PROP1', 'Hot') as HotProp1,
('PROP2', 'Hot') as HotProp2,
('PROP3', 'Hot') as HotProp3,
('PROP4', 'Hot') as HotProp4,
('PROP5', 'Hot') as HotProp5,
('PROP1', 'Cold') as ColdProp1,
('PROP2', 'Cold') as ColdProp2,
('PROP3', 'Cold') as ColdProp3,
('PROP4', 'Cold') as ColdProp4,
('PROP5', 'Cold') as ColdProp5)
)
Result:
ID1 HOTPROP1 HOTPROP2 HOTPROP3 HOTPROP4 HOTPROP5 COLDPROP1 COLDPROP2 COLDPROP3 COLDPROP4 COLDPROP5
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
1 10 9 23 32 4 2 24 53 34 5
2 11 9 23 32 4 22 1 53 30 11
Here is the demo

Related

sql pivot multiple and partially similar row values into multiple unknown number of cols

To SELECT multiple CASE-WHEN expressions into a single row per ID I have used aggregation MAX and GROUPBY.
SELECT table1.IDvar,
MAX(CASE WHEN table2.var1 = 'foo' THEN table2.var2 END) AS condition1,
MAX(CASE WHEN table2.var1 = 'bar' THEN table2.var2 END) AS condition2
FROM table1
FULL JOIN table2 ON table1.IDvar = table2.table1_IDvar
GROUP BY table1.IDvar
However, I have observed that empirical criteria such as foo entered in the CASE-WHEN-THEN-END expression may occur multiple times, that is, in multiple rows each of which corresponds to different values on columns of interest (THEN column-of-interest END) in the db schema. This implies that taking the MAX or MIN drops data that may be of interest. It is not known in advance how many rows there are for each value in criteria_col and thus in the cols_of_interest.
Sample data e.g.:
IDvar_foreign_key
criteria_col
col_of_interest1
col_of_interest2
x1
foo
01-01-2021
100
x1
foo
01-06-2021
2000
x1
foo
01-08-2021
0
x1
bar
01-08-2021
300
Note: the actual table does contain a unique identifier or primary key.
Q: Are there ways to pivot certain columns/tables in a db schema without possibly dropping some values?
An ouput something like this:
IDvar_foreign_key
foo_1_col_of_interest1
foo_1_col_of_interest2
foo_2_col_of_interest1
foo_2_col_of_interest2
foo_3_col_of_interest1
foo_3_col_of_interest2
x1
01-01-2021
100
01-06-2021
2000
01-08-2021
0
Edit
#lemon and #MTO suggests dynamic queries are necesarry, otherwise I was considering whether not using aggregation would do
Dynamic Pivot in Oracle's SQL
Pivot rows to columns without aggregate
TSQL Pivot without aggregate function
You can use the MIN and MAX aggregation functions and to get the correlated minimums and maximums for col_of_interest2 you can use KEEP (DENSE_RANK ...):
SELECT t1.IDvar,
MIN(CASE WHEN t2.criteria_col = 'foo' THEN t2.col_of_interest1 END)
AS foo_1_col_of_interest1,
MIN(col_of_interest2) KEEP (
DENSE_RANK FIRST ORDER BY
CASE WHEN t2.criteria_col = 'foo' THEN t2.col_of_interest1 END
ASC NULLS LAST
) AS foo_1_col_of_interest2,
MAX(CASE WHEN t2.criteria_col = 'foo' THEN t2.col_of_interest1 END)
AS foo_2_col_of_interest1,
MAX(col_of_interest2) KEEP (
DENSE_RANK FIRST ORDER BY
CASE WHEN t2.criteria_col = 'foo' THEN t2.col_of_interest1 END
DESC NULLS LAST
) AS foo_2_col_of_interest2
FROM table1 t1
FULL JOIN table2 t2
ON t1.IDvar = t2.table1_IDvar
GROUP BY t1.IDvar
Which, for the sample data:
CREATE TABLE table1 ( idvar ) AS
SELECT 1 FROM DUAL UNION ALL
SELECT 2 FROM DUAL UNION ALL
SELECT 3 FROM DUAL;
CREATE TABLE table2 ( table1_idvar, criteria_col, col_of_interest1, col_of_interest2 ) AS
SELECT 1, 'foo', DATE '2021-01-01', 100 FROM DUAL UNION ALL
SELECT 1, 'foo', DATE '2021-03-01', 500 FROM DUAL UNION ALL
SELECT 1, 'foo', DATE '2021-06-01', 2000 FROM DUAL UNION ALL
SELECT 1, 'bar', DATE '2021-06-01', 2000 FROM DUAL UNION ALL
SELECT 2, 'foo', DATE '2021-01-02', 200 FROM DUAL UNION ALL
SELECT 2, 'foo', DATE '2021-03-02', 300 FROM DUAL UNION ALL
SELECT 2, 'bar', DATE '2021-06-02', 400 FROM DUAL UNION ALL
SELECT 3, 'foo', DATE '2021-01-03', 700 FROM DUAL;
Outputs:
IDVAR
FOO_1_COL_OF_INTEREST1
FOO_1_COL_OF_INTEREST2
FOO_2_COL_OF_INTEREST1
FOO_2_COL_OF_INTEREST2
1
2021-01-01 00:00:00
100
2021-06-01 00:00:00
2000
2
2021-01-02 00:00:00
200
2021-03-02 00:00:00
300
3
2021-01-03 00:00:00
700
2021-01-03 00:00:00
700
SQL (not just Oracle) requires each query to have a known, fixed number of columns; if you want a dynamic number of columns then you should perform the pivot in whatever third-party application (Java, C#, PHP, etc.) that you are using to talk to the database.
If you want to pivot a fixed maximum number of columns then you can use the ROW_NUMBER analytic function. For example, if you want the 3 minimum values for col_of_interest1 then you can use:
SELECT idvar,
MAX(CASE WHEN criteria_col = 'foo' AND rn = 1 THEN col_of_interest1 END)
AS foo_1_col_of_interest1,
MAX(CASE WHEN criteria_col = 'foo' AND rn = 1 THEN col_of_interest2 END)
AS foo_1_col_of_interest2,
MAX(CASE WHEN criteria_col = 'foo' AND rn = 2 THEN col_of_interest1 END)
AS foo_2_col_of_interest1,
MAX(CASE WHEN criteria_col = 'foo' AND rn = 2 THEN col_of_interest2 END)
AS foo_2_col_of_interest2,
MAX(CASE WHEN criteria_col = 'foo' AND rn = 3 THEN col_of_interest1 END)
AS foo_3_col_of_interest1,
MAX(CASE WHEN criteria_col = 'foo' AND rn = 3 THEN col_of_interest2 END)
AS foo_3_col_of_interest2
FROM (
SELECT t1.IDvar,
criteria_col,
col_of_interest1,
col_of_interest2,
ROW_NUMBER() OVER (
PARTITION BY t1.IDvar, criteria_col
ORDER BY col_of_interest1, col_of_interest2
) AS rn
FROM table1 t1
FULL JOIN table2 t2
ON t1.IDvar = t2.table1_IDvar
WHERE criteria_col IN ('foo' /*, 'bar', 'etc'*/)
)
GROUP BY idvar
Which outputs:
IDVAR
FOO_1_COL_OF_INTEREST1
FOO_1_COL_OF_INTEREST2
FOO_2_COL_OF_INTEREST1
FOO_2_COL_OF_INTEREST2
FOO_3_COL_OF_INTEREST1
FOO_3_COL_OF_INTEREST2
1
2021-01-01 00:00:00
100
2021-03-01 00:00:00
500
2021-06-01 00:00:00
2000
2
2021-01-02 00:00:00
200
2021-03-02 00:00:00
300
null
null
3
2021-01-03 00:00:00
700
null
null
null
null
fiddle
Unknown number of columns is an issue that you can't ignore. The question is - are there any possible expected limits. I question who would get any meaningfull insight from a resulting dataset with hundreds of columns. It doesnt make sense. If you could setup the limit to 10 or 20 or whatever like that then you could build a datagrid structure using pivot where the number of columns would be the same and the data within could be placed as in your question.
Just as an example how - here is the code that does it with up to 6 pairs of your data of interest (COL_DATE and COL_VALUE) - it could be 20 or 30 or ...
First your sample data and some preparation for pivoting (CTE named grid):
WITH -- S a m p l e d a t a
tbl AS
(
SELECT 1 "ID", 'foo' "CRITERIA", DATE '2021-01-01' "INTEREST_1", 100 "INTEREST_2" FROM DUAL UNION ALL
SELECT 1, 'foo', DATE '2021-03-01', 500 FROM DUAL UNION ALL
SELECT 1, 'foo', DATE '2021-06-01', 2000 FROM DUAL UNION ALL
SELECT 1, 'bar', DATE '2021-06-01', 2000 FROM DUAL UNION ALL
SELECT 2, 'foo', DATE '2021-01-02', 200 FROM DUAL UNION ALL
SELECT 2, 'foo', DATE '2021-03-02', 300 FROM DUAL UNION ALL
SELECT 2, 'bar', DATE '2021-06-02', 400 FROM DUAL UNION ALL
SELECT 3, 'foo', DATE '2021-01-03', 700 FROM DUAL
),
grid AS
(SELECT * FROM
( Select ID "ID", CRITERIA "GRP", INTEREST_1 "COL_DATE", INTEREST_2 "COL_VALUE",
Count(*) OVER(Partition By ID, CRITERIA) "ROWS_TOT",
ROW_NUMBER() OVER(Partition By ID, CRITERIA Order By ID, CRITERIA) "RN_GRP_ID",
ROW_NUMBER() OVER(Partition By ID, CRITERIA Order By ID, CRITERIA) "RN_GRP_ID_2"
From tbl t )
ORDER BY ID ASC, GRP DESC, ROWS_TOT DESC
),
Result (grid)
ID GRP COL_DATE COL_VALUE ROWS_TOT RN_GRP_ID RN_GRP_ID_2
---------- --- --------- ---------- ---------- ---------- -----------
1 foo 01-JAN-21 100 3 3 3
1 foo 01-JUN-21 2000 3 2 2
1 foo 01-MAR-21 500 3 1 1
1 bar 01-JUN-21 2000 1 1 1
2 foo 02-MAR-21 300 2 2 2
2 foo 02-JAN-21 200 2 1 1
2 bar 02-JUN-21 400 1 1 1
3 foo 03-JAN-21 700 1 1 1
... next is pivoting (another CTE named grid_pivot) and designing another grid that will be populated with your data of interest...
grid_pivot AS
( SELECT
ID, GRP, ROWS_TOT,
MAX(GRP_1_LINK) "GRP_1_LINK", CAST(Null as DATE) "GRP_1_DATE", CAST(Null as NUMBER) "GRP_1_VALUE",
MAX(GRP_2_LINK) "GRP_2_LINK", CAST(Null as DATE) "GRP_2_DATE", CAST(Null as NUMBER) "GRP_2_VALUE",
MAX(GRP_3_LINK) "GRP_3_LINK", CAST(Null as DATE) "GRP_3_DATE", CAST(Null as NUMBER) "GRP_3_VALUE",
MAX(GRP_4_LINK) "GRP_4_LINK", CAST(Null as DATE) "GRP_4_DATE", CAST(Null as NUMBER) "GRP_4_VALUE",
MAX(GRP_5_LINK) "GRP_5_LINK", CAST(Null as DATE) "GRP_5_DATE", CAST(Null as NUMBER) "GRP_5_VALUE",
MAX(GRP_6_LINK) "GRP_6_LINK", CAST(Null as DATE) "GRP_6_DATE", CAST(Null as NUMBER) "GRP_6_VALUE"
-- ... ... ... ...
FROM
( Select *
From ( Select * From grid )
PIVOT ( Max(RN_GRP_ID) "LINK" --Min(RN_GRP_ID) "GRP_FROM",
FOR RN_GRP_ID_2 IN(1 "GRP_1", 2 "GRP_2", 3 "GRP_3", 4 "GRP_4", 5 "GRP_5", 6 "GRP_6" ) ) -- ... ...
Order By ROWS_TOT DESC, GRP DESC, ID ASC
)
GROUP BY GRP, ROWS_TOT, ID
ORDER BY ROWS_TOT DESC, GRP DESC, ID ASC
)
Result (grid_pivot)
ID GRP ROWS_TOT GRP_1_LINK GRP_1_DATE GRP_1_VALUE GRP_2_LINK GRP_2_DATE GRP_2_VALUE GRP_3_LINK GRP_3_DATE GRP_3_VALUE GRP_4_LINK GRP_4_DATE GRP_4_VALUE GRP_5_LINK GRP_5_DATE GRP_5_VALUE GRP_6_LINK GRP_6_DATE GRP_6_VALUE
---------- --- ---------- ---------- ---------- ----------- ---------- ---------- ----------- ---------- ---------- ----------- ---------- ---------- ----------- ---------- ---------- ----------- ---------- ---------- -----------
1 foo 3 1 2 3
2 foo 2 1 2
3 foo 1 1
1 bar 1 1
2 bar 1 1
... and, finaly, mixing grid_pivot data with grid data using 6 left joins to fit 6 pairs of your data of interest into the grid.
SELECT gp.ID, gp.GRP,
g1.COL_DATE "GRP_1_DATE", g1.COL_VALUE "GRP_1_VALUE",
g2.COL_DATE "GRP_2_DATE", g2.COL_VALUE "GRP_2_VALUE",
g3.COL_DATE "GRP_3_DATE", g3.COL_VALUE "GRP_3_VALUE",
g4.COL_DATE "GRP_1_DATE", g4.COL_VALUE "GRP_4_VALUE",
g5.COL_DATE "GRP_2_DATE", g5.COL_VALUE "GRP_5_VALUE",
g6.COL_DATE "GRP_3_DATE", g6.COL_VALUE "GRP_6_VALUE"
-- ... ... ... ...
FROM grid_pivot gp
LEFT JOIN grid g1 ON(g1.ID = gp.ID And g1.GRP = gp.GRP And g1.RN_GRP_ID = gp.GRP_1_LINK)
LEFT JOIN grid g2 ON(g2.ID = gp.ID And g2.GRP = gp.GRP And g2.RN_GRP_ID = gp.GRP_2_LINK)
LEFT JOIN grid g3 ON(g3.ID = gp.ID And g3.GRP = gp.GRP And g3.RN_GRP_ID = gp.GRP_3_LINK)
LEFT JOIN grid g4 ON(g4.ID = gp.ID And g4.GRP = gp.GRP And g4.RN_GRP_ID = gp.GRP_4_LINK)
LEFT JOIN grid g5 ON(g5.ID = gp.ID And g5.GRP = gp.GRP And g5.RN_GRP_ID = gp.GRP_5_LINK)
LEFT JOIN grid g6 ON(g6.ID = gp.ID And g6.GRP = gp.GRP And g6.RN_GRP_ID = gp.GRP_6_LINK)
-- ... ... ... ...
ORDER BY gp.ROWS_TOT DESC, gp.GRP DESC, gp.ID ASC
R e s u l t :
ID GRP GRP_1_DATE GRP_1_VALUE GRP_2_DATE GRP_2_VALUE GRP_3_DATE GRP_3_VALUE GRP_1_DATE GRP_4_VALUE GRP_2_DATE GRP_5_VALUE GRP_3_DATE GRP_6_VALUE
---------- --- ---------- ----------- ---------- ----------- ---------- ----------- ---------- ----------- ---------- ----------- ---------- -----------
1 foo 01-MAR-21 500 01-JUN-21 2000 01-JAN-21 100
2 foo 02-JAN-21 200 02-MAR-21 300
3 foo 03-JAN-21 700
1 bar 01-JUN-21 2000
2 bar 02-JUN-21 400
Anyway you will probably need dynamic solution so, this could be interesting for something else, who knows what, when and where...

split column value into multiple columns in oracle sql

I have data into table like this:
I want the output like this:
how we can achive this with orace sql statment.Kindly assist.
instr(comp,':')
yields the first colon occurrence
instr(comp,':',1,2)
yields the second colon occurrence, and so forth
After that, its just math with combinations of INSTR on : and |
For example
substr(comp,2,instr(comp,':')-2)
for the first column before the colon
substr(comp,instr(comp,':')+1,instr(comp,'|')-instr(comp,':')-1)
for the first element after the colon and before the bar
and so forth.
This is one option; not dynamic at all as you'll have to know how many items there are so that you could adjust the final query. Read comments within code.
SQL> with test (id, component) as
2 -- sample data
3 (select 1, '|TD-2-2720A-NVE-C:2|TD-2-2720A-TPM-C:2|TD-PREM-NLSAS-01-PR:480|TD-ONTAP-NLSAS-01-PR:480' from dual union all
4 select 2, '|TD-2-A220A-TPM-C:2|DD-FLASH-PREM-01-PR:115|DD-FLASH-ONTAP-01-PR:115' from dual union all
5 select 5, '|TD-2-2650A-NVE-C:2|TD-2-2650A-TPM-C:2' from dual
6 ),
7 temp as
8 -- split each component into rows, separated by the pipe character
9 (select id,
10 column_value cv,
11 regexp_substr(component, '[^|]+', 1, column_value) comp
12 from test cross join
13 table(cast(multiset(select level from dual
14 connect by level <= regexp_count(component, '\|')
15 ) as sys.odcinumberlist))
16 )
17 -- final result
18 select id,
19 max(case when cv = 1 then substr(comp, 1, instr(comp, ':') - 1) end) as comp_1,
20 max(case when cv = 1 then regexp_substr(comp, '\d+$') end) as cnt_1,
21 --
22 max(case when cv = 2 then substr(comp, 1, instr(comp, ':') - 1) end) as comp_2,
23 max(case when cv = 2 then regexp_substr(comp, '\d+$') end) as cnt_2,
24 --
25 max(case when cv = 3 then substr(comp, 1, instr(comp, ':') - 1) end) as comp_3,
26 max(case when cv = 3 then regexp_substr(comp, '\d+$') end) as cnt_3,
27 --
28 max(case when cv = 4 then substr(comp, 1, instr(comp, ':') - 1) end) as comp_4,
29 max(case when cv = 4 then regexp_substr(comp, '\d+$') end) as cnt_4
30 from temp
31 group by id
32 order by id;
ID COMP_1 CNT_1 COMP_2 CNT_2 COMP_3 CNT_3 COMP_4 CNT_4
--- -------------------- ----- -------------------- ----- -------------------- ----- -------------------- -----
1 TD-2-2720A-NVE-C 2 TD-2-2720A-TPM-C 2 TD-PREM-NLSAS-01-PR 480 TD-ONTAP-NLSAS-01-PR 480
2 TD-2-A220A-TPM-C 2 DD-FLASH-PREM-01-PR 115 DD-FLASH-ONTAP-01-PR 115
5 TD-2-2650A-NVE-C 2 TD-2-2650A-TPM-C 2
SQL>

Get data based on condition in oracle sql

My table
loads(Unique) Value
T123 11
T234 9.5
T456 15
T678 35
T345 3.7
Want I want
count(values<=10) count(values>10 &<=20) count(values>20)
2 2 1
I tried to use CASE but don't know the usage
CASE yes; not with COUNT but with SUM:
SQL> with test (loads, value) as
2 (select 't123', 11 from dual union all
3 select 't234', 9.5 from dual union all
4 select 't456', 15 from dual union all
5 select 't678', 35 from dual union all
6 select 't345', 3.7 from dual
7 )
8 select
9 sum(case when value <= 10 then 1 end) cnt_1,
10 sum(case when value > 10 and value <= 20 then 1 end) cnt_2,
11 sum(case when value > 20 then 1 end) cnt_3
12 from test;
CNT_1 CNT_2 CNT_3
---------- ---------- ----------
2 2 1
SQL>
Use conditional aggregation as
select coalesce(sum(case when value<=10 then 1 end),0) as "values<=10",
coalesce(sum(case when value>10 and value<=20 then 1 end),0) as "values>10value<20",
coalesce(sum(case when value>20 then 1 end),0) as "values>20"
from your_table;

Queryin One-to-Many same table in Oracle

I have a below table with sample data as below:
prod seq catid
-------------------
prod1 0 10
prod1 1 20
prod1 2 30
prod1 3 40
prod2 0 10
prod3 0 10
prod3 1 20
prod3 2 30
prod4 0 10
I need to query above table based on catid column.
Ex: If i query with catid - 10 then i need to get all products(here prod2, prod3, prod4) which has only catid as 10 all the other should be excluded.
Same way if i query with catid = 10 20 30 then i need to get output as prod3, if i query with catid as 10 20 30 40 then my output should be prod1.
SELECT * FROM table WHERE catid = ALL (1,2,3,4,5)
I tried using ALL in my query but i am not able to get desired output, please help.
You can get the expected prod value using the query:
SELECT prod
FROM mytable
GROUP BY prod
HAVING COUNT(DISTINCT catId) = 5 AND
COUNT(CASE WHEN catId NOT IN (1,2,3,4,5) THEN 1 END) = 0
The above query returns products having 5 distinct catId values. None of these values doesn't belong to (1,2,3,4,5) set of values.
One way to do this is using conditional aggregation:
SELECT prod
FROM yourTable
GROUP BY prod
HAVING SUM(CASE WHEN catid = 1 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN catid = 2 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN catid = 3 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN catid = 4 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN catid = 5 THEN 1 ELSE 0 END) > 0
Here's a way that is more generalised - it relies on you passing in a string to the query consisting of a comma separated list (no spaces) into the query:
WITH your_table AS (SELECT 'prod1' prod, 0 seq, 10 catid FROM dual UNION ALL
SELECT 'prod1' prod, 0 seq, 20 catid FROM dual UNION ALL
SELECT 'prod1' prod, 0 seq, 30 catid FROM dual UNION ALL
SELECT 'prod1' prod, 0 seq, 40 catid FROM dual UNION ALL
SELECT 'prod2' prod, 0 seq, 10 catid FROM dual UNION ALL
SELECT 'prod3' prod, 0 seq, 10 catid FROM dual UNION ALL
SELECT 'prod3' prod, 0 seq, 20 catid FROM dual UNION ALL
SELECT 'prod3' prod, 0 seq, 30 catid FROM dual UNION ALL
SELECT 'prod4' prod, 0 seq, 10 catid FROM dual)
-- end of mimicking your table with sample data in it
-- see sql below:
SELECT yt.prod
FROM your_table yt
GROUP BY yt.prod
HAVING min(CASE WHEN ','||:p_string_to_compare||',' LIKE '%,'||yt.catid||',%' THEN 'Y'
ELSE 'N'
END) = 'Y'
AND count(*) = regexp_count(:p_string_to_compare, ',') + 1;
With :p_string = '10,40,30,20':
PROD
-----
prod1
With :p_string = '10,20,30':
PROD
-----
prod3
With :p_string = '10, 20':
no rows returned
With :p_string = '10':
PROD
-----
prod4
prod2

Intersect table with different column value

I have a table:
num type flag
--- ---- ----
11 A 1
12 A 1
13 A 1
14 A 1
15 A 1
12 B 2
13 B 2
How would I write a query to get the following result:
num type flag
--- ---- ----
11 A 1
14 A 1
15 A 1
select num
from your_table
where num not in
(
select num
from your_table
where type = 'B'
)
Try to use not exists as below
select *
from tab t
where t.type = 'A'
and not exists
(
select 1
from tab t1
where t1.type = 'B'
and t1.num=t.num
)