Sybase/SAP ASE T-SQL: Why ltrim() and rtrim() native functions return null when evaluaten for empty and only-spaces strings? - sap-ase

I noted an (for me) unexpected behavior on ltrim() and rtrim() functions on Sybase ASE T-SQL engines. The weird behavior I observed occurs on ltrim() and rtrim() functions for empty and only-spaces strings arguments; they return NULL. I consider this behavior weird because one (or me at least) expect ltrim() and rtrim() string functions just remove starting and ending spaces; not to turn a not-null value (as empty and only-spaces strings) to NULL
To reproduce the issue, I wrote the script below. Knowing that using of the = operator against null isn't a good practice, I just included those examples for educative purposes
begin
create table #tmpSomeTable (
rowId int not null,
someStringColumn varchar(10) null
)
insert into #tmpSomeTable(someStringColumn,rowId) values (null,1)
insert into #tmpSomeTable(someStringColumn,rowId) values ('',2)
insert into #tmpSomeTable(someStringColumn,rowId) values (' ',3)
insert into #tmpSomeTable(someStringColumn,rowId) values (' ',4)
--
select '=null predicate' as [predicate]
,*
from #tmpSomeTable
where someStringColumn = null
select 'is null predicate' as [predicate]
,*
from #tmpSomeTable
where someStringColumn is null
--ltrim() when evaluated for empty string from rowId=2 row returns null
select '=null predicate' as [predicate]
,*
from #tmpSomeTable
where ltrim(someStringColumn) = null
select 'is null predicate' as [predicate]
,*
from #tmpSomeTable
where ltrim(someStringColumn) is null
--rtrim() when evaluated for empty string from rowId=2 row returns null
select '=null predicate' as [predicate]
,*
from #tmpSomeTable
where rtrim(someStringColumn) = null
select 'is null predicate' as [predicate]
,*
from #tmpSomeTable
where rtrim(someStringColumn) = null
drop table #tmpSomeTable
end
My questions about this are ¿Why ltrim() and rtrim() native functions return null when evaluated for empty and only-spaces strings on Sybase ASE Database Engine? ¿Is that an expected behavior? ¿Is that a non-deterministic behavior defined by database instance parameters? Is that a Bug or Known-issue?

Related

Inserting Python Dict to MariaDB giving Error 1064

Having a dict of structured_files variable as below;
structured_files = {'158795_1635509614542_20211029151335135_27.1943_38.4319.jpg': ['158795', '1635509614542', '20211029151335135', '27.1943', '38.4319'], '2773170_1635255851988_20211026164412576_27.1836_38.4777.jpg': ['2773170', '1635255851988', '20211026164412576', '27.1836', '38.4777'], '2777171_1635330525915_20211027132846547_27.1875_38.4720.jpg': ['2777171', '1635330525915', '20211027132846547', '27.1875', '38.4720'], '2779392_1635150026780_20211025112027410_27.1627_38.4724.jpg': ['2779392', '1635150026780', '20211025112027410', '27.1627', '38.4724'], '3724797_1634893471399_20211022120432057_27.1334_38.5426.jpg': ['3724797', '1634893471399', '20211022120432057', '27.1334', '38.5426'], '5218186_1635161250087_20211025142730572_27.0694_38.4943.jpg': ['5218186', '1635161250087', '20211025142730572', '27.0694', '38.4943'], '5347212_1634987405913_20211023141006566_27.0454_38.5138.jpg': ['5347212', '1634987405913', '20211023141006566', '27.0454', '38.5138'], '8174846_1635335281021_20211027144801672_27.1039_38.3572.jpg': ['8174846', '1635335281021', '20211027144801672', '27.1039', '38.3572'], '9179383_1635321573332_20211027105933968_27.1251_38.3576.jpg': ['9179383', '1635321573332', '20211027105933968', '27.1251', '38.3576']}
Trying to insert in to mysql db code is follows;
For Creation;
Qcreate1 = "CREATE TABLE data_11 (id_key LONGTEXT NOT NULL, name VARCHAR(50) NOT NULL, date VARCHAR(50) NOT NULL, sample VARCHAR(50) NOT NULL, coord_y VARCHAR(50) NOT NULL, coord_x VARCHAR(50) NOT NULL, created datetime NOT NULL, key_id int PRIMARY KEY NOT NULL AUTO_INCREMENT )"
For Inserting;
cols = list(structured_files.keys())
vals = list(structured_files.values())
Q1 = f"INSERT INTO data_11 {cols} values {vals}"
mycursor.execute(Q1)
It gives the error : mysql.connector.errors.ProgrammingError: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '['158795_1635509614542_20211029151335135_27.1943_38.4319.jpg', '2773170_16352...' at line 1
Why is that ?
Okay, I tested this code to do what you want:
Q1 = "INSERT INTO data_11 (id_key, name, date, sample, coord_y, coord_x) VALUES (%s, %s, %s, %s, %s, %s)"
for id_key, values in structured_files.items():
cursor.execute(Q1, [id_key] + values)
cnx.commit()
Tips:
Write the column names explicitly in the INSERT statement. Learn the syntax for INSERT:
INSERT INTO <table> (<columns>) VALUES (<values>)
Your id_key, the key in the dict, isn't a column name. It's one of the values, so it belongs in the VALUES clause.
This is the syntax for inserting one row. Once you get used to this, you can explore multi-row INSERT syntax.
Don't use f-strings to interpolate variables into the INSERT string, because that risks SQL injection flaws. Leave the values as placeholders as I showed, then pass the values separately as a list in the second argument to cursor.execute().

Replace One character in string with multiple characters in loop - ORACLE

I have a situation where say a string has one replaceable character.. For ex..
Thi[$] is a strin[$] I am [$]ew to Or[$]cle
Now I need to replace the [$] with s,g,n,a
Respectively...
How can I do that? Please help.
There is a special PL/SQL function UTL_LMS.FORMAT_MESSAGE:
You can use use it in your INLINE pl/sql function:
with function format(
str in varchar2
,s1 in varchar2 default null
,s2 in varchar2 default null
,s3 in varchar2 default null
,s4 in varchar2 default null
,s5 in varchar2 default null
,s6 in varchar2 default null
,s7 in varchar2 default null
,s8 in varchar2 default null
,s9 in varchar2 default null
,s10 in varchar2 default null
) return varchar2
as
begin
return utl_lms.format_message(replace(str,'[$]','%s'),s1,s2,s3,s4,s5,s6,s7,s8,s9,10);
end;
select format('Thi[$] is a strin[$] I am [$]ew to Or[$]cle', 's','g','n','a') as res
from dual;
Result:
RES
-------------------------------------
This is a string I am new to Oracle
Here is a hand-rolled solution using a recursive WITH clause, and INSTR and SUBSTR functions to chop the string and inject the relevant letter at each juncture.
with rcte(str, sigils, occ) as (
select 'Thi[$] is a strin[$] I am [$]ew to Or[$]cle' as str
, 'sgna' as sigils
, 0 as occ
from dual
union all
select substr(str, 1, instr(str,'[$]',1,1)-1)||substr(sigils, occ+1, 1)||substr(str, instr(str,'[$]',1,1)+3) as str
, sigils
, occ+1 as occ
from rcte
where occ <= length(sigils)
)
select *
from rcte
where occ = length(sigils)
Here is a working demo on db<>fiddle.
However, it looks like #sayanm has provided a neater solution.
Consider this method that lets the lookup values be table-based. See the comments within. The original string is split into rows using the placeholder as a delimiter. Then the rows are put back together using listagg, joining on it's order to the lookup table.
Table-driven using as many placeholders as you want. The order matters though of course just as with the other answers.
-- First CTE just sets up source data
WITH tbl(str) AS (
SELECT 'Thi[$] is a strin[$] I am [$]ew to Or[$]cle' FROM dual
),
-- Lookup table. Does not have to be a CTE here, but a normal table
-- in the database.
tbl_sub_values(ID, VALUE) AS (
SELECT 1, 's' FROM dual UNION ALL
SELECT 2, 'g' FROM dual UNION ALL
SELECT 3, 'n' FROM dual UNION ALL
SELECT 4, 'a' FROM dual
),
-- Split the source data using the placeholder as a delimiter
tbl_split(piece_id, str) AS (
SELECT LEVEL AS piece_id, REGEXP_SUBSTR(t.str, '(.*?)(\[\$\]|$)', 1, LEVEL, NULL, 1)
FROM tbl T
CONNECT BY LEVEL <= REGEXP_COUNT(t.str, '[$]') + 1
)
-- select * from tbl_split;
-- Put the string back together, joining with the lookup table
SELECT LISTAGG(str||tsv.value) WITHIN GROUP (ORDER BY piece_id) STRING
FROM tbl_split ts
LEFT JOIN tbl_sub_values tsv
ON ts.piece_id = tsv.id;
STRING
--------------------------------------------------------------------------------
This is a string I am new to Oracle

Azure Data Factory 2, Data flow with derived column, how to set a timestamp to null

I have a Azure DataFactory V2 pipeline that executes a data flow.
The Azure Sql source table have a Date not null column, DateReported.
This is imported from an external source. Where null values are
1899-01-01.
The destination Sql table have the same field, DateReported but as Date null
I'm using a Derived Column in my dataflow to sanitize data.
I want to insert null when the date is 1899-01-01
My derived column function is this
iif(!(year(DateReported) == 1899 || year(DateReported) == 1753)
, DateReported
, null()
)
This give me the error "Expression should return the same type 'timestamp' as previous expressions".
If I invert the iif to this
iif((year(DateReported) == 1899 || year(DateReported) == 1753)
, null()
, DateReported
)
I get the error "Expression should return the same type 'null' as previous expressions"
I can fix this in sql from the source like this
Select ...
DateReported2 =
CASE
WHEN DateReported is null THEN DateReported
WHEN YEAR(DateReported) = 1899 THEN NULL
ELSE DateReported
End
...
But this is messy, as all my other logic are in the dataflow.
How can I create a derived column that is a nullable timestamp, like C# DateTime? or SSIS NULL(DT_DATE)?
Solution:
case(year(DateReported) != 1899, DateReported)

Checking if key exists in Presto value map

I am new to Presto, and can't quite figure out how to check if a key is present in a map. When I run a SELECT query, this error message is returned:
Key not present in map: element
SELECT value_map['element'] FROM
mytable
WHERE name = 'foobar'
Adding AND contains(value_map, 'element') does not work
The data type is a string array
SELECT typeof('value_map') FROM mytable
returns varchar(9)
How would I only select records where 'element' is present in the value_map?
You can lookup a value in a map if the key is present with element_at, like this:
SELECT element_at(value_map, 'element')
FROM ...
WHERE element_at(value_map, 'element') IS NOT NULL
element_at is ambiguous in that case -- it'll return NULL when either there's no such key or the key does exist and has NULL associated with it. A guaranteed approach is contains(map_keys(my_map), 'mykey'), which admittedly should be a bit slower than the original variant.

Transformation logic in hive / spark

How can we write a Hive query in select statement for the logic below ?
If a column value is null then it should return ' '
If trim(column) is null then it should return ' '
Else it should populate the value of that column.
I guess this can be implemented using case when approach.
How to implement in a Hive query?
I think you want:
select coalesce(trim(column), '')
Note that trim() doesn't take a second argument in Hive. Also, trim() doesn't return NULL unless the argument is NULL; it returns an empty string.

Resources