Inline query to update multiple rows - sql

Here is a brief description of the tables I'm working with in Oracle 10g:
Notes:
Table : jnldetail : Single row with data as shown.
There are multiple package id's attached to the same bill_ref_no for an account. Therefore, I'm trying to update "jnldetail " with the multiple package_id's.
Relation between index_bill_ref and bill_ref_no : 1 - 1
Relation between account_no and ( index_bill_ref and bill_ref_no ) : 1 - Many
**Table : jnldetail** :
account_no bill_ref_no amount
8594822 74282843 822
I'm adding another column package_id with the following command:
alter table jnldetail add package_id number(10)
**table: bill_invoice**:
account_no bill_ref_no index_bill_ref
8594822 74282843 763653495
**table: bill_invoice_detail**:
index_bill_ref package_id component_id
763653495 20000077 20000177
763653495 20000250 20000528
763653495 13000019 13000137
**Expected Result:**
**Table : jnldetail** :
account_no bill_ref_no amount package_id
8594822 74282843 822 20000077
8594822 74282843 822 20000250
8594822 74282843 822 13000019
My Query is:
UPDATE jnldetail tp
SET tp.package_id = (
select
t1.package_id
from bill_invoice_detail t1
, bill_invoice t2
where
t1.index_bill_ref = t2.index_bill_ref
and
t2.account_no = tp.account_no
)
The error message is : ora 01427 : single row subquery returns more than one row
Any inputs will be helpful.
Thanks!

The problem is that you're trying to set tp.package_id to more than one number, because your subquery is returning more than one result, e.g. 20000077 and 13000019. You'll need to alter the subquery so that only one value is returned.

Why not keep the tables separate and use a join when you are ready to get the complete data?

This is tricky for two reasons:
1) you want to update the existing row, and want to add two new rows
2) the two new rows need the data from both the original jnldetail table (amount) and the bill_invoice tables (package_id)
To address 1, you can use the MERGE statement, but because of 2, the jnldetail is needed in the using clause of the MERGE statement.
Here is your example:
SQL> create table jnldetail (account_no, bill_ref_no, amount)
2 as
3 select 8594822, 74282843, 822 from dual
4 /
Tabel is aangemaakt.
SQL> alter table jnldetail add package_id number(10)
2 /
Tabel is gewijzigd.
SQL> create table bill_invoice (account_no, bill_ref_no, index_bill_ref)
2 as
3 select 8594822, 74282843, 763653495 from dual
4 /
Tabel is aangemaakt.
SQL> create table bill_invoice_detail (index_bill_ref, package_id, component_id)
2 as
3 select 763653495, 20000077, 20000177 from dual union all
4 select 763653495, 20000250, 20000528 from dual union all
5 select 763653495, 13000019, 13000137 from dual
6 /
Tabel is aangemaakt.
The tables as you described them.
SQL> UPDATE jnldetail tp
2 SET tp.package_id =
3 ( select t1.package_id
4 from bill_invoice_detail t1
5 , bill_invoice t2
6 where t1.index_bill_ref = t2.index_bill_ref
7 and t2.account_no = tp.account_no
8 )
9 /
( select t1.package_id
*
FOUT in regel 3:
.ORA-01427: single-row subquery returns more than one row
Your update statement fails, because you try to assign the result of a 3-rows-returning-query to a single column.
Here is the MERGE statement:
SQL> merge into jnldetail jd
2 using ( select bi.account_no
3 , bi.bill_ref_no
4 , jd.amount
5 , bid.package_id
6 , row_number() over (partition by bi.account_no,bi.bill_ref_no,bi.index_bill_ref order by null) rn
7 from bill_invoice bi
8 , bill_invoice_detail bid
9 , jnldetail jd
10 where bi.index_bill_ref = bid.index_bill_ref
11 and bi.account_no = jd.account_no
12 and bi.bill_ref_no = jd.bill_ref_no
13 ) bi
14 on ( jd.account_no = bi.account_no
15 and jd.bill_ref_no = bi.bill_ref_no
16 and bi.rn = 1
17 )
18 when matched then
19 update set package_id = package_id
20 when not matched then
21 insert values (bi.account_no,bi.bill_ref_no,bi.amount,bi.package_id)
22 /
3 rijen zijn samengevoegd.
Note that we pick an arbitrary row to be updated: the one with rn = 1.
It leads to the desired result set:
SQL> select * from jnldetail
2 /
ACCOUNT_NO BILL_REF_NO AMOUNT PACKAGE_ID
---------- ----------- ---------- ----------
8594822 74282843 822 13000019
8594822 74282843 822 20000077
8594822 74282843 822 20000250
3 rijen zijn geselecteerd.
Regards,
Rob.

Related

Insert into table gives different results

I inserted all the rows of a view to a delta table, but after running a query for a particular value I get below results.
Can someone explain to me how this is possible?
A is View and B is Delta(databricks) table.
1.
Select count(*) from A
result: 102.321
2.
Select * from A where id = '11'
id
date
unit
11
2022-09-02
4
3.
Insert Into B Select * From A
OR
CREATE OR REPLACE TABLE B AS ( SELECT * FROM A)
Select count(*) from B '
result: 101.372
5.
Select * from B where id = '11'
id
date
unit
11
2022-09-02
2

How to add new column in a table from existing column in the same table?

I have a table with only 1 column which has several details concatenated into it like Product Name, Shipment Date etc:
MASTERCOLUMN
Row1_Prod1_ShipDate_01-Dec-21
Row2_Prod2_ShipDate_03-Dec-21
Row3_Prod3_ShipDate_07-Dec-21
.
.
The requirement is to add another 2 columns containing only ProductName and ShipmentDate details corresponding to MASTERCOLUMN: (Eg below)
MASTERCOLUMN ProductName ShipmentDate
Row1_Prod1_ShipDate_01-Dec-21 Prod1 01-Dec-21
Row2_Prod2_ShipDate_03-Dec-21 Prod2 03-Dec-21
Row3_Prod3_ShipDate_07-Dec-21 Prod3 07-Dec-21
.
.
.
I've altered the table and added these new columns. Is there any way of updating the table so that corresponding values gets copied to these new columns? Can this be achieved using SQL query? I am using SQL Developer with Oracle 19.c version.
I've tried updating the column after adding the 2 columns..
The below sample query is for updating the ProductName column:
UPDATE TABLE
SET ProductName = (SELECT SUBSTR(MASTERCOLUMN,6,5) FROM TABLE);
But this returns ORA-01427: single-row subquery returns more than one row error.
However, I tried to update only one row and it worked fine;
UPDATE TABLE
SET ProductName = (SELECT SUBSTR(MASTERCOLUMN,6,5) FROM TABLE)
WHERE MASTERCOLUMN = 'Row1_Prod1_ShipDate_01-Dec-21';
But I need to populate the entire table with corresponding values from MASTERCOLUMN column..
Don't use subquery, you don't need it.
Sample table and rows:
SQL> create table test (mastercolumn varchar2(30));
Table created.
SQL> insert into test
2 select 'Row1_Prod1_ShipDate_01-Dec-21' from dual union all
3 select 'Row2_Prod2_ShipDate_03-Dec-21' from dual union all
4 select 'Row3_Prod3_ShipDate_07-Dec-21' from dual;
3 rows created.
Add new columns:
SQL> alter table test add
2 (product_name varchar2(10),
3 shipmentdate date);
Table altered.
Update:
SQL> update test set
2 product_name = substr(mastercolumn,
3 instr(mastercolumn, '_', 1, 1) + 1,
4 instr(mastercolumn, '_', 1, 2) - instr(mastercolumn, '_', 1,1 ) - 1
5 ),
6 shipmentdate = to_date(substr(mastercolumn, -9), 'dd-mon-yy', 'nls_date_language=english');
3 rows updated.
Result:
SQL> select * From test;
MASTERCOLUMN PRODUCT_NA SHIPMENTDA
------------------------------ ---------- ----------
Row1_Prod1_ShipDate_01-Dec-21 Prod1 01.12.2021
Row2_Prod2_ShipDate_03-Dec-21 Prod2 03.12.2021
Row3_Prod3_ShipDate_07-Dec-21 Prod3 07.12.2021
SQL>
But, as you've already been told, you'd rather choose another approach, one of them being a view:
SQL> create or replace view v_test as
2 select mastercolumn,
3 substr(mastercolumn,
4 instr(mastercolumn, '_', 1, 1) + 1,
5 instr(mastercolumn, '_', 1, 2) - instr(mastercolumn, '_', 1,1 ) - 1
6 ) as product_name,
7 to_date(substr(mastercolumn, -9), 'dd-mon-yy', 'nls_date_language=english')
8 as shipmentdate
9 from test;
View created.
SQL> select * From v_test;
MASTERCOLUMN PRODUCT_NAME SHIPMENTDA
------------------------------ -------------------- ----------
Row1_Prod1_ShipDate_01-Dec-21 Prod1 01.12.2021
Row2_Prod2_ShipDate_03-Dec-21 Prod2 03.12.2021
Row3_Prod3_ShipDate_07-Dec-21 Prod3 07.12.2021
SQL>

Pivot in SQL: count not working as expected

I have in my Oracle Responsys Database a table that contains records with amongst other two variables:
status
location_id
I want to count the number of records grouped by status and location_id, and display it as a pivot table.
This seems to be the exact example that appears here
But when I use the following request :
select * from
(select status,location_id from $a$ )
pivot (count(status)
for location_id in (0,1,2,3,4)
) order by status
The values that appear in the pivot table are just the column names :
output :
status 0 1 2 3 4
-1 0 1 2 3 4
1 0 1 2 3 4
2 0 1 2 3 4
3 0 1 2 3 4
4 0 1 2 3 4
5 0 1 2 3 4
I also gave a try to the following :
select * from
(select status,location_id , count(*) as nbreports
from $a$ group by status,location_id )
pivot (sum(nbreports)
for location in (0,1,2,3,4)
) order by status
but it gives me the same result.
select status,location_id , count(*) as nbreports
from $a$
group by status,location_id
will of course give me the values I want, but displaying them as a column and not as a pivot table
How can I get the pivot table to have in each cell the number of records with the status and location in row and column?
Example data:
CUSTOMER,STATUS,LOCATION_ID
1,-1,1
2,1,1
3,2,1
4,3,0
5,4,2
6,5,3
7,3,4
The table data types :
CUSTOMER Text Field (to 25 chars)
STATUS Text Field (to 25 chars)
LOCATION_ID Number Field
Please check if my understanding for your requirement is correct, you can do vice versa for the location column
create table test(
status varchar2(2),
location number
);
insert into test values('A',1);
insert into test values('A',2);
insert into test values('A',1);
insert into test values('B',1);
insert into test values('B',2);
select * from test;
select status,location,count(*)
from test
group by status,location;
select * from (
select status,location
from test
) pivot(count(*) for (status) in ('A' as STATUS_A,'B' as STATUS_B))

How can I select a particular row from a nested table? [duplicate]

This question already has an answer here:
Oracle SQL: select from table with nested table
(1 answer)
Closed 10 years ago.
I have a table that looks like this:
CREATE
OR
REPLACE
TYPE subaccount_nt
IS TABLE OF VARCHAR2(30);
CREATE
TABLE my_table
( contract_id NUMBER(38,0)
, subaccount SUBACCOUNT_NT );
Here's some sample data:
100 [1000, 1, 2]
200 [2000, NULL, 999]
300 [3000]
How can I write a query to return the the third row from the nested table if the 3rd row exists? Here's the output I'm trying to get:
100 1
200 NULL
300 NULL
Haeving never worked with nested tables before, I'm finding it quite hard to forumate my query. Thanks.
You can use analytics with a lateral join (unnesting of collection):
SQL> SELECT contract_id, CASE WHEN rn = 2 THEN val END val
2 FROM (SELECT t.contract_id, column_value val,
3 row_number() over(PARTITION BY t.contract_id ORDER BY 1) rn,
4 COUNT(*) over (PARTITION BY t.contract_id) cnt
5 FROM my_table t,
6 TABLE(t.subaccount))
7 WHERE rn = 2 OR cnt = 1;
CONTRACT_ID VAL
-------------- ---
100 1
200
300
This will not list rows that have an empty subaccount.
By the way the order is not guaranteed since the nested tables are stored as unordered sets of rows.

How to do I update existing records using a conditional clause?

I'm new to Oracle SQL so I have a question .. I have two tables, Table A and Table B .. Now Table A and Table B have the same column names, but in table A, only one column (named 'tracker') actually has data in it .. The rest of the columns in Table A are empty ... What I need to do is update each record in Table A, so that values for other columns are copied over from Table B, with the condition that the the 'tracker' columns value from Table A is matched with the 'tracker' column in Table B ..
Any ideas ?
MERGE INTO tableA a
USING tableB b
ON (a.tracker=b.tracker)
WHEN MATCHED THEN UPDATE SET
a.column1=b.column1,
a.column2=b.column2;
And if exist rows in B that does not exist in A:
MERGE INTO tableA a
USING tableB b
ON (a.tracker=b.tracker)
WHEN MATCHED THEN UPDATE SET
a.column1=b.column1,
a.column2=b.column2
WHEN NOT MATCHED THEN INSERT VALUES
a.tracker,a.column1,a.column2; --all columns
create table a (somedata varchar2(50), tracker number , constraint pk_a primary key (tracker));
create table b (somedata varchar2(50), tracker number, constraint pk_b primary key (tracker));
/
--insert some data
insert into a (somedata, tracker)
select 'data-a-' || level, level
from dual
connect by level < 10;
insert into b (somedata, tracker)
select 'data-b-' || -level, level
from dual
connect by level < 10;
select * from a;
SOMEDATA TRACKER
-------------------------------------------------- -------
data-a-1 1
data-a-2 2
data-a-3 3
data-a-4 4
data-a-5 5
data-a-6 6
data-a-7 7
data-a-8 8
data-a-9 9
select * from b;
SOMEDATA TRACKER
-------------------------------------------------- -------
data-b--1 1
data-b--2 2
data-b--3 3
data-b--4 4
data-b--5 5
data-b--6 6
data-b--7 7
data-b--8 8
data-b--9 9
commit;
update (select a.somedata a_somedata, b.somedata b_somedata
from a
inner join
b
on a.tracker = b.tracker)
set
a_somedata = b_somedata;
select * from a; --see below for results--
--or you can do it this way: (issuing rollback to get data back in previous state)
--for a one column update, either way will work, I would prefer the former in case there is a multi-column update necessary
-- merge *as posted by another person* will also work
update a
set somedata = (select somedata
from b
where a.tracker = b.tracker
);
select * from A; --see below for results--
-- clean up
-- drop table a;
-- drop table b;
this will give you the results:
SOMEDATA TRACKER
-------------------------------------------------- -------
data-b--1 1
data-b--2 2
data-b--3 3
data-b--4 4
data-b--5 5
data-b--6 6
data-b--7 7
data-b--8 8
data-b--9 9
here is a link to oracle's documentation on UPDATE