How to translate regexp_replace from Oracle to Snowflake? - oracle

I'm migrating some queries from Oracle to Snowflake and I got stuck with regexp_replace(column, '\\W', null).
In Oracle it replaces empty strings with null and it removes some characters, i.e. 218.55 becomes 21855
In Snowflake it replaces every single value with null and I need it to do the same like in Oracle.
What is the equivalent function I can use in Snowflake?

So JNevill did most the work. But given it very much seems to be a concatenation problem, why not use the replace of empty string to get what seems like broken Oracle behavior (if you floats are all the same decimal places this is a indirect why to covert to fixed point). And then use NULLIF to convert empties to NULL
SELECT '*'||column1||'*' as input,
'*' || null || '*' as null_test,
'*'||regexp_replace(column1, '\\W', null)||'*' as reg_null,
'*'||regexp_replace(column1, '\\W', '')||'*' as reg_empty,
nullif(regexp_replace(column1, '\\W', ''),'') as nullif
FROM VALUES
('218.55'),
('');
gives:
INPUT
NULL_TEST
REG_NULL
REG_EMPTY
NULLIF
218.55
null
null
21855
21855
**
null
null
**
null
extra stars there so strings could be seen.

Related

Why is this check constraint not working when it checks length?

create table test
(
id varchar2(10) check( length(trim(id)) > 0),
primary key(id)
)
insert into test values (' '); -- this works
I expected this check constraint to stop this insert. But, it gets inserted none the less. Why ?
Problem is TRIM(' ') returns NULL and LENGTH(NULL) also gives NULL (not 0)
Try NVL(LENGTH(TRIM(' ')), 0) > 0 or
Try TRIM(ID) IS NOT NULL
Snippet stating that constraints can return null aka 'unknown' and considered to be NOT VIOLATING the constraint. Only a return of false violates a constraint. At least as per Oracle 12c
See Oracle Concept page about constraints
Explanation for what you saw:
If str is made up entirely of spaces, then trim(str) is the empty string.
Oracle treats the "empty string" the same as null (of varchar2 data type, when that matters), in flagrant violation of the SQL standard. Oracle is not even consistent in this - there are (very few) exceptions where the empty string is, in fact, seen as "empty string" (for example, in concatenations).
By definition, the length of null is null (in particular, not zero).
In SQL, a condition like null > 0 evaluates to unknown (in the three-valued logic needed to accommodate null in such conditions).
In check constraints unknown is treated the same as true. This is different from the treatment in other conditions (in SQL statements - in where clauses, join conditions etc.), where unknown is treated the same as false. This is documented, for example, here: https://docs.oracle.com/cd/B19306_01/server.102/b14200/clauses002.htm - see the first paragraph in the Check Constraints section.
The correct solution to your problem:
Checking if something is null should be done DIRECTLY, with the is null or is not null conditions. Don't use length for that.
Like this:
check( trim(id) is not null )

How to insert a blank value instead of NULL in Columns other than String datatype in hive

I have a create statement like
CREATE TABLE temp_tbl (EmpId String,Salary int);
I would like to insert an employee id and a blank value into table.
So What I have done is
insert overwrite table temp_tbl select '013' as EmpId,'' as Salary from tbl;
hive> select * from temp_tbl;
OK
013 NULL
But expected result is
hive> select * from temp_tbl;
OK
013 NULL ---> Blank instead of NULL
Also tried with "". Still I get it as NULL instead of blank
3.Tried to create table with serialization property
CREATE TABLE temp_tbl (EmpId String,Salary int) TBLPROPERTIES ('serialization.null.format' = '');
That too didn't change NULL value to blank.
What can be the workaround for the same.
Use Case while selecting the data.
Select
(CASE
WHEN columnName is null THEN ''
ELSE columnName
END) as 'Result' from temp_tbl;
All types except strings/varchar/char and some complex types like array, in Hive cannot be blank, only NULL is possible. Empty string '' is quite normal value of type String. You can produce empty array() as well (Array with zero size).
As a workaround, you can use some predefined values which are not normally in your data to represent some special numeric values, like -99999. Alternatively you can store your numeric values in a String column, in such case you will be able to have empty values in it. But it's not possible to assign (cast) empty strings to numeric types, because such empty value is not allowed.
If you try to assign empty string to numeric column or cast to numeric type, the result will be the same as if you are converting non-numeric string to numeric - NULL (in Hive if not possible to cast, it returns NULL) or get java.lang.NumberFormatException in Java.
Knowing that datatype Int can be either NULL or integer , I'd think of how to work around the problem.
I have the impression that 0 can do the job. Why can it not?
If 1 is not ideal, why not create a new temp_employees_with_no_salary table?
If 2 is not ideal, can you afford to change the datatype of temp_tbl.Salary from Int to String, then use CAST(Salary AS INT) to work with it?

SQLDeveloper query automatic padding CHAR field

Given the table ATABLE with a field AFIELD of type CHAR(8), and where i have a field with value "1234567 "
Why, in SQL Developer, if I query:
SELECT * FROM ATABLE WHERE AFIELD = '1234567';
It will automatically pad the missing space and return the results, and if I query with :
SELECT * FROM ATABLE WHERE AFIELD = :value;
and input the value, it wont ?
From the documentation:
Within expressions and conditions, Oracle treats text literals as though they have the data type CHAR by comparing them using blank-padded comparison semantics.
When you do WHERE AFIELD = '1234567' the text literal '1234567' is treated as char and blank-padded comparison semantics are used to compare the column value and the literal. Even though the literal doesn't have the trailing space, those semantics see them as the same, so it finds a match.
When you use a bind variable the literal you assign to it is a char, but the bind variable itself is varchar2 - even if you declare it as char, oddly, though in that case the value is blank-padded anyway:
var char_value char(8);
exec :char_value := '1234567';
var varchar2_value varchar2(8);
exec :varchar2_value := '1234567';
select dump('1234567') as d1, dump(:char_value) as d2, dump(:varchar2_value) as d3
from dual;
D1 D2 D3
------------------------------------ ------------------------------------ ------------------------------------
Typ=96 Len=7: 49,50,51,52,53,54,55 Typ=1 Len=8: 49,50,51,52,53,54,55,32 Typ=1 Len=7: 49,50,51,52,53,54,55
The text literal is data type 96 (char), while both bind variables are type 1 (varchar/varchar2); but notice the char_value bind variable has the trailing space, with length 8 and the last character as code point 32.
When you compare your char column value with a varchar2 bind variable the column value is implicitly converted from char to varchar2:
The following rules govern implicit data type conversions:
During SELECT FROM operations, Oracle converts the data from the column to the type of the target variable.
So your space-padded char(8) column value is implicitly converted to varchar2(8) to match the bind variable's data type, and then because they are varchar2 the nonpadded comparison semantics are used.
When you compare your char(8) column with the supposedly-char(8) bind variable, you're actually comparing with a padded varchar2(8) - but both the implicitly converted column value and the blank-padded bind variable are actually the same, both with the trailing space; '1234567 ' is the same as '1234567 ', so there is a match, even with nonpadded comparison semantics.
With the varchar2(8) bind variable the same thing happens, but now the bound value is not padded, and as you are using nonpadded comparison semantics to compare '1234567 ' with '1234567' - they are not the same, so there is no match, and no data is returned by the query.
As #a_horse_with_no_name said you should almost always use varchar2 rather than char. But if you must use it and are stuck with it then at least make sure you use the same data type for comparisons.
You are right
SELECT * FROM ATABLE WHERE AFIELD = :value;
does not work with CHAR as you desire.
Anyway I have noticed that the following query works as you desire:
SELECT * FROM ATABLE WHERE AFIELD = &value;
If you use &value in several places, you can use &&value (double &) the first time (and &value elsewhere),
in order to avoid to input the same value several times;
when you have to change that value, you can undefine it with:
undef value;

Trigger not executing correctly in Oracle PL/SQL

I have a trigger which executes on AFTER UPDATE. It doesn't work as i want it to.
How would i check if a value has changed on a field which is of nullable type? I have the following fields which are of nullable type:
FRM_DATE DATE
FRM_TIME DATE
THE_DATE DATE
THE_TIME NUMBER(4,2)
THE_BOOL NUMBER(2)
I would like to execute a set of logic only if the value for the above fields have actually changed. If the values are the same then i do not want to code to execute. So from the UI, lets say if one of the fields had a value and the user removes it(it now becomes NULL) and hits submit button, i want my logic to execute because a change has been made.
I tried the following but it doesn't execute the logic i want:
IF (nvl(:old.FRM_DATE, '') <> nvl(:new.FRM_DATE,'')) THEN
--My logic
END IF;
I also tried
IF (nvl(:old.FRM_DATE, NULL) <> nvl(:new.FRM_DATE,NULL)) THEN
--My logic
END IF;
Any ideas?
Kind Regards,
In Oracle, null and the empty string '' are effectively equivalent:
Oracle Database currently treats a character value with a length of zero as null. However, this may not continue to be true in future releases, and Oracle recommends that you do not treat empty strings the same as nulls.
... so the two checks are really the same. In both cases you're doing nvl(something, null), which doesn't make much sense - you're saying "if the value is null then make it null", which is redundant and doesn't do any real transformation. So if either the old or new value is null you're still trying to compare null with either itself or a non-null value; and as San said, you can't compare null with anything using equality conditions.
You could use a magic value, again as San shows, but you have to be sure that can never actually appear in the data. It may be safer, and make the intent clearer, if you explicitly check with is null:
IF (:old.FRM_DATE IS NULL AND :new.FRM_DATE IS NOT NULL)
OR (:old.FRM_DATE IS NOT NULL AND :new.FRM_DATE IS NULL)
OR :old.FRM_DATE != :new.FRM_DATE
THEN
...
You cannot compare null with null or null with any other value, change the logic to:
IF (nvl(:old.FRM_DATE, to_date('01-01-1900', 'dd-mm-yyyy')) <> nvl(:new.FRM_DATE,to_date('01-01-1900', 'dd-mm-yyyy'))) THEN
--My logic
END IF;
Just in case, additional recommendations. Check type of trigger you use?
I mean, row trigger or statement trigger.
You can also see an example of a trigger on the column:
Oracle SQL trigger on update of column
While it is true that Oracle considers (for the time being) an empty string and NULL to be equivalent, the nice people at Oracle have provided us with an easy way to catch a change -- but it may not be what you want.
The updating system function returns true if the column appears on the left side of the "=" in the set clause. So
update table1
set col1 = null,
col2 = 42
where ...;
Within the update trigger, updating( 'col1' ) and updating( 'col2' ) will both return true. But they will return true even if col1 started out with a null value (or '') or col2 was already 42.
So it would appear you have two options: either you can, like Oracle, consider NULL and '' to be equivalent and don't flag them as a change, or you can flag any attempt to make a change in the field even if it turns out the same value was actually being rewritten to the field.
Unless there is an objective business requirement mandating one over the other, it really doesn't matter which way you (or whoever makes these decisions) choose, as long as you publicize the behavior to everyone who needs to know.

How do I find out which columns and rows contain Extended ASCII codes?

Can any one help How to find out which columns and rows has Extended ASCII Codes in the table (EX:-Ž,™,Ù)?
Examples
jacob\Û
=pal®
I need query some thing like Select * from table to get Extended ASCII
Thanks For help
You can try with:
SELECT *
FROM mytable
WHERE mycolumn<>CONVERT(mycolumn, 'US7ASCII');
You can use TRANSLATE to remove all valid characters from the string, so only the special characters remain. Then check for NULL (as an empty string is NULL in Oracle; don't use length, for the length will not be 0 as one would expect but null):
select name
from mytable
where TRANSLATE(name, '®ABCDEFG...abc...', '®') is not null;
You will have to put all valid characters in the string where I simply put '...'.
I used one special character to replace itself as you see, because otherwise the replacement string had to be empty, but empty means null in Oracle and translate doesn't work with null.
(Yes, that empty string is null thing in Oracle is really a nuisance.)

Resources