ORA-06512 and ORA-01403 no data found - plsql

I keep getting the below error upon executing the tax_calc_sf function on SQL developer.
enter image description here
Also I am not sure why it always disconnects from database immediately after the process is exits.Any help with this would be appreciated.
CREATE OR REPLACE FUNCTION tax_calc2_sf
(p_id NUMBER,
p_sub NUMBER)
RETURN NUMBER
IS
lv_tax_num NUMBER(5,2) :=0;
BEGIN
SELECT p_sub*t.taxrate tax
INTO lv_tax_num
FROM bb_basket b, bb_tax t
WHERE b.shipstate = t.state
AND b.idBasket = p_id;
RETURN lv_tax_num;
END;
I have tried adding a exception block as below but that does not change anything but the same error as shown in the image above still repeats.
enter image description here

In the context of your [PL/SQL] function – tax_calc2_sf – the SELECT INTO statement should return precisely one row. If it does not return precisely one row, you will get one of the following predefined exceptions
NO_DATA_FOUND if the SELECT returns zero rows
TOO_MANY_ROWS if the SELECT returns more than one row
Adding an exception handler does not prevent the exception from occurring, it just allows you to perform custom handling.
So ask yourself, what should function tax_calc2_sf do if the SELECT returns no rows. Should the function return null? Should it return zero? Should it throw an exception?
Similarly, you need to decide what to do when the SELECT returns more than one row.
Alternatively, you could first perform a SELECT count(*) which will always return precisely one row and so will not throw any exceptions. Then you can decide how to proceed depending on whether the count is zero, one or more than one.
By the way, it is recommended to use ANSI join syntax when you query more than one database table.
SELECT p_sub*t.taxrate tax
INTO lv_tax_num
FROM bb_basket b
JOIN bb_tax t
ON b.shipstate = t.state
WHERE b.idBasket = p_id;

Related

Dynamically checking if value is in sql query

I have a dynamically generated plsql region, in it, I have a bunch of dynamically generated items, some are popup_from_query and those have a query stored in an underlying table. But they also enable you to just type the return value in. So now I need to somehow check if the value you entered is in the LOV.
So I added some code to my validation(some also have extra conditions so I check those). I made a function that returns the relevant LOV, but reworked to something like this:
SELECT id --this is always the name of the column containing return value
FROM ( select something id, --this is the return value
something_else name --display value
from table
WHERE conditions)
WHERE id= :param;
This selects the return column from the lov, where the value is equal to the value we have entered, so this returns the entered value if it is in the LOV, and nothing if its not a valid value.
IF checking_lov THEN
a_lov := function_that_returns_an_sql_query;
DECLARE
x VARCHAR2(100);
BEGIN
EXECUTE IMMEDIATE
a_lov
INTO x
USING apex_application.g_f02(i); --value of parameter
EXCEPTION
WHEN no_data_found THEN
x := NULL;
END;
IF x IS NULL THEN
display_error; --I do stuff here to display error, not important to you
END IF;
END IF;
But I can't seem to get this to work. APEX doesn't find anything wrong with the code, it compiles without errors. But when I try it out, it throws an 'Invalid character' error, and the validation passes. I have tried perhaps making the entire a_lov query, adding an 'INTO x' and changing ':param' into 'apex_application.g_f02(i). But it just doesn't work.
Any ideas would be appreciated
Just wanted to post an update, actually got a solution going. And it was the stupidest thing ever.
The bit that is executed dynamically, I ended it with a semicolon, shouldnt have done that. That was all there was to it.
That one semicolon was what was messing me up, now it works. So if anyone stumbles upon this question, check your semicolons.

Using DBMS error log, how can I bulk insert values from one table into another skipping (but logging) errors?

I am trying to bulk insert rows from one table to another. I want to skip any errors that occur while doing this but log them as well. I used the following PL/SQL command to create an error log table for the table I am trying to insert all the values into:
BEGIN
DBMS_ERRLOG.create_error_log (
dml_table_name => 'ROBOT_ID_TOOL_DUMP_IDPK.TEST'
, skip_unsupported => TRUE);
END;
I then do a simple insert with logging turned on:
INSERT INTO table2
SELECT * FROM table1
LOG ERRORS INTO ERR$_table2;
The logging works but my insert is stopping, and rolling back after the first exception is hit (PK or unique constraint for example). I don't want to rollback when an exception is encountered though, I want that row to be skipped, and to continue trying to insert all remaining rows (but logging the problem row). I thought that is what the skip_unsupported parameter was doing. I have tried setting this value to FALSE and am still encountering the same issue.
I missed a step on my insert.
INSERT INTO table2
SELECT * FROM table1
LOG ERRORS INTO ERR$_table2 REJECT LIMIT UNLIMITED;
The REJECT LIMIT UNLIMITED flag Continues through every error.

how to use a cursor within a function in PL/SQL

I have an assignment, and the course materials do not cover how to do this, and a web search has not been help regarding cursors within functions.
The assignment is to return all last names in the database, but change any according to the case statement parameters. And I am required to use a cursor. Here is my code:
create or replace function Convert_New_Name
return sys_refcursor
as
c_results sys_refcursor;
begin
open c_results for
select
case last_name
when 'King' then 'LION'
when 'Ford' then 'CAR'
when 'Miller' then 'BEER'
else last_name
end as new_name
from employees;
return c_results;
end convert_new_name;
I'm having a hard time finding anything pertinent in searches. The database has 20 rows. This code returns all 20 rows, with required changes, but it returns those 20 row 20 times, instead of once.
There was another post on here with almost the same assignment, but when I tried to post on there, it got deleted, and I got told to ask my own question.
The function code you posted is fine. The calling code should call function Convert_New_Name only once. If you plan to call it from a SQL statement, then this query should do the job:
Select Convert_New_Name() From dual;

X++ Odd count result

I'm experiencing a really odd result when I do a count in X++, something I've not experienced before. I am performing what I thought was a really simply count query, but I can't seem to get the result I am after.
WMSOrderTrans orderTrans;
WMSOrderTrans orderTransChk;
;
select count(RecId) from orderTrans group by shipmentid where orderTrans.inventTransRefId == 'XXXXXX';
info(strFmt('Count is %1', orderTrans.RecId));
while select orderTransChk group by shipmentid where orderTransChk.inventTransRefId == 'XXXXXX' {
info(strFmt('Shipment is %1', orderTransChk.shipmentId));
}
The data set that I am selecting all have only 1 shipmentid, so the first select I am expecting a count of 1, instead I get 4 (which is how many lines for that transrefid exist). If I change the count from 'RecId' to 'ShipmentId', then instead of the count, I get actual shipmentId. I simply want it to return the count of the records, which is what I believe I've asked it to do.
I really can't see what I am missing.
In the while select, I get what I expect (the shipmentid), only 1 infolog message for the loop. This tells me that the group by with the where clause is working, but it doesn't explain why the first count select statement isn't behaving as I would expect.
For reference, this is AX2012 R1 system.
For anyone who might be interested in knowing my answer, it's tied up with Jeff's response. At the end of the day, I didn't look at data well enough, and the query returned the correct results. I initially thought there were a number of unique shipments, but I was wrong. My expected result was erroneous. There were 4 lines in the file, but the lines were unique for the item, not the shipment. They were all on the same shipment. So really, my own fault, it goes to show that one really needs to look at the data closely.
Thanks to all that responded, greatly appreciated.
I would try a database sync, then restarting the AOS. I don't see anything obviously wrong, so it points to bouncing everything.
Try getting the select statement via this method (from memory so check syntax) and then review the query against SQL directly. It uses generateOnly.
select generateOnly count(RecId) from orderTrans group by shipmentid where orderTrans.inventTransRefId == 'XXXXXX';
info(orderTrans.getSQLStatement());
If I understand what you try to achieve, you'd like to get something like this SQL query:
select count(distinct shipmentid) from orderTrans
where inventTransRefId = 'XXXXXX'
The 'distinct' keyword is not available in AX select command. The group by clause will allow you to iterate all distinct values but not to use an aggregate on top of it.
You may use a sql connection to push the exact sql command you want.
In AX, aggregate values are stores in the field used: Count(RecId), the count will go in the recid field otherwise the system may need to add new field on the buffer on the fly. I don't think you can aggregate on the group by clause as it's important to have its value.
You can try (I don't have an AX to test it) to use a query:
Query query = new Query();
QueryRun queryRun;
QueryBuildDataSource qbd;
qbd = query.addDataSource(tablenum(OrderTrans));
qbd.addRange(fieldNum(OrderTrans, InventTransId)).value("xxxx");
qbd.addSortField(fieldNum(OrderTrans, ShipmentId));
qbd.SortOrder(SortOrder::GroupBy);
queryRun = new QueryRun(query);
info(strfmt("Total Records in Query %1",SysQuery::countTotal(queryRun)));

trigger for updating a value

I am a newbie in PLSQL and I would like to create a trigger that checks first if there is a record in a table before making an update.
The code I got so far is:
CREATE OR REPLACE TRIGGER table_bu
BEFORE UPDATE ON employee
FOR EACH ROW
DECLARE
v_employee_id:=employee.employee_ID%TYPE;
BEGIN
SELECT employee_id INTO v_employee_id FROM employee;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR (-20001,'data not found');
END;
How I can create a trigger that checks up if a record exists in the table and if it does not exists does not allow the update.
My table estructure is:
employee_id NUMBER
employee_name VARCHAR(20)
employee_salary NUMBER
...
Thanks
You are on a wrong way. The trigger as it is will throw runtime 'Mutating table' error even after fixing syntax error - you missed semicolon after raise_application_error(also it should take 2 arguments, not one). Correct syntax :
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR (-20001, 'data not found'); -- 1st parameter -error code
Update
As far as I understand the updated version of the question, you want to show error if record doesn't exist. The problem with row level trigger approach is that it won't be executed if nothing is found due to condition in WHERE. The simplest way is to check number of rows affected on client side and raise an error there. Or you can write a procedure that checks sql%rowcount after executing desired update, and then throw an exception if it's 0.
If you prefer to do in a hard way, you can create package variable which of type employee.employee_ID%TYPE, before update statement level trigger that resets variable (say set it to null), after update row level trigger that sets this variable to NEW.employee_ID, and after update statement level trigger that throws an exception if the variable is null. Note: this will properly work for individual updates only.
"How I can create a trigger that checks up if a record exists in the table and if it does not exists does not allow the update."
There is really only one practical way to do this - use a referential constraint (foreign key).

Resources