Changing value of a temporary table based on condition - sql

I am using amazon redshift and I need to change values for a column called 'codes' in a temporary table like below.
id code
--- ----
1 99990
2 A0002
3 0000F
I need to check if the first and last character is numeric , if they both are then change the column value based on its range (e.g set code = 'category1' when 90000 < code < 99999).
If the last character is an alphabet, then set the code based on the range of the first 4 characters (e.g set code = "category2" when 0 < code[:4] < 1000 )
What I have right now is :
UPDATE tmp_table
SET code = 'category1'
WHERE substring(code,1,1) ~ '[0-9]'
AND 90000 <= CONVERT(INT,code) <= 99999 ;
However I am getting error for code like 'A0002' , the error message is : Invalid operation, Invalid digit, Value 'A'.
I suspect the reason is when it fails the first condition , and inside the second condition, the convert function can not take in non-numeric value thus raising the error. But I am not sure how to fix this and get what I want.
Any suggestions ? Thanks

The order of evaluation of expressions is indeterminate. They can be evaluated in any order.
To fix this, use case:
UPDATE tmp_table
SET code = 'category1'
WHERE (CASE WHEN code ~ '[0-9]+'
THEN CONVERT(INT, code) BETWEEN 90000 AND 99999
END);
Or, forget the conversion and just use string logic:
WHERE CODE ~ '^9[0-9]{4}$'

Related

How to remove/replace hyphens in postgresql

I have this set of data that contains hyphens sign in my cell. My plan is to replace this hyphens sign to a number of 0 so that I can convert my column to numeric data type to do a calculation. The tricky part is where I only need to replace the cell that only contains hyphens sign (row 2 and row 3) without changing the negative value (row 6,7,8 and 9). I tried to use
regexp_replace("M1KW",'-','0','g')
function but it does change the negative value as well.
Any other special command that I can use ?
This is my sample data:
You seem to want to treat the string '-' as '0'. If so, you can directly replace the values:
update t
set mikw = '0'
where mikw = '-';
so that I can convert my column to numeric data type to do a calculation
You don't need to UPDATE all rows before being able to convert the data type to the correct one:
alter table the_table
alter mikw type numeric
using (case when mikw = '-' then 0 else mikw::numeric end);
That will do the "update" and the change of the data type in a single operation, rather than two.
Seems like the RIGHT function would be useful here, for isolating only instances where the hyphen is the last character.
Try this out:
UPDATE your_table
SET M1KW = 0
WHERE RIGHT(M1KW, 1) = '-';

Replace a range of values in an SQL table to a single value

I am trying to replace a range of values with a string. I know how to do it with the replace function but that, as far as I know, requires them to be done one at a time.
Is there a way to select a range of values, for example (1-200), and replace them with a singular string value say "BLANK"?
I have tried WHEN, THEN and SET but get a syntax error near WHEN or SET as I try these.
Base Code Idea
Select DATA
WHEN DATA >= 1 THEN 'BLANK'
WHEN DATA <200 THEN 'BLANK
END
FROM DATABANK
Thanks!
Is this what you want?
select data,
case when data not between 1 and 200 then data end as new_data
from databank
What this does is take the integer value of data, and replace any value that's in the 1-200 range with null values, while leaving other values unchanged. The result goes into column new_data.
The assumption here is that data is a number - so the alternative value has to be consistent with that datatype (string 'BLANK' isn't): I went for null, which is consistent with any datatype, and is the default value returned by a case expression when no branch matches.
If you wanted something else, say 0, you would do:
select data,
case when data between 1 and 200 then 0 else data end as new_data
from databank

How do I return a value if the string is between 6 and 10 characters in SQL?

I have a column of data where the length of each entry varies, e.g
12345678
123
AA
12345678912345
......
I wish to return value if the string length is between 6 and 10. If it's less than 6 or greater than 10, then return a blank.
In my example I would have one value 12345678 showing and three blanks.
You can use LEN function to test length of column value and CASE to return the value you want (supposing the column name is "field"):
SELECT CASE WHEN (LEN(field) >= 6 AND LEN(field) <= 10)
THEN field
ELSE '' END as 'YourField'
FROM nameoftable
To get it without the blanks you would do:
SELECT FIELD
FROM table_name
WHERE LEN(FIELD) >= 6 AND LEN(FIELD) <= 10
If you don't mind having the output for each row presented in a new column, you could do the following:
Assume the data you have is stored in "colA" in a table called "yourTable", then:
select case when len(colA) between 6 and 10 then colA else '' end as colB from yourTable
The syntax above will work in Microsoft SQL Server. You may have to tweak to find the equivalent length and comparison functions in whichever RDMS you happen to be using.
Another issue you may face is data type conversion issues. If your colA is defined as a character field, the code above should work without issue (i.e., you'll get blanks back for values outside of your test criteria). If colA is numeric, then using '' to insert a blank may actually return 0. It's up to you to decide how you want to handle this issue.

Prevent ORA-01722: invalid number in Oracle

I have this query
SELECT text
FROM book
WHERE lyrics IS NULL
AND MOD(TO_NUMBER(SUBSTR(text,18,16)),5) = 1
sometimes the string is something like this $OK$OK$OK$OK$OK$OK$OK, sometimes something like #P,351811040302663;E,101;D,07112018134733,07012018144712;G,4908611,50930248,207,990;M,79379;S,0;IO,3,0,0
if I would like to know if it is possible to prevent ORA-01722: invalid number, because is some causes the char in that position is not a number.
I run this query inside a procedure a process all the rows in a cursor, if 1 row is not a number I can't process any row
You could use VALIDATE_CONVERSION if it's Oracle 12c Release 2 (12.2),
WITH book(text) AS
(SELECT '#P,351811040302663;E,101;D,07112018134733,07012018144712;G,4908611,50930248,207,990;M,79379;S,0;IO,3,0,0'
FROM DUAL
UNION ALL SELECT '$OK$OK$OK$OK$OK$OK$OK'
FROM DUAL
UNION ALL SELECT '12I45678912B456781234567812345671'
FROM DUAL)
SELECT *
FROM book
WHERE CASE
WHEN VALIDATE_CONVERSION(SUBSTR(text,18,16) AS NUMBER) = 1
THEN MOD(TO_NUMBER(SUBSTR(text,18,16)),5)
ELSE 0
END = 1 ;
Output
TEXT
12I45678912B456781234567812345671
Assuming the condition should be true if and only if the 16-character substring starting at position 18 is made up of 16 digits, and the number is equal to 1 modulo 5, then you could write it like this:
...
where .....
and case when translate(substr(text, 18, 16), 'z0123456789', 'z') is null
and substr(text, 33, 1) in ('1', '6')
then 1 end
= 1
This will check that the substring is made up of all-digits: the translate() function will replace every occurrence of z in the string with itself, and every occurrence of 0, 1, ..., 9 with nothing (it will simply remove them). The odd-looking z is needed due to Oracle's odd implementation of NULL and empty strings (you can use any other character instead of z, but you need some character so no argument to translate() is NULL). Then - the substring is made up of all-digits if and only if the result of this translation is null (an empty string). And you still check to see if the last character is 1 or 6.
Note that I didn't use any regular expressions; this is important if you have a large amount of data, since standard string functions like translate() are much faster than regular expression functions. Also, everything is based on character data type - no math functions like mod(). (Same as in Thorsten's answer, which was only missing the first part of what I suggested here - checking to see that the entire substring is made up of digits.)
SELECT text
FROM book
WHERE lyrics IS NULL
AND case when regexp_like(SUBSTR(text,18,16),'^[^a-zA-Z]*$') then MOD(TO_NUMBER(SUBSTR(text,18,16)),5)
else null
end = 1;

Sql parse column as int and check if it is within range

I've used the top voted answer from here to check if a cell value is an integer. But I also need to do a range check on it.
SELECT * FROM Table
WHERE (dbo.IsInteger(FieldName) = 1) AND FieldName > 400 AND FieldName < 500
But this returns a conversion error, as some of the cells in the column contains text. So, is it possible to get a subset, that is only results from the IsInteger query, and then do a range check on the result?
You need to wrap it in a CASE expression. I've altered the query slightly to use BETWEEN to avoid having to repeat the expression.
SELECT * FROM Table
WHERE CASE WHEN dbo.IsInteger(FieldName) = 1
THEN FieldName END BETWEEN 401 AND 499
The result of the expression will be NULL when dbo.IsInteger(FieldName) <> 1 which will not match the BETWEEN predicate.
Of course this is completely unsargable but so is your original query.