Oracle Apex Ora 01403 no data found - database

I have one small question. How to resolve this problem.
First, I have this code below and he give error Ora 01403 no data found. This code was debugged and I find when he give this error. This place was marked.
Second, my question is How I can modify this code?
Thirdly, how I can take only one row from the cursor? I know that command "fetch" store data for new row in variable with %rowtype
Fourthly, main task is need to store data from cursor in different tables with diffrent FK For this task was wroten this code. If anyone have Idea how to do this I wiil be greate to see solution or explanation how to resolve this "question". Thanks.
DECLARE
CURSOR c_data IS
SELECT td.*
FROM ddf td
WHERE td.col1 IS NOT NULL
AND td.col2 IS NOT NULL
AND td.col3 IS NOT NULL
AND td.col4 IS NOT NULL
AND td.col5 IS NOT NULL
AND td.col6 IS NOT NULL
AND td.col7 IS NOT NULL
OR td.col8 IS NOT NULL
OR td.col9 IS NOT NULL
OR td.col10 IS NOT NULL;
c_id NUMBER;
r_number NUMBER;
ed NUMBER;
nid NUMBER;
ssd NUMBER;
iiy number := :p13ns;
BEGIN
FOR i IN c_data LOOP
c_id := 0;
r_number := 0;
r_number := random_number();
c_id := get_cd(i.col5);
INSERT INTO rrree (
efn, eii, ec, edd, tei, eln, emn, ebd, eid, eiid
) VALUES (
i.col1, i.col8 || i.col9, c_id, to_date(sysdate, 'MM/DD/YYYY'),
CASE
WHEN i.col8 IS NOT NULL THEN (
SELECT tei FROM vre WHERE tei = 1 ) ELSE (
SELECT tei FROM vre WHERE tei = 2 )
END, i.col3, i.col2, to_date(i.col4, 'MM/DD/YYYY'), to_date(i.col6, 'MM/DD/YYYY'), to_date(i.col7, 'MM/DD/YYYY')
);
COMMIT;
/* Second call for this select get error Ora-01403 no data found. */
SELECT DISTINCT( dii ) INTO ed
FROM vrt
WHERE upper(efn) LIKE upper(i.col1)
AND upper(eln) LIKE upper(i.col3)
AND upper(emn) LIKE upper(i.col2)
AND ROWNUM = 1;
/* end Second call for this select get error Ora-01403 no data found. */
SELECT DISTINCT( isd ) INTO nid
FROM vri
WHERE isd = iiy
AND ROWNUM = 1;
INSERT INTO rrre (
cal_id, dii
) VALUES (
1, ed
);
COMMIT;
SELECT DISTINCT( sd ) INTO ssd
FROM rrre
WHERE dii = ed
AND ROWNUM = 1;
INSERT INTO rrrs (
sid, sssi, sns, sts, sids, va, cdc, dii, sd, disv, isd
) VALUES (
to_date(sysdate, 'MM/DD/YYYY'), nid, r_number, to_date(sysdate + 5, 'MM/DD/YYYY'), 1, 1, 1, ed, ssd, to_date(sysdate, 'MM/DD/YYYY'), nid
);
COMMIT;
END LOOP;
END;

Related

Facing an issue in MERGE SQL query

I have a requirement, insert/update data from staging table stgTbl to another table T2. If exists update, no matter how many duplicates are there. Similarly, if not exists insert directly T2. Very Simple. Since the staging table stgTb1 is scheduled job everyday. Sometime I would get multiple duplicate rows as well. So because of duplicates, merge statement producing an error:
"The MERGE statement attempted to UPDATE or DELETE the same row more
than once. This happens when a target row matches more than one source
row".
I tried with checksum but still getting because i may done wrongly in checksum. There is no primary key in both the tables (i removed, because otherwise i am getting primary key constraint error). Based on columns (account and ref_key2) should go with insert/update. I have tried with if else with exists also but somehow this is also not working if in case there are 0 records in the target table T2. SQL masters could solve this issue. Appreciate their knowledge share.
CREATE OR ALTER Trigger [dbo].[tr_Merge_Personal_Expense] on [dbo].
[Personal_Expense_Staging]
AFTER INSERT
AS
BEGIN
DECLARE #SummaryOfChanges TABLE(Change nvarchar(20));
MERGE [dbo].[Personal_Expense] AS TARGET
USING (
SELECT *,
CHECKSUM(
ISNULL(CONVERT(nvarchar (3) ,[Client]),'0'),
ISNULL(CONVERT(nvarchar (50),[Text]),'0'),
ISNULL(CONVERT(nvarchar (10),[Cost_Center]),'0'),
ISNULL(CONVERT(nvarchar (2) ,[Posting_Period]),'0'),
ISNULL(CONVERT(nvarchar (10),[Profit]),'0') ,
ISNULL(CONVERT(nvarchar (2) ,[Document_Type]),'0'),
ISNULL(CONVERT(nvarchar (4) ,[Company_Code]),'0') ,
-- ISNULL(CONVERT(nvarchar (10),[Account]),'0'),
ISNULL(CONVERT(nvarchar (20),[Amount_In_Doc_Curr]),'0'),
ISNULL(CONVERT(nvarchar (5) ,[Document_Currency]),'0') ,
ISNULL(CONVERT(nvarchar (20),[Amount_In_local_Curr]),'0') ,
ISNULL(CONVERT(nvarchar (20),[Amount_In_Grp_Curr]),'0'),
ISNULL(CONVERT(nvarchar (25),[Group]),'0'),
[Posting_Date],
ISNULL(CONVERT(nvarchar (18), [Assignment]),'0'),
ISNULL(CONVERT(nvarchar (16), [Reference]),'0'),
ISNULL(CONVERT(nvarchar (20), [Reference_Key1]),'0') ,
--[Reference_Key2] [nvarchar](12) NOT NULL,
ISNULL(CONVERT(nvarchar (20), [Reference_Key3]),'0') ,
ISNULL(CONVERT(nvarchar (20), [Document_Number]),'0') ,
ISNULL(CONVERT(nvarchar (25), [Document_Header_Text]),'0')
) AS [HashChecksum]
FROM
[dbo].[Personal_Expense_Staging]
) AS SOURCE
ON (
TARGET.[Reference_Key2] = SOURCE.[Reference_Key2] AND
TARGET.[Account] = SOURCE.[Account]
)
----- Update
WHEN MATCHED AND ( TARGET.[HashChecksum] <> SOURCE.[HashChecksum] )
THEN
UPDATE SET
TARGET.[client] = SOURCE.[client],
TARGET.[text] = SOURCE.[text],
TARGET.[cost_center] = SOURCE.[cost_center],
TARGET.[posting_period] = SOURCE.[posting_period],
TARGET.[profit] = SOURCE.[profit],
TARGET.[document_type]= SOURCE.[document_type],
TARGET.[company_code] = SOURCE.[company_code],
TARGET.[Account] = SOURCE.[Account],
TARGET.[Amount_In_Doc_Curr] = SOURCE.[Amount_In_Doc_Curr],
TARGET.[document_currency] = SOURCE.[document_currency],
TARGET.[Amount_In_local_Curr] = SOURCE.[Amount_In_local_Curr],
TARGET.[Amount_In_Grp_Curr] = SOURCE.[Amount_In_Grp_Curr],
TARGET.[group] = SOURCE.[group],
TARGET.[posting_date] = SOURCE.[posting_date],
TARGET.[assignment] = SOURCE.[assignment],
TARGET.[reference] = SOURCE.[reference],
TARGET.[document_header_text] = SOURCE.[document_header_text],
TARGET.[Last_updated_DateTime] = GETDATE(),
TARGET.[HashChecksum] = SOURCE.[HashChecksum]
-- Insert
WHEN NOT MATCHED THEN
INSERT (
[Client],
[text],
[cost_center],
[posting_period],
[profit],
[document_type],
[company_code],
[Account],
[Amount_In_Doc_Curr],
[document_currency],
[Amount_In_local_Curr],
[Amount_In_Grp_Curr],
[group],
[posting_date],
[assignment],
[reference],
[reference_key2],
[reference_key3],
[document_number],
[document_header_text],
[Last_updated_DateTime],
[HashChecksum]
)
VALUES (
SOURCE.[client],
SOURCE.[text],
SOURCE.[cost_center],
SOURCE.[posting_period],
SOURCE.[profit],
SOURCE.[document_type],
SOURCE.[company_code],
SOURCE.[Account],
SOURCE.[Amount_In_Doc_Curr],
SOURCE.[document_currency],
SOURCE.[Amount_In_local_Curr],
SOURCE.[Amount_In_Grp_Curr],
SOURCE.[group],
SOURCE.[posting_date],
SOURCE.[assignment],
SOURCE.[reference],
SOURCE.[reference_key2],
SOURCE.[reference_key3],
SOURCE.[document_number],
SOURCE.[document_header_text],
GETDATE(),
SOURCE.[HashChecksum]
)
OUTPUT $action INTO #SummaryOfChanges;
DECLARE #RowsProcessed INT = 0;
SELECT
#RowsProcessed = ISNULL([INSERT],0) + ISNULL([UPDATE],0) + ISNULL([DELETE],0)
FROM (
SELECT COUNT(*) ChangeCount, Change as ChangeType
FROM #SummaryOfChanges
GROUP BY Change
)Main
PIVOT (
MAX(ChangeCount)
FOR ChangeType IN ([INSERT],[UPDATE],[DELETE])
)Pvt;
SELECT #RowsProcessed AS RowsProcessed;
CREATE OR ALTER TRIGGER [dbo].[tr_merge_personal_expense]
ON personal_expense_staging
AFTER INSERT AS
----- CASE 1: IF (ACCOUNT AND REF_KEY2) ARE MATCHED THEN UPDATE
IF EXISTS
(
SELECT
*
FROM dbo.personal_expense p
INNER JOIN inserted e
ON p.[account] = e.[account] AND p.[reference_key2] = e.
[reference_key2]
)
BEGIN
UPDATE target
SET
target.[document_number] = source.[document_number],
target.[client] = source.[client],
target.[text] = source.[text],
target.[cost_center] = source.[cost_center],
target.[posting_period] = source.[posting_period],
target.[profit] = source.[profit],
target.[document_type] = source.[document_type],
target.[company_code] = source.[company_code],
target.[amount_in_doc_curr] = source.[amount_in_doc_curr],
target.[document_currency] = source.[document_currency],
target.[amount_in_local_curr] = source.[amount_in_local_curr],
target.[amount_in_grp_curr] = source.[amount_in_grp_curr],
target.[group] = source.[group],
target.[posting_date] = source.[posting_date],
target.[assignment] = source.[assignment],
target.[reference] = source.[reference],
target.[reference_key1] = source.[reference_key1],
target.[reference_key3] = source.[reference_key3],
target.[document_header_text] = source.[document_header_text],
target.[last_updated_datetime] = GETDATE()
FROM personal_expense target
INNER JOIN inserted source
ON target.[account] = source.[account]
AND target.[reference_key2] = source.[reference_key2];
END;
------ CASE 2: IF (ACCOUNT AND REF_KEY2) ARE NOT MATCHED THEN INSERT
IF NOT EXISTS
(
SELECT
*
FROM dbo.personal_expense p
INNER JOIN inserted e
ON p.[account] = e.[account] AND p.[reference_key2] = e.
[reference_key2]
)
BEGIN
INSERT INTO dbo.personal_expense
(
[client],
[text],
[cost_center],
[posting_period],
[profit],
[document_type],
[company_code],
[account],
[amount_in_doc_curr],
[document_currency],
[amount_in_local_curr],
[amount_in_grp_curr],
[group],
[posting_date],
[assignment],
[reference],
[reference_key1],
[reference_key2],
[reference_key3],
[document_number],
[document_header_text],
[last_updated_datetime]
)
SELECT
source.[client],
source.[text],
source.[cost_center],
source.[posting_period],
source.[profit],
source.[document_type],
source.[company_code],
source.[account],
source.[amount_in_doc_curr],
source.[document_currency],
source.[amount_in_local_curr],
source.[amount_in_grp_curr],
source.[group],
source.[posting_date],
source.[assignment],
source.[reference],
source.[reference_key1],
source.[reference_key2],
source.[reference_key3],
source.[document_number],
source.[document_header_text],
GETDATE()
FROM inserted source;
END;
SO, you know that of duplicates, merge statement producing an error. Then simply remove the duplicates in your source clause, using DISTINCT:
SELECT DISTINCT *
FROM [dbo].[Personal_Expense_Staging]

Is there a way to add a logical Operator in a WHERE clause using CASE statements? - T-SQL

I searched the web but cannot find a solution for my problem (but perhaps I am using the wrong keywords ;) ).
I've got a Stored Procedure which does some automatic validation (every night) for a bunch of records. However, sometimes a user wants to do the same validation for a single record manually. I thought about calling the Stored Procedure with a parameter, when set the original SELECT statement (which loops through all the records) should get an AND operator with the specified record ID. I want to do it this way so that I don't have to copy the entire select statement and modify it just for the manual part.
The original statement is as follows:
DECLARE GenerateFacturen CURSOR LOCAL FOR
SELECT TOP 100 PERCENT becode, dtreknr, franchisebecode, franchisenemer, fakgroep, vonummer, vovolgnr, count(*) as nrVerOrd,
FaktuurEindeMaand, FaktuurEindeWeek
FROM (
SELECT becode, vonummer, vovolgnr, FaktuurEindeMaand, FaktuurEindeWeek, uitgestfaktuurdat, levdat, voomschrijving, vonetto,
faktureerperorder, dtreknr, franchisebecode, franchisenemer, fakgroep, levscandat
FROM vwOpenVerOrd WHERE becode=#BecondeIN AND levdat IS NOT NULL AND fakstatus = 0
AND isAllFaktuurStukPrijsChecked = 1 AND IsAllFaktuurVrChecked = 1
AND (uitgestfaktuurdat IS NULL OR uitgestfaktuurdat<=#FactuurDate)
) sub
WHERE faktureerperorder = 1
GROUP BY becode, dtreknr, franchisebecode, franchisenemer, fakgroep, vonummer, vovolgnr,
FaktuurEindeMaand, FaktuurEindeWeek
ORDER BY MIN(levscandat)
At the WHERE faktureerperorder = 1 I came up with something like this:
WHERE faktureerperorder = 1 AND CASE WHEN #myParameterManual = 1 THEN vonummer=#vonummer ELSE 1=1 END
But this doesn't work. The #myParameterManual indicates whether or not it should select only a specific record. The vonummer=#vonummer is the record's ID. I thought by setting 1=1 I would get all the records.
Any ideas how to achieve my goal (perhaps more efficient ideas or better ideas)?
I'm finding it difficult to read your query, but this is hopefully a simple example of what you're trying to achieve.
I've used a WHERE clause with an OR operator to give you 2 options on the filter. Using the same query you will get different outputs depending on the filter value:
CREATE TABLE #test ( id INT, val INT );
INSERT INTO #test
( id, val )
VALUES ( 1, 10 ),
( 2, 20 ),
( 3, 30 );
DECLARE #filter INT;
-- null filter returns all rows
SET #filter = NULL;
SELECT *
FROM #test
WHERE ( #filter IS NULL
AND id < 5
)
OR ( #filter IS NOT NULL
AND id = #filter
);
-- filter a specific record
SET #filter = 2;
SELECT *
FROM #test
WHERE ( #filter IS NULL
AND id < 5
)
OR ( #filter IS NOT NULL
AND id = #filter
);
DROP TABLE #test;
First query returns all:
id val
1 10
2 20
3 30
Second query returns a single row:
id val
2 20

Find missing numbers in list of file names in one query

In document management database there is a list of existing files. New files are supposed to get a number, such as SW_01234.xxx. There is a numbering mechanism that serves the new numbers. Question is to find the missing elements - for example if file was deleted.
Existing file names might be completely different and not following the scheme above.
My attempt was to do it this way :
Split existing files at the "dot" - I don't care about .xxx extension, like .doc, .xlsx
Generate a temporary list of SW_00000 to SW_99999
Bring those element that exist in b) but not a)
Sample values
..
SW_00015.PRT
SW_00016.DRW
SW_00020.DRW
SW_00020.PDF
XBC115.DOC
..
I need to get SW_00017, SW_00018, SW_00019 (don't care about the XBC)
Need to have one query in the end
This should get you 99% of the way there. Tweak as necessary. You'll notice that records, 1, 3, 4, and 10 are all missing from the output.
DECLARE #allFiles TABLE (Name VARCHAR(100));
DECLARE #i INT = 0;
DECLARE #dataset TABLE (name VARCHAR(100));
INSERT INTO #dataset
( name )
VALUES ( 'SW_00001.PRT'), ('SW_00003.DRW'), ('SW_00004.DRW'), ('SW_00010.PDF'
);
WHILE #i < 100
BEGIN
INSERT INTO #allFiles
( Name )
VALUES ( 'SW_' + REPLICATE('0',5-LEN(#i)) + CAST(#i AS VARCHAR(10)) -- Name - varchar(100)
);
SET #i = #i + 1;
END;
SELECT *
FROM #allFiles af
WHERE NOT EXISTS (SELECT TOP 1 1 FROM #dataset ds WHERE af.Name = SUBSTRING(ds.name, 0, CHARINDEX('.', ds.name)))
I tried to implement your approach all in one query. In order to do it all in one query, I used CTEs to isolate the document numbers and also to get the range of numbers to use in the "not exists" part. If you need more range in the numbers table, you can get the range by querying differently. See Generate Sequential Set of Numbers
declare #t as table (DocName varchar(50));
insert #t (DocName)
values
('SW_00015.PRT')
,('SW_00016.DRW')
,('SW_00020.DRW')
,('SW_00020.PDF');
/*doing with CTE so the split and substring is more readable, plus needed it anyway for getting the numbers table*/
with isolatedFileNames
as (
/*might be dots in filename, reversing it to isolate the last set (file ext)*/
select DocName
,left(DocName, len(DocName) - charindex('.', reverse(DocName), 0)) as IsolatedDocName
from #t
)
,isolatedNumbers
as (
/*substring to get the number without the prefix*/
select DocName
,IsolatedDocName
,cast(substring(IsolatedDocName, charindex('_', IsolatedDocName, 0) + 1, len(IsolatedDocName)) as int) as IsolatedDocNumber
from isolatedFileNames
)
,numbers
as (
/*use row_number on a large set to get the range*/
select ROW_NUMBER() over (
order by object_id
) + (
/*start at the first document number, change this to 0 if you want to start at 0*/
select min(IsolatedDocNumber) - 1
from isolatedNumbers
) as num
from sys.all_objects
)
,numbersLessThanDocNumbers
as (
select num
from numbers
where num < (
/*limit to max document number in the set*/
select max(IsolatedDocNumber)
from isolatedNumbers
)
)
select num as MissingFromDocumentSet
from numbersLessThanDocNumbers n
where not exists (
select 1
from isolatedNumbers iso
where iso.IsolatedDocNumber = n.num
)

Missing right parenthesis and column being added already exists in table error shown in my code

I am trying to run this code
declare
temp_atr_val varchar2(400);
temp_val varchar2 (400);
temp_sum_percent decimal (10,3);
temp_variable number (10,3);
column_count number ;
val_count number;
sales_store number;
begin
select count(distinct ATTRIBUTE_INPUT) into column_count from look_up_table;
for ind in 1..column_count loop
/* putting current value of attribute from look_up_table in temp variable*/
select ATTRIBUTE_INPUT into temp_atr_val from (
select ATTRIBUTE_INPUT, rownum rwn
from
(
select distinct ATTRIBUTE_INPUT
from look_up_table
)
) where rwn = ind;
select count( value_for_atr ) into val_count from look_up_table;
for ind in 1..val_count loop
/* putting current value_for_atr for corresponding attribute from look_up_table in temp variable*/
select value_for_atr into temp_val from
(
select value_for_atr, rownum rwn
from look_up_table
) where rwn = ind;
SELECT SUM(CASE WHEN temp_atr_val = temp_val THEN net_sales_home ELSE 0 END) into temp_variable
FROM schemafinal;
/*temp_variable := temp_variable/sales_store;*/
EXECUTE IMMEDIATE 'ALTER TABLE SAR ADD (percent_'||temp_val||' number)';
EXECUTE IMMEDIATE ' update SAR b
set b.percent_'||temp_atr_val||'_'||temp_val||' = 105 ';
END LOOP;
END LOOP;
END;
But every time the code shows one of the 2 errors:
ORA-01430: column being added already exists in table
00000 - "missing right parenthesis"
And when I check the SAR table only 5 new columns are made in it.
I don't know why this is happening, have tried almost everything.
It is difficult to analyze the query without knowing the data structure.
But I am assuming you need an extra ATTRIBUTE_INPUT condition in the second loop select query to find temp_val. Otherwise for each ATTRIBUTE_INPUT temp_val will return same result.
That means in the second iteration of first loop temp_val will be the same old values of first iteration. So the Alter table Add query will throw error.
So please try to add an additional ATTRIBUTE_INPUT condition
/* putting current value_for_atr for corresponding attribute from look_up_table in temp variable*/
select value_for_atr into temp_val from
(
select value_for_atr, rownum rwn
from look_up_table
where ATTRIBUTE_INPUT = temp_atr_val
) where rwn = ind;

How to get result table from two tables without common field between tables?

I have two tables as shown below.
Consider that there is no such relationship between the tables.
So I need my result table should have like this as shown below.
How may I achieve this?
"AcctRef", in your DebitNoteTable, is a "repeating column".
That's a big, huge, no-no :)
You're debit table should look something like this:
Debit No AcctRef
-------- -------
DN1 CMP1
DN1 CMP3
DN1 CMP6
...
Then you could do a simple "join" ;)
Here's a good overview of normalization. I definitely encourage you to revisit your schema, if at all possible:
http://databases.about.com/od/specificproducts/a/normalization.htm
If you can't, then I guess "Plan B" would be write a program that:
reads all the prices and stores them in a table
reads all the AcctRef's for all the debits
Parses each AcctRef into individual accruals
prints the price and each debit for each accrual
This effectively means reading all the data in the entire database and then reorganizing it manually. If you're going to do that, why bother with a database in the first place?
PS:
It's unfortunate that you used a bitmap for your tables. Text would have been much nicer ;)
Try this:
Since the table is not normalized, you have to do the below steps.. Keeping comma separated values in a column is a bad idea. For any kind of operation on the table you have to split it..
Step 1: You have to create the following function to split the accRef column
create FUNCTION [dbo].[SDF_SplitString]
(
#sString varchar(2048),
#cDelimiter char(1)
)
RETURNS #tParts TABLE ( part varchar(2048) )
AS
BEGIN
if #sString is null return
declare #iStart int,
#iPos int
if substring( #sString, 1, 1 ) = #cDelimiter
begin
set #iStart = 2
insert into #tParts
values( null )
end
else
set #iStart = 1
while 1=1
begin
set #iPos = charindex( #cDelimiter, #sString, #iStart )
if #iPos = 0
set #iPos = len( #sString )+1
if #iPos - #iStart > 0
insert into #tParts
values ( substring( #sString, #iStart, #iPos-#iStart ))
else
insert into #tParts
values( null )
set #iStart = #iPos+1
if #iStart > len( #sString )
break
end
RETURN
END
step 2:
Use this query to get the result
with cte as(
select * from DebitNote cross apply dbo.SDF_SplitString(AccRef,','))
select part,price,[Debit No]=STUFF((SELECT ', ' + DebitNo
FROM cte b
WHERE b.part = a.part
FOR XML PATH('')), 1, 2, '')
FROM cte a join AccrualNote
on part=AccrualNo
GROUP BY part,price
SQL Fiddle Demo
I guess it should be something like:
SELECT a.Accrual_No, a.Price, d.Debit_no FROM AccrualNote AS a, DebitNote as d
WHERE a.Accrual_No IN d.AccRef
Next you need to create a loop for the records you get using this query (just try it using phpMyAdmin
(sure paulsm4 is absolutly right, but maybe you can't change the table structure)
CREATE FUNCTION [dbo].[F_Get_DebitNo] ( #AccrualNo VARCHAR(20) )
RETURNS VARCHAR(100)
AS
BEGIN
DECLARE #DebitNo VARCHAR(100)
SET #DebitNo = ''
SELECT #DebitNo = #DebitNo + ',' + DebitNo
FROM DebitNote
WHERE CHARINDEX(#AccrualNo, AccRef) > 0
SELECT #DebitNo = RIGHT(#DebitNo, LEN(#DebitNo) - 1)
RETURN #DebitNo
END
The sql works well, I'v test it already, you just need to create a Scalar-values Function as below.
SELECT AccrualNo ,
Price ,
dbo.F_Get_DebitNo(AccrualNo) FROM AccrualNote

Resources