How fix double encoding in PostgreSQL? - sql

I have a table in PostgreSQL with words, but some words have invalid UTF-8 chars like 0xe7e36f and 0xefbfbd.
How I can identify all chars inside words that are invalid and replace they with some symbol like ??
EDIT: My database is in UTF-8, but I think there are double encoding from various other encodings. I think this because when I tried to convert to one type as LATIN1, I get an error saying that some char don't exists in that encoding, when I change to LATIN2 I get
the same error, but with another character.
So, what is possible to do to solve this?

Usage
It's a solution for my specific case, but maybe with some modifications can help another people.
Usage
SELECT fix_wrong_encoding('LATIN1');
Function
-- Convert words with wrong encoding
CREATE OR REPLACE FUNCTION fix_wrong_encoding(encoding_name VARCHAR)
RETURNS VOID
AS $$
DECLARE
r RECORD;
counter INTEGER;
token_id INTEGER;
BEGIN
counter = 0;
FOR r IN SELECT t.id, t.text FROM token t
LOOP
BEGIN
RAISE NOTICE 'Converting %', r.text;
r.text := convert_from(convert_to(r.text,encoding_name),'UTF8');
RAISE NOTICE 'Converted to %', r.text;
RAISE NOTICE 'Checking existence.';
SELECT id INTO token_id FROM token WHERE text = r.text;
IF (token_id IS NOT NULL) THEN
BEGIN
RAISE NOTICE 'Token already exists. Updating ids in textblockhastoken';
IF(token_id = r.id) THEN
RAISE NOTICE 'Token is the same.';
CONTINUE;
END IF;
UPDATE textblockhastoken SET tokenid = token_id
WHERE tokenid = r.id;
RAISE NOTICE 'Removing current token.';
DELETE FROM token WHERE id = r.id;
END;
ELSE
BEGIN
RAISE NOTICE 'Token don''t exists. Updating text in token';
UPDATE token SET text = r.text WHERE id = r.id;
END;
END IF;
EXCEPTION WHEN untranslatable_character THEN
--do nothing
WHEN character_not_in_repertoire THEN
--do nothing
END;
counter = counter + 1;
RAISE NOTICE '% token converted', counter;
END LOOP;
END
$$
LANGUAGE plpgsql;

Related

Function returning error texts in Oracle APEX

I am trying to take a count of the records in the interactive grid and based on that I am trying to pass a message to the user. However, I am getting error : ORA-06550: line 1, column 141: PLS-00103: Encountered the symbol "NUMBER" when expecting one of the following: := . ( # % ; The symbol "." was substituted for "NUMBER" to continue.Following is my code in the validation. Validation Type is : Function Returning Error Text.
l_count NUMBER := 0;
BEGIN
SELECT COUNT(1)
INTO l_count
FROM ugh
WHERE ugh.pre = :PRE
AND ugh.APP1 = :APP1
AND ugh.APP2 = :APP2
AND ugh.APP3 = :APP3
AND ugh.FINL_APP = :FINL_APP;
IF l_count > 1 THEN
IF END_DATE IS NULL THEN
RETURN 'Error Message to be displayed.';
ELSE
RETURN NULL;
END IF;
ELSE
RETURN NULL;
END IF;
END;
Can anyone please help ?
Looks like you're missing the DECLARE keyword:
DECLARE --> this
l_count NUMBER := 0;
BEGIN
SELECT COUNT (1)
INTO l_count
FROM ugh
Also, what is END_DATE? You never declared it. If it is a page item, then precede it with a colon, :END_DATE

Error while writing to array plsql how to fix? Extend doesn't work also

so I am trying to write to an array in PL/SQL, and I always get the subscript outside of limit error. I've seen similar posts and implemented everything based on those answers, I can't seem to find what I'm doing wrong. The line giving the error is "arr_quartosLivres(counter) := q.id;" I've tried to extend the array and it still doesn't work, however, either way, the look only runs 21 times (because there are only 21 values in the table quarto) so it shouldn't even need to be extended. Any help would be highly appreciated! Thank you
SET SERVEROUTPUT ON;
DECLARE
p_idReserva reserva.id%type := 408;
v_dataEntradaReserva reserva.data_entrada%type;
counter integer := 0;
type arr_aux IS varray(21) of quarto.id%type;
arr_quartosLivres arr_aux := arr_aux();
BEGIN
SELECT data_entrada INTO v_dataEntradaReserva FROM reserva WHERE id = p_idreserva;
FOR q IN (SELECT * FROM quarto)
LOOP
BEGIN
IF isQuartoIndisponivel(q.id, v_dataEntradaReserva)
THEN DBMS_OUTPUT.PUT_LINE('nao disponivel' || counter);
arr_quartosLivres(counter) := q.id;
ELSE DBMS_OUTPUT.PUT_LINE('disponivel' || counter);
END IF;
counter := counter + 1;
END;
END LOOP;
END;
The index values for varray begin with 1. Your logic is trying to use index value 0. Thus index out of range. BTW extend does not apply to varray, when declared a varray has a fixed size. You have 3 solutions: initialize counter to 1 instead of 0, or move incrementing it prior to its use as an index. Since as it stands you increment every time through the loop, even when the IF condition returns false and you do not use the counter as an index, leaving a NULL value in the array.But you use counter for 2 different purposes: Counting rows processed and index into the array. Since the row value may not be put into the array then your 3rd option is to introduce another variable for the index. Further there is no need for the BEGIN ... End block in the loop.
declare
p_idreserva reserva.id%type := 408;
v_dataentradareserva reserva.data_entrada%type;
counter integer := 0;
type arr_aux is varray(21) of quarto.id%type;
arr_quartoslivres arr_aux := arr_aux();
varray_index integer := 1 ; -- index varaibal for varray.
begin
select data_entrada into v_dataentradareserva from reserva where id = p_idreserva;
for q in (select * from quarto)
loop
if isquartoindisponivel(q.id, v_dataentradareserva)
then
dbms_output.put_line('nao disponivel' || counter || ' at index ' || varray_index);
arr_quartoslivres(varray_index) := q.id;
varray_index := varray_index + 1;
else
dbms_output.put_line('disponivel' || counter);
end if;
counter := counter + 1;
end loop;
end;

Having hard time figuring out the best attribute to use with cursor

Using this attribute %NOTFOUND with this cursor is giving me issues. I also tried using %FOUND. Is There a better option? It keeps returning the Else even if the cursor comes back with something in it or not. I want it to send the first email if the cursor has something and the second one if the cursor has nothing.
CURSOR crs IS
select *
from user_objects
where status = 'INVALID';
BEGIN
OPEN crs;
Loop
FETCH crs bulk collect INTO messages limit 10;
EXIT WHEN message. count = '0';
End IF;
for indx in messages.FIRST .. messages.LAST
loop
email_body := email_body||CHR(10)||'OBJECT NAME: '||messages(indx).OBJECT_NAME||', OBJECT TYPE: '||messages(indx). OBJECT_TYPE||', STATUS: '||messages(indx).STATUS;
end loop;
END LOOP;
IF CRS%NOTFOUND THEN
Email_body := email_body||CHR(10)|| '' ||CHR(10)||'All of these objects are invalid in your database. Please troubleshoot the issue. Thank you.'
DBMS_OUTPUT_LINE(email_body||'Invalid obj.';
ELSE
Email_body := 'There are no invalid objects in your database. Thank You.';
DBMS_OUTPUT_LINE(email_body||'No Invalid obj.';
END IF;
You can try this for test (i think more readable and shorter):
declare
email_body varchar2( 4000 ) := '';
l_invalid_objects_list varchar2( 4000 ) := '';
begin
l_invalid_objects_list := '';
for i in ( select OBJECT_NAME, OBJECT_TYPE, STATUS from user_objects where status = 'INVALID' and rownum <= 10 ) --limited to 10 records
loop
l_invalid_objects_list := l_invalid_objects_list||CHR(10)||'OBJECT NAME: '||i.OBJECT_NAME||', OBJECT TYPE: '||i. OBJECT_TYPE||', STATUS: '||i.STATUS;
end loop;
if length( l_invalid_objects_list ) > 0 then
email_body := email_body||CHR(10)|| '' ||CHR(10)||l_invalid_objects_list||CHR(10)|| '' ||CHR(10)||'All of these objects are invalid in your database. Please troubleshoot the issue. Thank you.';
DBMS_OUTPUT.PUT_LINE(email_body||'Invalid obj.');
else
Email_body := 'There are no invalid objects in your database. Thank You.';
DBMS_OUTPUT.PUT_LINE(email_body||'No Invalid obj.');
end if;
end;
I'm assuming you want to use a bulk operation and that you want to do this in batches of 10 even though it might be overkill for the functionality.
So . . . you need to declare a table type based on the cursor (ROWTYPE) then declare a variable based on the type.
You want to add to the email_body for each object and when you've looped through the lot it looks like you want another message saying if there were any invalid objects.
Using %NOTFOUND is not right here as you exit your loop when the messages.COUNT = 0. When it is 0 the cursor will always be %NOTFOUND so you're always getting the INVALID option.
I've used a boolean that is set to TRUE as soon as you have at least one invalid object and that is checked instead of the %NOTFOUND.
DECLARE
CURSOR crs
IS
SELECT *
FROM user_objects
WHERE status = 'INVALID';
TYPE work_recs IS TABLE OF crs%ROWTYPE;
messages work_recs;
lbol_invalid_objects BOOLEAN := FALSE;
email_body VARCHAR2(2000);
BEGIN
OPEN crs;
LOOP
FETCH crs BULK COLLECT INTO messages LIMIT 10;
DBMS_OUTPUT.PUT_LINE('COUNT - '||messages.COUNT);
EXIT WHEN messages.COUNT = '0';
lbol_invalid_objects := TRUE;
FOR indx IN messages.FIRST .. messages.LAST
LOOP
email_body := email_body||CHR(10)||'OBJECT NAME: '||messages(indx).OBJECT_NAME||', OBJECT TYPE: '||messages(indx). OBJECT_TYPE||', STATUS: '||messages(indx).STATUS;
END LOOP;
END LOOP;
IF lbol_invalid_objects THEN
email_body := email_body||CHR(10)|| '' ||CHR(10)||'All of these objects are invalid in your database. Please troubleshoot the issue. Thank you.'
dbms_output.put_line('Invalid obj.');
ELSE
email_body := 'There are no invalid objects in your database. Thank You.';
dbms_output.put_line('No Invalid obj.');
END IF;
END;

Postgresql function auto add 's' character to the end of string

I have a function in PostgreSQL database. However, every time I run the function in PostgreSQL, it auto-adda the character s behind of the query, therefore, I receive an error when it executes.
An example query ends up looking like this:
WHAT IN HERE: query SELECT uom_id FROM ps_quantity where id = 11s
My version is PostgreSQL 9.2.13. How can I solve this? Thanks.
CREATE OR REPLACE FUNCTION select_field(
selected_table text,
selected_field text,
field_type_sample anyelement,
where_clause text DEFAULT ''::text)
RETURNS anyelement AS
$BODY$ DECLARE
-- Log
ME constant text := 'selected_field()';
-- Local variables
_qry varchar := '';
_result_value ALIAS FOR $0;
where_clause1 varchar := 'asdasdsad';
BEGIN
RAISE NOTICE 'FUNCTION: SELECT_FIELD';
-- BANGPH
RAISE NOTICE 'BANGPH - CHANGE 11s to 11';
_qry := 'SELECT uom_id FROM ps_quantity where id = 11';
RAISE NOTICE 'WHERE = %s', where_clause1;
RAISE NOTICE 'WHAT IN HERE: query %s', _qry;
As the manual explains:
instead of:
RAISE NOTICE 'WHAT IN HERE: query %s', _qry;
you need to use:
RAISE NOTICE 'WHAT IN HERE: query %', _qry;
Placeholders for the RAISE statement don't have a "type modifier", it's a plain %

What is << some text >> in oracle

I found this character while reading some blog of pl sql << some text >> .
I found this character from following blog http://www.oracle-base.com/articles/8i/collections-8i.php
As others have said, <<some_text>> is a label named "some_text". Labels aren't often used in PL/SQL but can be helpful in a variety of contexts.
As an example, let's say you have several nested loops, execution has reached the very inner-most level, and the code needs to exit from all the nested loops and continue after the outer-most one. Here a label can be used in the following fashion:
<<outer_most_loop>>
LOOP
...
<<next_inner_loop>>
LOOP
...
<<inner_most_loop>>
LOOP
...
IF something <> something_else THEN
EXIT outer_most_loop;
END IF;
...
END LOOP inner_most_loop;
...
END LOOP next_inner_loop;
...
END LOOP outer_most_loop;
-- Execution continues here after EXIT outer_most_loop;
something := something_else;
...
Next, let's say that you've got some code with nested blocks, each of which declares a variable of the same name, so that you need to instruct the compiler about which of the same-named variables you intend to use. In this case you could use a label like this:
<<outer>>
DECLARE
nNumber NUMBER := 1;
BEGIN
<<inner>>
DECLARE
nNumber NUMBER := 2;
BEGIN
DBMS_OUTPUT.PUT_LINE('outer.nNumber=' || outer.nNumber);
DBMS_OUTPUT.PUT_LINE('inner.nNumber=' || inner.nNumber);
END inner;
END outer;
Labels can also be useful if you insist on giving a variable the same name as a column in a table. As an example, let's say that you have a table named PEOPLE with a non-nullable column named LASTNAME and you want to delete everyone with LASTNAME = 'JARVIS'. The following code:
DECLARE
lastname VARCHAR2(100) := 'JARVIS';
BEGIN
DELETE FROM PEOPLE
WHERE LASTNAME = lastname;
END;
will not do what you intended - instead, it will delete every row in the PEOPLE table. This occurs because in the case of potentially ambiguous names, PL/SQL will choose to use the column in the table instead of the local variable or parameter; thus, the above is interpreted as
DECLARE
lastname VARCHAR2(100) := 'JARVIS';
BEGIN
DELETE FROM PEOPLE p
WHERE p.LASTNAME = p.lastname;
END;
and boom! Every row in the table goes bye-bye. :-) A label can be used to qualify the variable name as follows:
<<outer>>
DECLARE
lastname VARCHAR2(100) := 'JARVIS';
BEGIN
DELETE FROM PEOPLE p
WHERE p.LASTNAME = outer.lastname;
END;
Execute this and only those people with LASTNAME = 'JARVIS' will vanish.
And yes - as someone else said, you can GOTO a label:
FUNCTION SOME_FUNC RETURN NUMBER
IS
SOMETHING NUMBER := 1;
SOMETHING_ELSE NUMBER := 42;
BEGIN
IF SOMETHING <> SOMETHING_ELSE THEN
GOTO HECK;
END IF;
RETURN 0;
<<HECK>>
RETURN -1;
END;
(Ewwwww! Code like that just feels so wrong..!)
Share and enjoy.
It's often used to label loops, cursors, etc.
You can use that label in goto statements. Else, it is just 'comment'.
Sample from Oracle:
DECLARE
p VARCHAR2(30);
n PLS_INTEGER := 37; -- test any integer > 2 for prime
BEGIN
FOR j in 2..ROUND(SQRT(n)) LOOP
IF n MOD j = 0 THEN -- test for prime
p := ' is not a prime number'; -- not a prime number
GOTO print_now; -- << here is the GOTO
END IF;
END LOOP;
p := ' is a prime number';
<<print_now>> -- << and it executes this
DBMS_OUTPUT.PUT_LINE(TO_CHAR(n) || p);
END;
/
It is a label, a subgroup of comments in the plsql syntax.
http://ss64.com/oraplsql/operators.html
Its is a label delimeter
<< label delimiter (begin)
label delimiter (end) >>
http://docs.oracle.com/cd/B10501_01/appdev.920/a96624/02_funds.htm