Insert new rows based on conditions - Oracle SQL - sql

I have a table:
table1
unique_id col_id col_nm col_val sequ
1 1 testq 1 100 1
1 2 testc 1 abc 1
1 1 testq 1 101 2
1 2 testc 1 xyz 2
1 5 test 5 10 1
1 8 test 6 100 1
2 1 testq 1 100 1
2 2 testc 1 pqr 1
2 1 testq 1 101 2
2 2 testc 1 xxy 2
2 5 test 5 qqw 1
2 8 test 6 100 1
I need to insert new rows in the table based on the following condition:
Find unique_id and sequ of col_id = 1 and col_nm = 'testq 1' and col_val = 100
Find col_val of col_id = 2 and col_nm = 'testc 1' and sequ = {sequ of step 1} and unique_id = {unique_id of step 1}.
Insert a new row for the corresponding unique_id, with col_id = 100, col_nm = 'test q100c', col_val = {col_val found in step 2}, sequ = {sequ found in step 2}
The output would be:
unique_id col_id col_nm col_val sequ
1 1 testq 1 100 1
1 2 testc 1 abc 1
1 1 testq 1 101 2
1 2 testc 1 xyz 2
1 5 test 5 10 1
1 8 test 6 100 1
1 100 test q100c abc 1
2 1 testq 1 100 2
2 2 testc 1 pqr 2
2 1 testq 1 101 2
2 2 testc 1 xxy 2
2 5 test 5 qqw 1
2 8 test 6 100 1
2 100 test q100c pqr 2
Is there anyway in SQL to achieve this?

We can use WITH clause in an INSERT … SELECT construct. So something like this?
insert into table1
with s1 as (
select t.unique_id
, t.sequ
from table1 t
where t.col_id = 1
and t.col_nm = 'testq 1'
and t.col_val = 100 )
, s2 as (
select s1.*
, t.col_val
from s1
join table1 t
on t.sequ = s1.sequ
and t.unique_id = s1.unique_id
where t.col_id = 2
and t.col_nm = 'testc 1'
)
select s2.unique_id
,100 as col_id
,'test q100c' as col_nm
,s2.col_val
,s2.sequ
from s2
/
I'm not sure I have entirely understood your rules - I used the col_val from step #2 (which is what your expected output shows) rather than the value from step #1 as your rule 3 states - but I hope this gives you a start. Also, this may not be a very efficient approach. I offer no guarantees regarding performance over a large volume of data.

Related

oracle query with groupby clause

i have a upload table as follows:
bulk_upload_hist
id file_name doc_blob upload_date upload_by
10 abc.pdf 12-APR-21 123
11 xyz.pdf 12-APR-21 123
inventory history stores the records from the file as follows:
inventory_doc_hist
id upload_id upload_status create_date create_by inv_doc_type
1 10 1 12-APR-21 123 20
2 10 1 12-APR-21 123 20
3 10 0 12-APR-21 123 10
4 10 1 12-APR-21 123 10
4 11 1 12-APR-21 123 20
5 11 0 12-APR-21 123 10
I want my output per bulk upload as follows:
id file_name successful/10 Successful/20 UnSuccessful upload_date upload_by
10 abc.pdf 2 1 1 12-APR-21 123
11 xyz.pdf 1 1 0 12-APR-21 123
what is the best way to do this?
I think you want a join and conditional aggregation:
select buh.id, buh.file_name,
sum(case when ih.inv_doc_type = 10 then 1 else 0 end) as num_successful_10,
sum(case when ih.inv_doc_type = 20 then 1 else 0 end) as num_successful_20,
sum(case when ih.inv_doc_type not in (10, 20) then 1 else 0 end) as num_successful_20,
ih.upload_date, ih.upload_by
from bulk_upload_hist buh join
inventory_history ih
on ih.upload_id = ih.id
group by buh.id, buh.file_name, ih.upload_date, ih.upload_by;

re-indexing duplicate rows

Hi I have a table below;
ID length
1 1050
1 1000
1 900
1 600
2 545
2 434
3 45
3 7
4 5
I need an SQL code to make the below table
ID IDK length
1 1 1050
1 2 1000
1 3 900
1 4 600
2 1 545
2 2 434
3 1 45
3 2 7
4 1 5
IDK is the new column to reindexing the same ID according to ascending order of length.
Thank you very much
This is a pain in MS Access. Here is one way using a correlated subquery:
select t.*,
(select count(*)
from foo as t2
where t2.id = t.id and t2.length >= t.length
) as idk
from foo as t;

if Sum Exceeds show new record with the values left in next line

A B C D
12426 4 1 KT1217V
12426 4 1 KT1218V
12428 3 1 KT1217V
12428 3 1 KT1218V
12430 3 1 KT1217V
12430 3 1 KT1218V
12431 3 1 KT1217V
12431 3 1 KT1218V
12434 3 1 KT1217V
12434 3 1 KT1218V
12439 8 1 KT1217V
12439 8 1 KT1218V
12440 1 1 KT1217V
12440 1 1 KT1218V
12442 8 1 KT1217V
12442 8 1 KT1218V
12443 8 1 KT1217V
12443 8 1 KT1218V
I am looking for a result like this:
KT1217V 12426,12428 .....
KT1218 12426,12428,12431
KT1218 12434,12439
till value of column b sums < 5 if sum exceeds > 5
show new record of same with the values left
where c=1
I wrote the query to obtain value < or > sum(column B) but unable to show new record of the same with leftover values column A for column D
select D,
(select a.A+',' from table1 a where a.D = b.D for XML PATH ('') )
from table1 b
WHERE c = 1
group by D
HAVING SUM(B)<5
ORDER BY D
You need to use LISTAGG(), smth like SELECT A, LISTAGG(D, ',') WITHIN GROUP (ORDER BY D). There is no such things in Oracle as a.A+',' or for XML PATH ('')...

Query to multiply certain sets of rows on a single table

I've got a bit of a complicated query that I'm struggling with. You will notice that the schema isn't the easiest thing to work with but it's what I've been given and there isn't time to re-design (common story!).
I have rows like the ones below. Note: The 3 digit value numbers are just random numbers I made up.
id field_id value
1 5 999
1 6 888
1 7 777
1 8 foo <--- foo so we want the 3 values above
1 9 don't care
2 5 123
2 6 456
2 7 789
2 8 bar <--- bar so we DON'T want the 3 values above
2 9 don't care
3 5 623
3 6 971
3 7 481
3 8 foo <--- foo so we want the 3 values above
3 9 don't care
...
...
n 5 987
n 6 654
n 7 321
n 8 foo <--- foo so we want the 3 values above
n 9 don't care
I want this result:
id result
1 999*888*777
3 623*971*481
...
n 987*654*321
Is this clear? So we have a table with n*5 rows. For each of the sets of 5 rows: 3 of them have values we might want to multiply together, 1 of them tells us if we want to multiply and 1 of them we don't care about so we don't want the row in the query result.
Can we do this in Oracle? Preferably one query.. I guess you need to use a multiplication operator (somehow), and a grouping.
Any help would be great. Thank you.
something like this:
select m.id, exp(sum(ln(m.value)))
from mytab m
where m.field_id in (5, 6, 7)
and m.id in (select m2.id
from mytab m2
where m2.field_id = 8
and m2.value = 'foo')
group by m.id;
eg:
SQL> select * from mytab;
ID FIELD_ID VAL
---------- ---------- ---
1 5 999
1 6 888
1 7 777
1 8 foo
1 9 x
2 5 123
2 6 456
2 7 789
2 8 bar
2 9 x
3 5 623
3 6 971
3 7 481
3 8 foo
3 9 x
15 rows selected.
SQL> select m.id, exp(sum(ln(m.value))) result
2 from mytab m
3 where m.field_id in (5, 6, 7)
4 and m.id in (select m2.id
5 from mytab m2
6 where m2.field_id = 8
7 and m2.value = 'foo')
8 group by m.id;
ID RESULT
---------- ----------
1 689286024
3 290972773
Same logic; just removed the hard-coded values. posting this answer thinking might be helpful to some others.
SELECT a.id,
exp(sum(ln(a.val)))
FROM mytab a,
(SELECT DISTINCT id,
field_id
FROM mytab
WHERE val = 'foo') b
WHERE a.id = b.id
AND a.field_id < b.field_id
GROUP BY a.id;

stored procedure to find value in 2 columns out of 3

I am putting in the samle date and i am supposed to do something similar what i am asking.
I want to run a query that would pull values in any two columns out 3 if it has a 1 or if any one column has a 1 it will return just those results. However it should search all three columns and in any of the three columns where it found value as 1 it should return that result. Can anyone please help me with this. Thanks in advance.
ID Patient Patient Name prio prio2 prio3
-------------------------------------------------
1 101563 Robert Riley 1 1 1
2 101583 Cody Ayers 1 0 1
3 101825 Jason Lawler 0 0 1
4 101984 Dustin Lumis 1 0 0
5 102365 Stacy smith 1 0 0
6 102564 Frank Milon 1 0 0
7 102692 Thomas Kroning 1 0 0
8 102856 Andrew Philips 1 0 0
9 102915 Alice Davies 0 0 1
10 103785 Jon Durley 0 0 1
11 103958 Clayton Folsom 1 1 1
12 104696 Michelle Holsley 1 1 1
13 104983 Teresa Jones 1 0 1
14 105892 Betsy Prat 1 1 0
15 106859 Casey Ayers 1 1 0
So, basically you want to pull anything where any of the 3 columns prio,prio2, or prio3 =1? Please clarify your question if this isn't what you are asking( for a better answer). Also, you should tag it with what type of SQL.
SELECT ID,Patient,[Patient Name],prio,prio2, prio3
FROM uRtable
WHERE prio = 1 OR prio2 = 1 OR prio3 = 1
But, if you are saying that you want to pull back any row where any of the 3 columns prio,prio2, or prio3 = 1, but at least one of them is 0 (Get any where any of the 3 = 1 but exclude where they all = 1), probably the easiest way to understand that would be
SELECT ID,Patient,[Patient Name],prio,prio2, prio3
FROM uRtable
WHERE (prio = 1 OR prio2 = 1 OR prio3 = 1)
AND (prio = 0 OR prio2 = 0 OR prio3 = 0)
Try this:
select * from mytable
where prio + prio2 + prio3 = (
select max(prio + prio2 + prio3)
from mytable
where prio = 1 or prio2 = 1 or prio3 = 1
)
SELECT *
FROM tbl
WHERE 1 IN (prio,prio2,prio3)