Oracle: Update from within procedure not working - oracle

In my Oracle PL/SQL procedure I am trying to update a row like this:
UPDATE personal p
SET p.surname = surname, p.name = name, p."alter" = alter, p.sex = sex, p.jobcode = jobcode, p.year_wage = month_wage * 12
WHERE p.personalnr = personalnr;
COMMIT;
I have added these two statements right after the commit to confirm the code is reached and executed with the right arguments (e.g. here I want to change the name):
DBMS_OUTPUT.put_line('updated ' || name);
DBMS_OUTPUT.put_line('personalnr ' || personalnr);
Now this update-statement is part of a procedure that is called from within another procedure.
However, the changes are not applied and the name will remain the same even tho the update was executed. I have tried to use an exception-handler as well and there doesn't seem to be any exception happening. I can confirm that the WHERE-clause is as intendet. There is one record that matches the predicate.
Now the strange thing:
When I change the code to the example below, an update happens. However it updates every record and not only the one with the right personalnr. Again: the routine is called only once with one personalnr that matches only one entry in the table.
UPDATE personal p
SET p.name = 'test'
WHERE p.personalnr = personalnr;
COMMIT;

It is working, but it's updating all rows in the table (or at least, those where personalnr is not null), not just the one you expect.
From the documentation:
If a SQL statement references a name that belongs to both a column and either a local variable or formal parameter, then the column name takes precedence.
You have a PL/SQL variable that has the same name as a column. When you do
where p.personalnr = personalnr
you are really doing:
where p.personalnr = p.personalnr
and the same thing happens in the set part; SET p.surname = surname updates the column value to whatever value it had before, not the PL/SQL variable's value. So it looks like the update didn't happen- it actually did, but because everything was set to the same as it's original value it doesn't look like anything happened. (Except - all rows will now have the same year_wage value...)
You can either prefix your variables with the procedure name:
where p.personalnr = my_proc.personalnr
or change the variable names so they don't conflict; it's common to use a short prefix, e.g. l_ for a local variable, or p_ for a passed-in parameter, etc.
where p.personalnr = l_personalnr
Remember to do that for the set part too, or your update still won't appear to do anything.
UPDATE personal p
SET p.surname = l_surname, p.name = l_name, p."alter" = l_alter,
p.sex = l_sex, p.jobcode = l_jobcode, p.year_wage = l_month_wage * 12
WHERE p.personalnr = l_personalnr;

You need to change the parameter name something other than the table's column name.
UPDATE personal p
SET p.name = 'test'
WHERE p.personalnr = personally;
-- here condition is column_name = column_name
-- This will be true for all the records of the table
Change personalnr --> p_personalnr and it will work for you

Related

Passing a range table to an ABAP class/method causes a commit

I want to pass a range table for OBJNR, e.g.
call method ME->ME_GET_STATUS
exporting
I_OBJNR = <FS_DATA>-OBJNR_NTF
I_AEDAT = LV_AEDAT
I_AEZEIT = LV_AEZEIT
IT_OBJNR = LR_OBJNR
importing ...
In the PUBLIC section of the super class I have:
RT_OBJNR type range of JSTO-OBJNR . (this is inherited by the calling class)
which is used by both calling & called methods.
The method ME_GET_STATUS has a parameter:
IT_OBJNR Importing Type RT_OBJNR Range table for OBJNR
and code
,WA_OBJNR like line of IT_OBJNR
,LR_OBJNR type RT_OBJNR
LR_OBJNR[] = IT_OBJNR[].
The range table is only used to buffer an itab - LT_JCDS.
select S~OBJNR, S~STAT, S~CHGNR, S~UDATE, S~UTIME,
S~INACT, O~OBTYP, O~STSMA
from JCDS as S
join JSTO as O
on O~OBJNR = S~OBJNR
into table #IT_JCDS
where S~OBJNR in #LR_OBJNR
order by S~OBJNR, S~UDATE, S~UTIME, S~STAT, S~CHGNR
loop at IT_JCDS into data(LT_JCDS)
where OBJNR = I_OBJNR
group by ( OBJNR = LT_JCDS-OBJNR STAT = LT_JCDS-STAT
GS = group size GI = group index )
ascending
reference into data(OBJNR_REF)
It all works perfectly if there is just 1 record in the range table.
The issue is that if I pass more than 1 record it still works fine but seems to cause a commit (?) which closes the cursor causing a dump in MCEX_BW_LO_API. This occurs when calling the macro "sel" for the 2nd data package.
The idea is to pass multiple records of 'EQ' and 'BT' selections resulting in fewer records being returned from the database.
I've tried changing to a standard table and using = LR_OBJNR[]

Return auto increment value in Oracle SQL Insert statement?

I have Insert statement that should return Auto Increment column value. Here is example of my insert:
myQuery = new query();
myQuery.name = "insertRec";
myQuery.setDatasource("db");
mySQL = "
INSERT INTO myTable (
First, Last, Email, ActionDate
)VALUES(
:first, :last, :email, :actiondt
)
";
myQuery.setSQL(mySQL);
myQuery.addParam(name="first", cfsqltype="cf_sql_varchar", value="#trim(form.first)#", maxlength="50");
myQuery.addParam(name="last", cfsqltype="cf_sql_varchar", value="#trim(form.last)#", maxlength="50");
myQuery.addParam(name="email", cfsqltype="cf_sql_varchar", value="#trim(form.email)#", maxlength="320");
myQuery.addParam(name="actiondt", cfsqltype="cf_sql_timestamp", value="#now()#");
myQuery.execute().getResult();
//result = myQuery.execute().getResult(); This line is commented because I was getting error message that test variable is not defined. Not sure why since test is declared and equals to myQuery.execute().getResult();
After I run this code record will appear in the table. Result set looks like this:
RecordID First Last Email ActionDt
7 John Woss jwoss#gmail.com 16-NOV-18
As you can see RecordID (auto increments) is there. I would like to get that value once myQuery is completed. How to achieve that?
As outlined in https://stackoverflow.com/a/34894454/432681, you can retrieve the auto-incremented ID via a SELECT on the related sequence.
So, your query should look something like this:
mySQL = "
INSERT INTO myTable (
First, Last, Email, ActionDate
)VALUES(
:first, :last, :email, :actiondt
);
SELECT "sequenceForMyTable".currval from dual;
";
How to get the name of the sequence is also described in the linked answer above.
There's a second way outlined in https://stackoverflow.com/a/25268870/432681 and also mentioned in the CFML documentation, which says that you may use the getPrefix() function to be able to access the generated key. Note that in this case result is the object returned by the execute() method, not the getResult() (because the query doesn't return a result set). So for your example this is how you can get the ID:
result = myQuery.execute();
newID = result.getPrefix().generatedKey;

Efficiency of my function with Lua tables

I have a question about the way I put together this piece of Lua code.
Say, there is a function like the one below, containing 200 myTable tables, where the names are ordered alphabetically:
function loadTable(x)
local myTable
if x == "aaron" then myTable = {1,2,3,4,5,6,7,8,9,0}
elseif x == "bobby" then myTable = {1,3,3,4,5,8,7,8,9,1}
elseif x == "cory" then myTable = {1,2,3,3,3,6,7,8,9,2}
elseif x == "devin" then myTable = {1,2,3,4,5,2,3,4,9,0}
...
else
print("table not available")
end
return myTable
end
and now I want to find the table corresponding to x == "zac" (which happens to be somewhere at the end). I use this line of code:
local foundTable = loadTable("zac")
Isnt this like not efficient at all? If it has to find the table at the very end of the function it has to go through all the previous lines of code. Is there some way to code this more efficiently in lua and find the correct table faster? ?
This can become a lot faster by using... a table!
Simply make a table whose keys are the name of the person and the values are the table you want to load, like this:
local tables = {
john = {1,2,3,4,5,6,7,8,9,0},
peter = {1,3,3,4,5,8,7,8,9,1},
william = {1,2,3,3,3,6,7,8,9,2},
victoria = {1,2,3,4,5,2,3,4,9,0}
--...
}
Then, instead of calling loadTable("richard") simply use tables["richard"] or tables.richard if the key is a valid identifier

how to reference function parameter in query?

In the declared function definition I want to use value of function parameter item_account_id in the select query's WHERE clause .
CREATE OR REPLACE
FUNCTION UPDATE_CURRENT_BALANCE( item_account_id IN item_account.item_account_id%TYPE)
RETURN boolean
AS
BEGIN
if item_data_table_id = 10 then
select current_balance_curr_id
from BANK_ACCOUNT
where item_account_id = item_account_id;
end if;
RETURN true;
END UPDATE_CURRENT_BALANCE;
You have a scoping issue because the parameter name is the same as the column. The way Oracle's name resolution works, both these item_account_id = item_account_id will identify the table column. Even it we added a table alias and used it in the one side of the equality operation Oracle will still evaluate it as 1 = 1.
The solution is simple: rename the parameter. Using a prefix is popular:
CREATE OR REPLACE FUNCTION UPDATE_CURRENT_BALANCE
( p_item_account_id IN item_account.item_account_id%TYPE)
RETURN boolean
AS
BEGIN
if item_data_table_id = 10 then -- the posted code has no source for this? perhaps it's another parameter?
select current_balance_curr_id
from BANK_ACCOUNT
where item_account_id = p_item_account_id;
end if;
RETURN true;
END UPDATE_CURRENT_BALANCE;
I presume item_data_table_id is another parameter which got lost in transcription. You should prefix that too: consistency is a good thing in naming conventions.

Using Rails Update to Append to a Text Column in Postgresql

Thanks in advance for any help on this one.
I have a model in rails that includes a postgresql text column.
I want to append (i.e. mycolumn = mycolumn || newdata) data to the existing column. The sql I want to generate would look like:
update MyOjbs set mycolumn = mycolumn || newdata where id = 12;
I would rather not select the data, update the attribute and then write the new data back to the database. The text column could grow relatively large and I'd rather not read that data if I don't need to.
I DO NOT want to do this:
#myinstvar = MyObj.select(:mycolumn).find(12)
newdata = #myinstvar.mycolumn.to_s + newdata
#myinstvar.update_attribute(:mycolumn, newdata)
Do I need to do a raw sql transaction to accomplish this?
I think you could solve this problem directly writing your query using the arel gem, that's already provided with rails.
Given that you have these values:
column_id = 12
newdata = "a custom string"
you can update the table this way:
# Initialize the Table and UpdateManager objects
table = MyOjbs.arel_table
update_manager = Arel::UpdateManager.new Arel::Table.engine
update_manager.table(table)
# Compose the concat() function
concat = Arel::Nodes::NamedFunction.new 'concat', [table[:mycolumn], new_data]
concat_sql = Arel::Nodes::SqlLiteral.new concat.to_sql
# Set up the update manager
update_manager.set(
[[table[:mycolumn], concat_sql]]
).where(
table[:id].eq(column_id)
)
# Execute the update
ActiveRecord::Base.connection.execute update_manager.to_sql
This will generate a SQL string like this one:
UPDATE "MyObjs" SET "mycolumn" = concat("MyObjs"."mycolumn", 'a custom string') WHERE "MyObjs"."id" = 12"

Resources