How to pass multiple values to UPDATE or SELECT COUNT(*) statement - oracle

I am trying to do a update a record.
Table name is customer
id | name | address | state
---+---------+------------+-------------------------
1 | John | 123 main st | TX
2 | Jack | 678 John st | NJ
3 | Bet | 987 Tx st | NY
4 | Maddy| 9812 Hudson st | CA
5 | ABCD | 9813 Mainly st | PA
My query is like below
UPDATE CUSTOMER c SET c.state = 'CA' WHERE c.id IN (idList);
Where idList is a localVariable that I created and it returns a list of id like 1,3,5
The query is working if do it like
UPDATE CUSTOMER c SET c.state = 'CA' WHERE c.id IN (1,3,5);
It is updating the respective records to CA.
But if I use it as
UPDATE CUSTOMER c SET c.state = 'CA' WHERE c.id IN (idList);
I get the below error. I don't want to pass the list directly as the list might change. I am getting the list of ids using a different command where it returns and assigns to idList as 1,3,5
Error:
ORA-01722: invalid number
ORA-06512: at line 35
01722. 00000 - "invalid number"**
How to solve this? I am writing it as a stored procedure.

I guess idList is a comma separated string with all the ids that you want to update.So what is happening is that the operator IN compares each id with that string and since this comparison can't succeed in any case you get an error.
What you can do instead is use the LIKE operator:
UPDATE customer
SET "state" = 'CA'
WHERE ',' || idList || ',' LIKE '%,' || "id" || ',%'
See the demo.

You may create parameterized query string and pass values like,
UPDATE CUSTOMER c SET c.state = 'CA' WHERE c.id IN (:idList);

You can't substitute a text variable for a list of values - it's simply not allowed. You're going to have to use dynamic SQL:
EXECUTE IMMEDIATE 'UPDATE CUSTOMER c SET c.state = ''CA'' WHERE c.id IN (' || idList || ')';

Related

Update "varchar2" column only if new record found

I'm trying to develop simple code for my project.
Where I am supposed to update table books.PUBLISHER. Here in PUBLISHER column we already have below values 'abc; pqr' and I want to update it with 'pqr; xyz' so my expected output will be 'abc; pqr; xyz'.
update books SET PUBLISHER = PUBLISHER || '; ' ||'pqr; xyz'
where id = 1 and PUBLISHER NOT LIKE '%pqr; xyz%';
My expected output will be 'abc; pqr; xyz'.
Your current value of publisher contains the string pqr. Your requirement shows you don't want to duplicate that value. By appending your proposed solution will duplicate the pqr value.
You can avoid the duplication with a replace():
update books
SET PUBLISHER = replace(PUBLISHER, 'pqr', 'pqr; xyz')
where id = 1
and PUBLISHER NOT LIKE '%pqr; xyz%';
This will substitute pqr; xyz wherever pqr appears in the publisher column.
The following update statement should do the job:
update books b
set publisher =
(select listagg(publisher_part, '; ') within group(order by publisher_part)
from (select regexp_substr(bb.publisher, '[a-z]+', 1, level) as publisher_part
from (select publisher from books where id = b.id) bb
connect by regexp_substr(bb.publisher, '[a-z]+', 1, level) is not null
union
select 'lmn' as publisher_part --> your new "publisher" pattern
from dual))
where id = 1; --> id to update
The inner select (select regexp...) scatters your publisher column in separate results
abc
pqr
xyz
...
After that, the new value lmnis added by union select from dual and finally the result is aggregated in the previous format by listagg.
Better solution, as APC already recommended, is a normalization of your table.

Making an Oracle query between three tables using INNER JOIN

I'm working with a super inconsistent Oracle database and I need help to make a query.
Simplyfying the database to an example I have these three tables.
TABLE_F
------
id = 3
title = "Hello"
TABLE_M
------
id = 3
category = "val3"
flid = 5
TABLE_X
------
id = 3
body = "How are you?"
flid = 30
id = 3
body= "Bye bye"
flid = 35
I want to make a query to get the following result:
id | title | mat | BODY | OTHER
------------------------------------------
3 helllo val3 How are you? Bye bye
My query is:
SELECT
TABLE_F.title,
TABLE_M.category,
TABLE_X.body as BODY
FROM TABLE_F
INNER JOIN TABLE_M
ON TABLE_F.id=TABLE_M.id
INNER JOIN TABLE_X
ON TABLE_F.id=TABLE_X.id
WHERE TABLE_M.flid=5 AND TABLE_X.flid=30;
Where I get:
id | title | mat | BODY
--------------------------------
3 helllo val3 How are you?
I need to add to the query the TABLE_X.body as OTHER (which contains the "Bye bye" string), BUT I can't do it as I'm filtering witd flid=30 in order to get the body.
It's not my database and I can't change the design. I need to get that desired output with one query (which I dont know if it's possible).
Thanks in advance.
Join table_x two times using alias
SELECT_F.id,
TABLE_F.title,
TABLE_M.category mat,
TABLE_X.body BODY,
Y.body OTHER BODY,
FROM TABLE_F
INNER JOIN TABLE_M ON TABLE_F.id=TABLE_M.id
INNER JOIN TABLE_X ON TABLE_F.id=TABLE_X.id AND TABLE_X.flid=30
INNER JOIN TABLE_X Y ON TABLE_F.id=Y.id AND Y.flid=35

How to update table1 field by using other table and function

I have two table and one function,
Table1 contains shop_code,batch_id,registry_id
shop_code| batch_id|registry_id
123 | 100 |12
124 | 100 |13
125 | 100 |12
Table2 contains shop_code,shop_name
shop_code| shop_name
123 | need to populate
124 | need to populate
125 | need to populate
Function1 take parameter registry_id from table1 and returns shop_name
Table2 shop_name is empty I want to populate against the shop_code.
I have tried my best but all effort is gone in vain.
It will be great if someone can help I am using Oracle.
I tried below code but giving error on from keyword
update TABLE2 set T2.SHOP_NAME = T.SHOP_NAME
from(
select GET_shop_name(t1.registry_id) as shop_name ,
t1.shop_code shop_code
from TABLE1 T1
) t where t.shop_code = t1.shop_code;
I am not entirely 100% sure if I got your question right, but I believe you want something like
update
table2 u
set
shop_name = (
select
get_shop_name(t1.batch_id)
from
table1 t1
where
t1.chop_code = u.shop_code
);
can you try this approach try to put inner query to get shop name value; I have not tested it but I think approach will work for you.
update TABLE2 T2
set T2.SHOP_NAME =
(select GET_shop_name(t1.batch_id, t1.shop_code) from table1 t1 wehre t1.shop_code = t2.shop_code)
where T2.shop_name is null
You want the MERGE statement.
Something like this might work:
MERGE INTO TABLE2 t2
USING (
SELECT GET_shop_name(t1.batch_id) AS shop_name ,
t1.shop_code shop_code
FROM TABLE1 T1 ) t1
ON (t2.shop_code = t1.shop_code)
WHEN MATCHED THEN
UPDATE SET t2.shop_name = t1.shop_name
;
You'll have to excuse if the exact code above doesn't work I don't have SQL Dev where I am right now for syntax details. :)

Get records from a collection based on a list of integer ids

I have a list of integers: ids. There is also collection, IdNames which comes from an sql table. For each integer in ids I want to find the matching id in, IdNames. Then for each record in IdNames that has a matching id I'd like to select the value in the Name and DisplayName columns and the id.
So here is the table IdNames
Id | Name | DisplayName
--------------------------------
1 | fistName | firstDisplayName
2 | secondName | secondDisplayName
3 | thirdName | thirdDisplayName
If ids contained the integers 2 and 3, I'd want this collection to be returned
Id | Name | DisplayName
--------------------------------
2 | secondName | secondDisplayName
3 | thirdName | thirdDisplayName
How would I write this as a linq query?
I stared writing it like this: IdNames.Select(x => x.Id == ids.Any()), but obviously it's not right.
var idNames = from idName in DataContext.IdNames
where ids.Contains(idName.Id)
select idName;
Good enough?
Use Join in Linq-To-Objects("I have a list of integers: ids. There is also collection, IdNames"):
var query = from id in ids
join idName in IdNames
on id equals idName.Id
select idName;
Why is LINQ JOIN so much faster than linking with WHERE?

How to make null equal null in oracle

I have a variable being passed to my stored proc and it's a filter (basically). However, that field can sometimes be null, and if it is, I want to be able to check against the rows that have that field as null.
For example,
Table A:
VALUE_COLUMN | FILTER_COLUMN
----------------------------
A | (NULL)
B | (NULL)
C | (NULL)
D | (NULL)
A | 1
E | (NULL)
F | (NULL)
B | 1
The query (With inputs, val, filter):
SELECT COUNT(1)
FROM TableA
WHERE
wrap_up_cd = val
AND brn_brand_id = filter
Expected I/O:
val = A, filter = (null) = 1
val = A, filter = 1 = 1
val = C, filter = 1 = 0
How can I make Oracle behave this way?
How about:
SELECT COUNT(1)
FROM TableA
WHERE
wrap_up_cd = val
AND ((brn_brand_id = filter) OR (brn_brand_id IS NULL AND filter IS NULL))
I'm not an Oracle expert, but I'd expect that to work - basically make the query match if both the filter and the value are NULL.
Oracle doesn't have an ISNULL function. So you'd need something like
SELECT COUNT(*)
FROM tableA
WHERE brn_brand_id = filter
OR ( brn_brand_id IS NULL
AND filter IS NULL)
This can also be handy at times:
SELECT COUNT(*)
FROM tableA
WHERE
NVL(brn_brand_id, CHR(0)) = NVL(filter, CHR(0))

Resources