PL/SQL Query to check row's length - sql

I'm having some trouble on solving this.
I have to check on the table, if there's any row that exceed the length of 34 characters (for this, I'm using this first part of the query using Lenght command), if found, return the error with the variable 'END_CNPJ$' (that's being populated by the second part of the query 'ENDERECO') so the user can see which row has more than 34 characters. Is this code correct (probably not)? If it isn't, how can I fix it?
SELECT
LENGTH(CONCAT (CONCAT (CONCAT(CONCAT (CONCAT (CONCAT (CONCAT (
'', T.TTIPO_LOGR),
''), T.TENDERE),
''), T.NNRO_ENDER),
''),T.TCOMPL_ENDER) ),
T.TTIPO_LOGR || ' ' || T.TENDERE || ', ' || T.NNRO_ENDER || ' ' || T.TCOMPL_ENDER || ' - ' || TMUNICI || ' CNPJ: ' || T.NCGC AS ENDERECO
INTO CHARACTER_COUNT$, END_CNPJ$
FROM TBENDER T
WHERE T.CEMPRES = :ENDER_BLK.CEMPRES;
IF CHARACTER_COUNT$ > 34 THEN
MSG_ALERT_COSMO(' You exceeded 34 character for this address: ' || END_CNPJ$ );
RAISE FORM_TRIGGER_FAILURE;
END IF;
I hope I'm not violating any rule, just got here yesterday :D
TIA

That's actually Oracle Forms, is it not? raise form_trigger_failure and :ender_blk smell so.
In that case, the only drawback might be possibility of no rows in that table for block item value (which will raise no_data_found) or two or more rows for it (which will then raise too_many_rows).
Other than that, this should be OK.
Though, it is kind of unclear why you nicely concatenated values (using the double pipe || operator) for END_CNPJ$ and nested that many concat functions for CHARACTER_COUNT$.
Also, you didn't post the whole trigger code (missing declarations, begin-end keywords, perhaps something else).
But, as I said, in general - that's OK.

Related

How do I parameterize table & column in a Postgres-custom-function, selecting PK if value exists, otherwise insert it and return PK anyways?

Trying to do what I specified in the title, I already got the upsert-functionalities working, however when I try to parameterize it, I'm just out of my depth and can't debug it.
My query:
CREATE OR REPLACE FUNCTION custom_upsert(target_value_input text,
target_table_input text,
target_column_input text,
OUT pk_output int)
LANGUAGE plpgsql AS
$func$
BEGIN
LOOP
execute 'SELECT id '
' FROM ' || target_table_input ||
' WHERE ' || target_column_input || ' = ' || target_value_input ||
' INTO pk_output';
EXIT WHEN FOUND;
execute 'INSERT INTO ' || target_table_input || 'AS o ( ' || target_column_input || ' )'
' VALUES ( ' || target_value_input || ' ) '
' ON CONFLICT ( ' || target_column_input || ' ) DO NOTHING '
' RETURNING o.id'
' INTO pk_output';
EXIT WHEN FOUND;
END LOOP;
END
$func$;
now when I try to use the function, I get:
ERROR: syntax error at or near "INTO"
LINE 1: ...module WHERE artifact_id = artifact_id_example_1 INTO pk_ou...
^
QUERY: SELECT id FROM maven_module WHERE artifact_id = artifact_id_example_1 INTO pk_output
CONTEXT: PL/pgSQL function custom_upsert(text,text,text) line 4 at EXECUTE
What puzzles me about this is the fact that this syntax works fine in an unparameterized version:
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=765389a746d3a392bc646fbedb7ed3b3
My attempts at parameterization:
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=1bffab45d8a9587342a7c3253ea35fc8
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=de6ba235aa21dae33b922f8fddac3b63
Thank you very much in advance, first time posting so if there's anything I should do differently when asking a question, I'm happy about feedback
edit: this is my function call:
-- should return pk of existing artifact_id
SELECT custom_upsert('artifact_id_example_1', 'maven_module', 'artifact_id');
-- should return pk of new artifact_id
SELECT custom_upsert('artifact_id_example_2', 'maven_module', 'artifact_id');
Do not concatenate strings like that. The function format() makes your life much easier (safer), e.g.
EXECUTE format('INSERT INTO %1$I AS o (%2$I)
VALUES (%3$L) ON CONFLICT (%2$I) DO NOTHING RETURNING o.id',
target_table_input,
target_column_input,
target_value_input) INTO pk_output;
%I will wrap the identifiers with double quote, which is handy when tables or columns are case sensitive of contain special characters.
%L will wrap the literals with single quotes
1$, 2$ and 3$ are the variables positions provided in the format() call, which is quite handy if one variable is used more than once.
Demo: db<>fiddle

SQL I need to extract a stored procedure name from a string

I am a bit new to this site but I have looked an many possible answers to my question but none of them has answered my need. I have a feeling it's a good challenge. Here it goes.
In one of our tables we list what is used to run a report this can mean that we can have a short EXEC [svr1].[dbo].[stored_procedure] or "...From svr1.dbo.stored_procedure...".
My goal is to get the stored procedure name out of this string (column). I have tried to get the string between '[' and ']' but that breaks when there are no brackets. I have been at this for a few days and just can't seem to find a solution.
Any assistance you can provide is greatly appreciated.
Thank you in advance for entertaining this question.
almostanexpert
Considering the ending character of your sample sentences is space, or your sentences end without trailing ( whether space or any other character other than given samples ), and assuming you have no other dots before samples, the following would be a clean way which uses substring(), len(), charindex() and replace() together :
with t(str) as
(
select '[svr1].[dbo].[stored_procedure]' union all
select 'before svr1.dbo.stored_procedure someting more' union all
select 'abc before svr1.dbo.stored_procedure'
), t2(str) as
(
select replace(replace(str,'[',''),']','') from t
), t3(str) as
(
select substring(str,charindex('.',str)+1,len(str)) from t2
)
select
substring(
str,
charindex('.',str)+1,
case
when charindex(' ',str) > 0 then
charindex(' ',str)
else
len(str)
end - charindex('.',str)
) as "Result String"
from t3;
Result String
----------------
stored_procedure
stored_procedure
stored_procedure
Demo
With the variability of inputs you seem to have we will need to plan for a few scenarios. The below code assumes that there will be exactly two '.' characters before the stored_procedure, and that [stored_procedure] will either end the string or be followed by a space if the string continues.
SELECT TRIM('[' FROM TRIM(']' FROM --Trim brackets from final result if they exist
SUBSTR(column || ' ', --substr(string, start_pos, length), Space added in case proc name is end of str
INSTR(column || ' ', '.', 1, 2)+1, --start_pos: find second '.' and start 1 char after
INSTR(column || ' ', ' ', INSTR(column || ' ', '.', 1, 2), 1)-(INSTR(column || ' ', '.', 1, 2)+1))
-- Len: start after 2nd '.' and go until first space (subtract 2nd '.' index to get "Length")
))FROM TABLE;
Working from the middle out we'll start with using the SUBSTR function and concatenating a space to the end of the original string. This allows us to use a space to find the end of the stored_procedure even if it is the last piece of the string.
Next to find our starting position, we use INSTR to search for the second instance of the '.' and start 1 position after.
For the length argument, we find the index of the first space after that second '.' and then subtract that '.' index.
From here we have either [stored_procedure] or stored_procedure. Running the TRIM functions for each bracket will remove them if they exist, and if not will just return the name of the procedure.
Sample inputs based on above description:
'EXEC [svr1].[dbo].[stored_procedure]'
'EXEC [svr1].[dbo].[stored_procedure] FROM TEST'
'svr1.dbo.stored_procedure'
Note: This code is written for Oracle SQL but can be translated to mySQL using similar functions.

Using CASE on empty string

I have a code that goes like this:
SELECT
'"35933-14",' ||
'"' || us_1.gr_UniqueName || '",' ||
'"' || (CASE WHEN us_1.mls0_PrimaryString = '' THEN 'This is empty'
WHEN CAST(Length(us_1.mls0_PrimaryString) AS INT) < 4 THEN ('Less than 4: '|| SUBSTR(us_1.mls0_PrimaryString,1,10000))
ELSE SUBSTR(us_1.mls0_PrimaryString,1,10000) END) || '",' ||
'"",' ||
'"",' ||
'""'
FROM
us_GroupTab us_1
WHERE (us_1.gr_Active = 1)
AND (us_1.gr_PurgeState = 0)
AND (us_1.gr_PartitionNumber = 0)
AND (us_1.gr_UniqueName IN ('US_HARDWARE_1', 'US_HARDWARE_2','GROUP_NULL'));
Basically the problem is that not all empty string is handled, some users are only inputting multiple spaces which the first case statement does not handle. Is there any way to do this, I have tried using TRIM function but it does not work.
Thanks!
An empty string is the same as null in Oracle, and you can't compare anything to null. You need to use is null instead of = null or = ''.
CASE WHEN TRIM(us_1.mls0_PrimaryString) IS null THEN 'This is empty' ...
You also don't need to cast the length check to int. And the maximum length of a varchar2 before 12c is 4000 chars, so there's no point using 10000 in your substr. In fact the first substr isn't going to do anything anyway as you already know the length is less than 4.
If you want to remove new lines and carriage returns before checking - and that is perhaps something you should be doing client-side, unless you want to store those too - then you can either replace them first:
CASE WHEN TRIM(REPLACE(REPLACE(us_1.mls0_PrimaryString, CHR(10)), CHR(13))) IS null
THEN ...
Or more generically remove all whitespace which would catch tabs etc. too:
CASE WHEN REGEXP_REPLACE(us_1.mls0_PrimaryString, '[[:space:]]') IS NULL THEN ...
Or:
CASE WHEN REGEXP_LIKE(us_1.mls0_PrimaryString, '^[[:space:]]*$') THEN ...
Note that don't need a separate trim with regexp_replace.
Best solution would be to validate and filter that kind of input before it even enters the database.
But as that is not the case, a solution that could work:
regexp_matches()

Trimming a part of string in sql needed for datatrieve

I have a column called notation in the correspondence table in our database. The values are as such for this column:
notation
SSQSUPER405575681 || 032-797 || 034828 1141289
SGQSUPER405575091 || 032-797 || 034828 1140802
SGQSUPER395729693 || 032-797 || 034828 1061943
I want to have this value only SSQSUPER405575681 or SGQSUPER405575091 for notation column and trim the rest part of the string such as || 032-797 || 034828 1141289 in the 1st row and || 032-797 || 034828 1140802 in 2nd row.
Please tell me how can i do that.
Well, Sybase functions are often pretty similar to T-SQL for SQL Server, so to extract the desired substrings out the notation column, try:
select
substring([notation], 1, patindex ('%||%',[notation]) - 1) as f1,
substring([notation],
patindex ('%||%',[notation]),
len([notation]) - patindex ('%||%',[notation]) ) as f2
from [correspondence]
If that doesn't work exactly, you might see if there is some variation in the way the Sybase functions work.

migrating carriage returns from oracle to sql server

I've been trying to migrate some carriage returns from an oracle varchar2 field to a sql server varchar field and it's not working at all.
I had working code in Oracle of the form:
'_Person making Contact__' ||chr(13) ||
which works perfectly fine in Oracle, but seems to get lost by the time SSIS has extracted the data to sql server.
I tried to pass the below:
'Name: ' || nvl2(p.surname || p.forename ,p.surname || ', ' || p.forename,'None Recorded') || 'char(13)' ||
'Organisation: ' || nvl(a.agency_name, 'None Recorded')
as ContactDetails
but the carriage returns end up embedded as text. e.g "Person making Contact___char(13)Name: None"
I've tried replacing the char (13) in various ways at the sqlserver end but cannot get the results to be anything other than char(13)s embedded in the text.
e.g
update mytable set [ContactDetails] = REPLACE(contactdetails,'char(13)',CHAR(13))
update mytable set [ContactDetails] = REPLACE(contactdetails,'char(13)',''' + CHAR(13) + ''' )
Things like "select myfield + char(13) + 'test text' give me the results I'm after so I can rule out really daft mistakes.
Can anyone offer any suggestions? At Oracle or sqlserver end is fine by me :)
don't know how this didn't work before but Jayvee has pointed me in the right direction. Re-tested this and it works now...
update mytable
set [ContactDetails] = REPLACE(contactdetails,'char(13)',CHAR(13))
Thanks all