check if integer value inside a string list with Firebird - sql

I am writing a stored procedure and I need to check if an integer variable value is inside a list.
I tried like this
If (var_int1 in (4,6,9) ) then ....
This work but the list of numbers will return to me from a varchar field so is there a way to still use IN and without using a temporary table.

You could use the builtin function position:
if(position(val IN valList) > 0)then
Note that you need to avoid false positives where only part of the number matches, ie given the values '123,456,789' position for '2' would return true which you probably don't want. To avoid that you could add comma (as you have comma separated values in the varchar field) as prefix and suffix to your search strings, ie
val = ',' || cast(var_int1 as varchar(10)) || ',';
valList = ',' || valList || ',';
if(position(val IN valList) > 0)then ...

Just to provide another possible solution:
valList = '2,3,4'; --- varchar
val = 3; --- integer
if ( valList like '%'||val||'%' ) then ...

Related

In SQL Server, how can I search for column with 1 or 2 whitespace characters?

So I need to filter column which contains either one, two or three whitespace character.
CREATE TABLE a
(
[col] [char](3) NULL,
)
and some inserts like
INSERT INTO a VALUES (' ',' ', ' ')
How do I get only the row with one white space?
Simply writing
SELECT *
FROM a
WHERE column = ' '
returns all rows irrespective of one or more whitespace character.
Is there a way to escape the space? Or search for specific number of whitespaces in column? Regex?
Use like clause - eg where column like '%[ ]%'
the brackets are important, like clauses provide a very limited version of regex. If its not enough, you can add a regex function written in C# to the DB and use that to check each row, but it won't be indexed and thus will be very slow.
The other alternative, if you need speed, is to look into full text search indexes.
Here is one approach you can take:
DECLARE #data table ( txt varchar(50), val varchar(50) );
INSERT INTO #data VALUES ( 'One Space', ' ' ), ( 'Two Spaces', ' ' ), ( 'Three Spaces', ' ' );
;WITH cte AS (
SELECT
txt,
DATALENGTH ( val ) - ( DATALENGTH ( REPLACE ( val, ' ', '' ) ) ) AS CharCount
FROM #data
)
SELECT * FROM cte WHERE CharCount = 1;
RETURNS
+-----------+-----------+
| txt | CharCount |
+-----------+-----------+
| One Space | 1 |
+-----------+-----------+
You need to use DATALENGTH as LEN ignores trailing blank spaces, but this is a method I have used before.
NOTE:
This example assumes the use of a varchar column.
Trailing spaces are often ignored in string comparisons in SQL Server. They are treated as significant on the LHS of the LIKE though.
To search for values that are exactly one space you can use
select *
from a
where ' ' LIKE col AND col = ' '
/*The second predicate is required in case col contains % or _ and for index seek*/
Note with your example table all the values will be padded out to three characters with trailing spaces anyway though. You would need a variable length datatype (varchar/nvarchar) to avoid this.
The advantage this has over checking value + DATALENGTH is that it is agnostic to how many bytes per character the string is using (dependant on datatype and collation)
DB Fiddle
How to get only rows with one space?
SELECT *
FROM a
WHERE col LIKE SPACE(1) AND col NOT LIKE SPACE(2)
;
Though this will only work for variable length datatypes.
Thanks guys for answering.
So I converted the char(3) column to varchar(3).
This seemed to work for me. It seems sql server has ansi padding that puts three while space in char(3) column for any empty or single space input. So any search or len or replace will take the padded value.

Query condition where a value is in a comma separated string

I have a table in which one of the table columns third_row stores a comma-separated list of numbers as a string but when its value is A then it means a combination of all the possible numbers. How do I approach this so that the query returns all the rows that have the third_row as A and the rest where third_row is equal to one of the values in the comma-separated string?
For reference, here is the format of the table:
first_row
second_row
third_row
0028001070200
50
A
0049048000701
51
01,04,02,31,
I have also tried this query but no luck:
SELECT
sds.scheme_code,
rs.scheme_name
FROM
trea.salary_deduction_schemes sds
LEFT JOIN
trea.receipt_schemes rs
ON sds.scheme_code = rs.scheme_code
WHERE sds.list_object_head = 'A'
OR 16 IN(regexp_split_to_table(sds.list_object_head, E','))
Your method almost works:
WHERE sds.list_object_head = 'A' OR
16 IN (SELECT val::int
FROM regexp_split_to_table(sds.list_object_head, E',') val
)
You can also use string matching:
WHERE ',' || sds.list_object_head || ',' LIKE '%,' || 16 || ',%'
Or you could convert to an array and use array operations.
I would strongly suggest that find a representation other than strings for storing integer values -- preferably another table or perhaps an array.
You can convert the list to an array and use the = any operator:
WHERE sds.list_object_head = 'A'
OR 16 = any(string_to_array(trim(',' from sds.list_object_head), ',')::int[])
The trim() is necessary to get rid of the trailing , that would result in an empty string after applying string_to_array() and that in turn would result in a casting error as an empty string isn't a valid integer.
This is probably a bit faster than using a regex and unnesting the array.

Snowflake : REGEXP replace with uppercase of capture group

I want to replace the very first letter after a comma(,) with uppercase of it in snowflake database. Below given is what I tried, but it did not work.
eg:
Apple,ball,cat --> Apple,Ball,Cat
Bulb,LED,tube --> Bulb,LED,Tube
SELECT REGEXP_REPLACE('Apple,ball,cat',',(\\\w)',UPPER('\\\1'));
,(\\\w) captures letters after the comma, but UPPER('\\\1') does not convert it to uppercase.
I am not sure if you can use functions inside REGEXP_REPLACE at all.
Please use the built-in INITCAP function
SELECT INITCAP('Apple,ball,cat', ',');
Reference: INITCAP
Or maybe like this:
SELECT LISTAGG(UPPER(LEFT(VALUE, 1)) || SUBSTRING(VALUE, 2, LEN(VALUE)), ',')
FROM TABLE(SPLIT_TO_TABLE('Apple,ball,cat', ',')) as t(val);
Not "regex", but if you're interested in a Javascript UDF to do what you need...
CREATE OR REPLACE FUNCTION fx_replaceInitOnly(
input varchar)
returns varchar
language javascript
as '
//logic from https://www.freecodecamp.org/news/how-to-capitalize-words-in-javascript/
var words = INPUT.split(",");
for (let i = 0; i < words.length; i++) {
words[i] = words[i][0].toUpperCase() + words[i].substr(1);
}
output = words.join(",");
return output;
';
SELECT
'Apple,ball,cat,Bulb,LED,Tube' as str,
fx_replaceInitOnly(str) as new,
case WHEN str <> new THEN 'Changed' ELSE 'Same' END as test;
--STR NEW TEST
--Apple,ball,cat,Bulb,LED,Tube Apple,Ball,Cat,Bulb,LED,Tube Changed
Regexp will not help you to upper your chars, so you may combine split_to_table and initcap:
SELECT LISTAGG( INITCAP(VALUE) ,',' )
FROM TABLE(SPLIT_TO_TABLE('Apple,ball,cat',','));

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()

SQL update a value within a string from another column

I have a column which contains a string within this string their is a GUID see below called voucherID, I would like to replace this GUID from another column on the same row.
<VoucherID>6c1c5c4f-3bab-4804-9a92-80b34f448cfe<VoucherID>
any help appreciated.
There are around 6000 rows.
IF on Oracle try
UPDATE YourTable T SET
T.YourXMLColumn = SUBSTR ( T.YourXMLColumn, 1, INSTR ( T.YourXMLColumn, '>' ) + 1 ) ||
T.YourValueColumn ||
SUBSTR ( T.YourXMLColumn, INSTR (T.YourXMLColumn, '<', -1 ) ) ;
Another option is just rebuilding the content with the new value
UPDATE YourTable T SET
T.YourXMLColumn = '<VoucherID>' ||
T.YourValueColumn ||
'</VoucherID>';
Why don't you select the value in the right colomn and then make an update ?
If you've a lot of switches to do you can use a loop, offcours it can be realy slow but it's the easier way, I think...