ORA-01722 Error when Returning Identity Column into variable - oracle19c

I have the table below, and I am inserting a record into it. For some reason, the RETURNING [column_name] INTO [variable] is throwing an ORA-01722: invalid number error. I've looked at other similar issues on stack overflow and elsewhere and only thing I found is someone was using a variable for the [column_name] that needed an extra step, but i'm using the [column_name] explicitly.
TABLE:
catalog_year
catalog_year_id number (pk, identity column)
catalog_year varchar2(10)
catalog_status_id number
declare
l_new_calendar_year_id number;
begin
insert into catalog_year
(catalog_year, catalog_status_id)
values
('2022-2023', 5)
returning catalog_year_id into l_new_calendar_year_id;
end;

Related

How to convert text field with formatted currency to numeric field type in Postgres?

I have a table that has a text field which has formatted strings that represent money.
For example, it will have values like this, but also have "bad" invalid data as well
$5.55
$100050.44
over 10,000
$550
my money
570.00
I want to convert this to a numeric field but maintain the actual numbers that can be retained, and for any that can't , convert to null.
I was using this function originally which did convert clean numbers (numbers that didn't have any formatting). The issue was that it would not convert $5.55 as an example and set this to null.
CREATE OR REPLACE FUNCTION public.cast_text_to_numeric(
v_input text)
RETURNS numeric
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
declare v_output numeric default null;
begin
begin
v_output := v_input::numeric;
exception when others then return null;
end;
return v_output;
end;
$BODY$;
I then created a simple update statement which removes the all non digit characters, but keeps the period.
update public.numbertesting set field_1=regexp_replace(field_1,'[^\w.]','','g')
and if I run this statement, it correctly converts the text data to numeric and maintains the number:
alter table public.numbertesting
alter column field_1 type numeric
using field_1::numeric
But I need to use the function in order to properly discard any bad data and set those values to null.
Even after I run the clean up to set the text value to say 5.55
my "cast_text_to_numeric" function STILL sets this to null ? I don't understand why this sets it to null, but the above statement correctly converts it to a proper number.
How can I fix my cast_text_to_numeric function to properly convert values such as 5.55 , etc?
I'm ok with disgarding (setting to NULL) any values that don't end up with numbers and a period. The regular expression will strip out all other characters... and if there happens to be two numbers in the text field, with the script, they would be combined into one (spaces are removed) and I'm good with that.
In the example of data above, after conversion, the end result in numeric field would be:
5.55
100050.44
null
550
null
570.00
FYI, I am on Postgres 11 right now

Can you reference an aggregate function on a temporary row in an insert statement within a stored procedure in postgresql?

I am writing a postgres stored procedure that loops through the rows returned from a select statement. For each row it loops through, it inserts values from that select statement into a new table. One of the values I need to insert into the second table is the average of a column. However, when I call the stored procedure, I get an error that the temporary row has no attribute for the actual column that I am averaging. See stored procedure and error below.
Stored Procedure:
create or replace procedure sendToDataset(sentence int)
as $$
declare temprow peoplereviews%rowtype;
BEGIN
FOR temprow IN
select rulereviewid, avg(rulereview)
from peoplereviews
where sentenceid = sentence
group by rulereviewid
loop
insert into TrainingDataSet(sentenceId, sentence, ruleCorrectId, ruleCorrect, dateAdded)
values(sentence, getSentenceFromID(sentence), tempRow.rulereviewid, tempRow.avg(rulereview), current_timestamp);
END LOOP;
END
$$
LANGUAGE plpgsql;
Error:
ERROR: column "rulereview" does not exist
LINE 2: ...omID(sentence), tempRow.rulereviewid, tempRow.avg(rulereview...
^
QUERY: insert into TrainingDataSet(sentenceId, sentence, ruleCorrectId, ruleCorrect, dateAdded)
values(sentence, getSentenceFromID(sentence), tempRow.rulereviewid, tempRow.avg(rulereview), current_timestamp)
CONTEXT: PL/pgSQL function sendtodataset(integer) line 11 at SQL statement
SQL state: 42703
Basically, I am wondering if it's possible to use that aggregate function in the insert statement or not and if not, if there is another way around it.
you don't need to use a slow and inefficient loop for this:
insert into TrainingDataSet(sentenceId, sentence, ruleCorrectId, ruleCorrect, dateAdded)
select getSentenceId(sentence), sentence, rulereviewid, avg(rulereview), current_timestamp
from peoplereviews
where sentenceid = sentence
group by rulereviewid
To answer the original question: you need to provide a proper alias for the aggregate:
FOR temprow IN
select rulereviewid, avg(rulereview) as avg_views
from peoplereviews
where sentenceid = sentence
group by rulereviewid
loop
insert into TrainingDataSet(sentenceId, sentence, ruleCorrectId, ruleCorrect, dateAdded)
values(sentence, getSentenceFromID(sentence), tempRow.rulereviewid,
tempRow.avg_views, current_timestamp);
END LOOP;

row number 0 is out of range 0..-1 LIBPQ

query = "select * results where id = '";
query.append(ID);
query.append("'");
res = PQexec(conn, query.c_str());
After executing this statement, i get the following error.
row number 0 is out of range 0..-1
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
However, when I run the same query in postgresql, it does not have any problem.
select * from results where id = 'hello'
The only problem is that if the query parameter passed is not in database, it would throw runtime error. If you provide the exact query parameter which is in database, it executes normally.
That's two separate errors, not one. This error:
row number 0 is out of range 0..-1
is from libpq, but is reported by code you have not shown here.
The error:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
is not from PostgreSQL, it is from your C++ runtime.
It isn't possible for me to tell exactly where it came from. You should really run the program under a debugger to tell that. But if I had to guess, based on the code shown, I'd say that ID is null, so:
query.append(ID);
is therefore aborting the program.
Separately, your code is showing a very insecure practice where you compose SQL by string concatenation. This makes SQL injection exploits easy.
Imagine what would happen if your "ID" variable was set to ';DROP TABLE results;-- by a malicious user.
Do not insert user-supplied values into SQL by appending strings.
Instead, use bind parameters via PQexecParams. It looks complicated, but most parameters are optional for simple uses. A version for your query, assuming that ID is a non-null std::string, would look like:
PGresult res;
const char * values[1];
values[0] = ID.c_str();
res = PQexecParams("SELECT * FROM results WHERE id = $1",
1, NULL, values, NULL, NULL, 0);
If you need to handle nulls you need another parameter; see the documentation.
Maybe, a bit too late but just want to put in my 5 cents.
Got this error also these days with a very simple stored procedure of the kind like:
CREATE OR REPLACE FUNCTION selectMsgCounter()
RETURNS text AS
$BODY$
DECLARE
msgCnt text;
BEGIN
msgCnt:= (SELECT max(messageID)::text from messages);
RETURN 'messageCounter: ' || msgCnt;
END
$BODY$
LANGUAGE plpgsql STABLE;
Made some debugging with:
if (PQntuples(res)>=1)
{
char* char_result=(char*) realloc(NULL,PQgetlength(res, 0,0)*sizeof(char));
strcpy( char_result,PQgetvalue(res, 0, 0));
bool ok=true;
messageCounter=QString(char_result).remove("messageCounter: ").toULongLong(&ok);
if (!ok) messageCounter=-1;
qDebug()<<"messageCounter: " << messageCounter;
free(char_result);
PQclear(res);
PQfinish(myConn); // or do call destructor later?
myConn=NULL;
}
else
{
fprintf(stderr, "storedProcGetMsgCounter Connection Error: %s",
PQerrorMessage(myConn));
PQclear(res);
PQfinish(myConn); // or do call destructor later?
myConn=NULL;
}
Turned out that the owner of the stored procedure was not the one whose credentials I used to log in with.
So - at least - in my case this error "row number 0 is out of range 0..-1" was at first sight a false positive.

CTE with HierarchyID suddenly causes parse error

So I have this self-referencing table in my database named Nodes, used for storing the tree structure of an organization:
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL,
[ParentId] [int] NULL,
(+ other metadata columns)
And from it I'm using HIERARCHYID to manage queries based on access levels and such. I wrote a table-valued function for this, tvf_OrgNodes, a long time ago, tested and working on SQL Server 2008 through 2014 and it's remained unchanged since then since it's been doing great. Now, however, something has changed because the parsing of HIERARCHYIDs from path nvarchars ("/2/10/8/") results in the following error, matching only 4 hits (!) on Google:
Msg 6522, Level 16, State 2, Line 26
A .NET Framework error occurred during execution of user-defined routine or aggregate "hierarchyid":
Microsoft.SqlServer.Types.HierarchyIdException: 24000: SqlHierarchyId operation failed because HierarchyId object was constructed from an invalid binary string.
When altering the function to only return NVARCHAR instead of actual HIERARCHYID's, the paths all look fine, beginning with / for the root, followed by /2/ etc etc. Simply selecting HIERARCHYID::Parse('path') also works fine. I actually got the function working by leaving the paths as strings all the way until the INSERT into the function result, parsing the paths there. But alas, I get the same error when I then try and insert the reusulting data into a table of same schema.
So the question is, Is this a bug, or does anybody know of any (new?) pitfalls in working with HIERARCHYIDs<->Path strings that could cause this? I don't get where the whole binary string idea comes from.
This is the code of the TVF:
CREATE FUNCTION [dbo].[tvf_OrgNodes] ()
RETURNS #OrgNodes TABLE (
OrgNode HIERARCHYID,
NodeId INT,
OrgLevel INT,
ParentNodeId INT
) AS
BEGIN
WITH orgTree(OrgNode, NodeId, OrgLevel, ParentNodeId) AS (
-- Anchor expression = root node
SELECT
CAST(HIERARCHYID::GetRoot() AS varchar(180))
, n.Id
, 0
, NULL
FROM Nodes n
WHERE ParentId IS NULL -- Top level
UNION ALL
-- Recursive expression = organization tree
SELECT
CAST(orgTree.OrgNode + CAST(n.Id AS VARCHAR(180)) + N'/' AS VARCHAR(180))
, n.Id
, orgTree.OrgLevel + 1
, n.ParentId
FROM Nodes AS n
JOIN orgTree
ON n.ParentId = orgTree.NodeId
)
INSERT INTO #OrgNodes
SELECT
HIERARCHYID::Parse(OrgNode),
NodeId,
OrgLevel,
ParentNodeId
FROM orgTree;
RETURN;
END
I might have recently installed .NET 4.53 aka 4.6 for the lolz. Can't find much proof of it anywhere except in the reg, though: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework\v4.0.30319\SKUs.NETFramework,Version=v4.5.3

Print value from a lua table if pattern matches

Okay, so I just recently got into lua and find myself stuck with the following:
I have the function peripheral.getNames() (which is a custom function)
it will return a table with the structure key,value, whereas key is always a number and starts from 1 and value will be what the function finds (it searches for devices connected to it)
In my example it creates a table which looks like this
1 herp
2 derp
3 monitor_1
4 morederp
I can print the values with the following
local pgn = peripherals.getNames()
for key,value in pairs(pgn) do
setCursorPos(1,key)
write(value)
end
end
this will output the corresponding value of the table at key on my display like this
herp
derp
monitor_1
morederp
now, I try to filter my results so it only prints something if value contains 'monitor'
I tried to achive this with
for key,value in pairs(pgn) do
if string.match(value, monitor) then
#dostuff
end
end
but it always returns 'bad argument: string expected, got nil'
so obviously string.match either does not accept 'value' or, value is not a string
so i tried converting value first
for key,value in pairs(pgn) do
value = tostring(value)
if ....
#dostuff
end
end
but it still throws the same error
Do any of you have an idea how i might either get string.match to accept 'value' or if there is another method to check the contents of 'value' for a pattern while in this for loop?
The error message is talking about the variable monitor, which is not defined and so has a nil value.
Try string.match(value, "monitor").