Snowflake : REGEXP replace with uppercase of capture group - sql

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',','));

Related

Extract number from string with Oracle function

I need to create an Oracle DB function that takes a string as parameter. The string contains letters and numbers. I need to extract all the numbers from this string. For example, if I have a string like RO1234, I need to be able to use a function, say extract_number('RO1234'), and the result would be 1234.
To be even more precise, this is the kind of SQL query which this function would be used in.
SELECT DISTINCT column_name, extract_number(column_name)
FROM table_name
WHERE extract_number(column_name) = 1234;
QUESTION: How do I add a function like that to my Oracle database, in order to be able to use it like in the example above, using any of Oracle SQL Developer or SQLTools client applications?
You'd use REGEXP_REPLACE in order to remove all non-digit characters from a string:
select regexp_replace(column_name, '[^0-9]', '')
from mytable;
or
select regexp_replace(column_name, '[^[:digit:]]', '')
from mytable;
Of course you can write a function extract_number. It seems a bit like overkill though, to write a funtion that consists of only one function call itself.
create function extract_number(in_number varchar2) return varchar2 is
begin
return regexp_replace(in_number, '[^[:digit:]]', '');
end;
You can use regular expressions for extracting the number from string. Lets check it. Suppose this is the string mixing text and numbers 'stack12345overflow569'. This one should work:
select regexp_replace('stack12345overflow569', '[[:alpha:]]|_') as numbers from dual;
which will return "12345569".
also you can use this one:
select regexp_replace('stack12345overflow569', '[^0-9]', '') as numbers,
regexp_replace('Stack12345OverFlow569', '[^a-z and ^A-Z]', '') as characters
from dual
which will return "12345569" for numbers and "StackOverFlow" for characters.
This works for me, I only need first numbers in string:
TO_NUMBER(regexp_substr(h.HIST_OBSE, '\.*[[:digit:]]+\.*[[:digit:]]*'))
the field had the following string: "(43 Paginas) REGLAS DE PARTICIPACION".
result field: 43
If you are looking for 1st Number with decimal as string has correct decimal places, you may try regexp_substr function like this:
regexp_substr('stack12.345overflow', '\.*[[:digit:]]+\.*[[:digit:]]*')
To extract charecters from a string
SELECT REGEXP_REPLACE(column_name,'[^[:alpha:]]') alpha FROM DUAL
In order to extract month and a year from a string 'A0807' I did the following in PL/SQL:
DECLARE
lv_promo_code VARCHAR2(10) := 'A0807X';
lv_promo_num VARCHAR2(5);
lv_promo_month NUMBER(4);
lv_promo_year NUMBER(4);
BEGIN
lv_promo_num := REGEXP_SUBSTR(lv_promo_code, '(\d)(\d)(\d)(\d)');
lv_promo_month := EXTRACT(month from to_date(lv_promo_num, 'MMYY'));
DBMS_OUTPUT.PUT_LINE(lv_promo_month);
lv_promo_year := EXTRACT(year from to_date(lv_promo_num, 'MMYY'));
DBMS_OUTPUT.PUT_LINE(lv_promo_year);
END;

How to search for all names with an apostrophe by using the INSTR function in ORACLE?

I cannot figure out how to do this. I have looked through my book on oracle SQL and it has nothing of sort about this function. I am not sure if my instructor did not mean to ask this question or if there is a way to do it.
INSTR
The INSTR functions search string for substring. The function returns
an integer indicating the position of the character in string that is
the first character of this occurrence.
Note: If substring is not found in string, then the INSTR function will return 0.
SELECT *
FROM your_table
WHERE INSTR(name, '''') > 0;
SQLFiddleDemo
You can also perform
SELECT *
FROM your_table
WHERE INSTR(name, q'!'!') > 0;
I think you mean single quote. You can do like
select column_name
from table1
where INSTR(your_column, '''') > 0;

Best way to parse and concatenate a string with SQL

I'm trying to turn object_type,ABC,00,DEF,XY string into ABC-00-DEF-XY-
Here's what I've got, I'm wondering if there is a more efficient way?
CONCAT(
REPLACE(
SUBSTR(a.object_name,
INSTR(a.object_name, ',',1,1)+1,
INSTR(a.object_name, ',',1,2)+1
),',','-'
),'-'
)
Clarification: I need to strip off everything up to and including the first comma, replace all remaining commas with dashes, and then add a dash onto the end.
Try this
replace(substr(a.object_name,instr(a.object_name,',',1,1) + 1),',','-') ||'-'
Rexexp_replace() regular expression function can come in handy in this situation as well:
select ltrim(
regexp_replace( col
, '([^,]+)|,([^,]+)', '\2-'
)
, '-'
) as res
from t1
Result:
RES
--------------
ABC-00-DEF-XY-
SQLFiddle Demo
I suggest using the following code:
REPLACE(SUBSTRING(a.object_name,13,LEN(#object_name)-11),',','-') + '-'

Parameters in query with in clause?

I want to use parameter for query like this :
SELECT * FROM MATABLE
WHERE MT_ID IN (368134, 181956)
so I think about this
SELECT * FROM MATABLE
WHERE MT_ID IN (:MYPARAM)
but it doesn't work...
Is there a way to do this ?
I actually use IBX and Firebird 2.1
I don't know how many parameters in IN clause.
For whom ever is still interested. I did it in Firebird 2.5 using another stored procedure inspired by this post.
How to split comma separated string inside stored procedure?
CREATE OR ALTER PROCEDURE SPLIT_STRING (
ainput varchar(8192))
RETURNS (
result varchar(255))
AS
DECLARE variable lastpos integer;
DECLARE variable nextpos integer;
DECLARE variable tempstr varchar(8192);
BEGIN
AINPUT = :AINPUT || ',';
LASTPOS = 1;
NEXTPOS = position(',', :AINPUT, LASTPOS);
WHILE (:NEXTPOS > 1) do
BEGIN
TEMPSTR = substring(:AINPUT from :LASTPOS for :NEXTPOS - :LASTPOS);
RESULT = :TEMPSTR;
LASTPOS = :NEXTPOS + 1;
NEXTPOS = position(',', :AINPUT, LASTPOS);
suspend;
END
END
When you pass the SP the following list
CommaSeperatedList = 1,2,3,4
and call
SELECT * FROM SPLIT_STRING(:CommaSeperatedList)
the result will be :
RESULT
1
2
3
4
And can be used as follows:
SELECT * FROM MyTable where MyKeyField in ( SELECT * FROM SPLIT_STRING(:CommaSeperatedList) )
I ended up using a global temporary table in Firebird, inserting parameter values first and to retrieve results I use a regular JOIN instead of a WHERE ... IN clause. The temporary table is transaction-specific and cleared on commit (ON COMMIT DELETE ROWS).
Maybe you should wite it like this:
SELECT * FROM MATABLE
WHERE MT_ID IN (:MYPARAM1 , :MYPARAM2)
I don't think it's something that can be done. Are there any particular reason why you don't want to build the query yourself?
I've used this method a couple of times, it doesn't use parameters though. It uses a stringlist and it's property DelimitedText. You create a IDList and populate it with your IDs.
Query.SQL.Add(Format('MT_ID IN (%s)', [IDList.DelimitedText]));
You might also be interested in reading the following:
http://www.sommarskog.se/dynamic_sql.html
and
http://www.sommarskog.se/arrays-in-sql-2005.html
Covers dynamic sql with 'in' clauses and all sorts. Very interesting.
Parameters are placeholders for single values, that means that an IN clause, that accepts a comma delimited list of values, cannot be used with parameters.
Think of it this way: wherever I place a value, I can use a parameter.
So, in a clause like: IN (:param)
I can bind the variable to a value, but only 1 value, eg: IN (4)
Now, if you consider an "IN clause value expression", you get a string of values: IN (1, 4, 6) -> that's 3 values with commas between them. That's part of the SQL string, not part of a value, which is why it cannot be bound by a parameter.
Obviously, this is not what you want, but it's the only thing possible with parameters.
The answer from Yurish is a solution in two out of three cases:
if you have a limited number of items to be added to your in clause
or, if you are willing to create parameters on the fly for each needed element (you don't know the number of elements in design time)
But if you want to have arbitrary number of elements, and sometimes no elements at all, then you can generate SLQ statement on the fly. Using format helps.
SELECT * FROM MATABLE
WHERE MT_ID IN (:MYPARAM) instead of using MYPARAM with :, use parameter name.
like SELECT * FROM MATABLE
WHERE MT_ID IN (SELECT REGEXP_SUBSTR(**MYPARAM,'[^,]+', 1, LEVEL)
FROM DUAL
CONNECT BY REGEXP_SUBSTR(MYPARAM, '[^,]+', 1, LEVEL) IS NOT NULL))**
MYPARAM- '368134,181956'
If you are using Oracle, then you should definitely check out Tom Kyte's blog post on exactly this subject (link).
Following Mr Kyte's lead, here is an example:
SELECT *
FROM MATABLE
WHERE MT_ID IN
(SELECT TRIM(substr(text, instr(text, sep, 1, LEVEL) + 1,
instr(text, sep, 1, LEVEL + 1) -
instr(text, sep, 1, LEVEL) - 1)) AS token
FROM (SELECT sep, sep || :myparam || sep AS text
FROM (SELECT ',' AS sep
FROM dual))
CONNECT BY LEVEL <= length(text) - length(REPLACE(text, sep, '')) - 1)
Where you would bind :MYPARAM to '368134,181956' in your case.
Here is a technique I have used in the past to get around that 'IN' statement problem. It builds an 'OR' list based on the amount of values specified with parameters (unique). Then all I had to do was add the parameters in the order they appeared in the supplied value list.
var
FilterValues: TStringList;
i: Integer;
FilterList: String;
Values: String;
FieldName: String;
begin
Query.SQL.Text := 'SELECT * FROM table WHERE '; // set base sql
FieldName := 'some_id'; // field to filter on
Values := '1,4,97'; // list of supplied values in delimited format
FilterList := '';
FilterValues := TStringList.Create; // will get the supplied values so we can loop
try
FilterValues.CommaText := Values;
for i := 0 to FilterValues.Count - 1 do
begin
if FilterList = '' then
FilterList := Format('%s=:param%u', [FieldName, i]) // build the filter list
else
FilterList := Format('%s OR %s=:param%u', [FilterList, FieldName, i]); // and an OR
end;
Query.SQL.Text := Query.SQL.Text + FilterList; // append the OR list to the base sql
// ShowMessage(FilterList); // see what the list looks like.
if Query.ParamCount <> FilterValues.Count then
raise Exception.Create('Param count and Value count differs.'); // check to make sure the supplied values have parameters built for them
for i := 0 to FilterValues.Count - 1 do
begin
Query.Params[i].Value := FilterValues[i]; // now add the values
end;
Query.Open;
finally
FilterValues.Free;
end;
Hope this helps.
There is one trick to use reversed SQL LIKE condition.
You pass the list as string (VARCHAR) parameter like '~12~23~46~567~'
Then u have query like
where ... :List_Param LIKE ('%~' || CAST( NumField AS VARCHAR(20)) || '~%')
CREATE PROCEDURE TRY_LIST (PARAM_LIST VARCHAR(255)) RETURNS (FIELD1....)
AS
BEGIN
/* Check if :PARAM_LIST begins with colon "," and ands with colon ","
the list should look like this --> eg. **",1,3,4,66,778,33,"**
if the format of list is right then GO if not just add then colons
*/
IF (NOT SUBSTRING(:PARAM_LIST FROM 1 FOR 1)=',') THEN PARAM_LIST=','||PARAM_LIST;
IF (NOT SUBSTRING(:PARAM_LIST FROM CHAR_LENGTH(:PARAM_LIST) FOR 1)=',') THEN PARAM_LIST=PARAM_LIST||',';
/* Now you are shure thet :PARAM_LIST format is correct */
/ * NOW ! */
FOR SELECT * FROM MY_TABLE WHERE POSITION(','||MY_FIELD||',' in :PARAM_LIST)>0
INTO :FIELD1, :FIELD2 etc... DO
BEGIN
SUSPEND;
END
END
How to use it.
SELECT * FROM TRY_LIST('3,4,544,87,66,23')
or SELECT * FROM TRY_LIST(',3,4,544,87,66,23,')
if the list have to be longer then 255 characters then just change the part of header f.eg. like PARAM_LIST VARCHAR(4000)

How can I remove leading and trailing quotes in SQL Server?

I have a table in a SQL Server database with an NTEXT column. This column may contain data that is enclosed with double quotes. When I query for this column, I want to remove these leading and trailing quotes.
For example:
"this is a test message"
should become
this is a test message
I know of the LTRIM and RTRIM functions but these workl only for spaces. Any suggestions on which functions I can use to achieve this.
I have just tested this code in MS SQL 2008 and validated it.
Remove left-most quote:
UPDATE MyTable
SET FieldName = SUBSTRING(FieldName, 2, LEN(FieldName))
WHERE LEFT(FieldName, 1) = '"'
Remove right-most quote: (Revised to avoid error from implicit type conversion to int)
UPDATE MyTable
SET FieldName = SUBSTRING(FieldName, 1, LEN(FieldName)-1)
WHERE RIGHT(FieldName, 1) = '"'
I thought this is a simpler script if you want to remove all quotes
UPDATE Table_Name
SET col_name = REPLACE(col_name, '"', '')
You can simply use the "Replace" function in SQL Server.
like this ::
select REPLACE('this is a test message','"','')
note: second parameter here is "double quotes" inside two single quotes and third parameter is simply a combination of two single quotes. The idea here is to replace the double quotes with a blank.
Very simple and easy to execute !
My solution is to use the difference in the the column values length compared the same column length but with the double quotes replaced with spaces and trimmed in order to calculate the start and length values as parameters in a SUBSTRING function.
The advantage of doing it this way is that you can remove any leading or trailing character even if it occurs multiple times whilst leaving any characters that are contained within the text.
Here is my answer with some test data:
SELECT
x AS before
,SUBSTRING(x
,LEN(x) - (LEN(LTRIM(REPLACE(x, '"', ' ')) + '|') - 1) + 1 --start_pos
,LEN(LTRIM(REPLACE(x, '"', ' '))) --length
) AS after
FROM
(
SELECT 'test' AS x UNION ALL
SELECT '"' AS x UNION ALL
SELECT '"test' AS x UNION ALL
SELECT 'test"' AS x UNION ALL
SELECT '"test"' AS x UNION ALL
SELECT '""test' AS x UNION ALL
SELECT 'test""' AS x UNION ALL
SELECT '""test""' AS x UNION ALL
SELECT '"te"st"' AS x UNION ALL
SELECT 'te"st' AS x
) a
Which produces the following results:
before after
-----------------
test test
"
"test test
test" test
"test" test
""test test
test"" test
""test"" test
"te"st" te"st
te"st te"st
One thing to note that when getting the length I only need to use LTRIM and not LTRIM and RTRIM combined, this is because the LEN function does not count trailing spaces.
I know this is an older question post, but my daughter came to me with the question, and referenced this page as having possible answers. Given that she's hunting an answer for this, it's a safe assumption others might still be as well.
All are great approaches, and as with everything there's about as many way to skin a cat as there are cats to skin.
If you're looking for a left trim and a right trim of a character or string, and your trailing character/string is uniform in length, here's my suggestion:
SELECT SUBSTRING(ColName,VAR, LEN(ColName)-VAR)
Or in this question...
SELECT SUBSTRING('"this is a test message"',2, LEN('"this is a test message"')-2)
With this, you simply adjust the SUBSTRING starting point (2), and LEN position (-2) to whatever value you need to remove from your string.
It's non-iterative and doesn't require explicit case testing and above all it's inline all of which make for a cleaner execution plan.
The following script removes quotation marks only from around the column value if table is called [Messages] and the column is called [Description].
-- If the content is in the form of "anything" (LIKE '"%"')
-- Then take the whole text without the first and last characters
-- (from the 2nd character and the LEN([Description]) - 2th character)
UPDATE [Messages]
SET [Description] = SUBSTRING([Description], 2, LEN([Description]) - 2)
WHERE [Description] LIKE '"%"'
You can use following query which worked for me-
For updating-
UPDATE table SET colName= REPLACE(LTRIM(RTRIM(REPLACE(colName, '"', ''))), '', '"') WHERE...
For selecting-
SELECT REPLACE(LTRIM(RTRIM(REPLACE(colName, '"', ''))), '', '"') FROM TableName
you could replace the quotes with an empty string...
SELECT AllRemoved = REPLACE(CAST(MyColumn AS varchar(max)), '"', ''),
LeadingAndTrailingRemoved = CASE
WHEN MyTest like '"%"' THEN SUBSTRING(Mytest, 2, LEN(CAST(MyTest AS nvarchar(max)))-2)
ELSE MyTest
END
FROM MyTable
Some UDFs for re-usability.
Left Trimming by character (any number)
CREATE FUNCTION [dbo].[LTRIMCHAR] (#Input NVARCHAR(max), #TrimChar CHAR(1) = ',')
RETURNS NVARCHAR(max)
AS
BEGIN
RETURN REPLACE(REPLACE(LTRIM(REPLACE(REPLACE(#Input,' ','¦'), #TrimChar, ' ')), ' ', #TrimChar),'¦',' ')
END
Right Trimming by character (any number)
CREATE FUNCTION [dbo].[RTRIMCHAR] (#Input NVARCHAR(max), #TrimChar CHAR(1) = ',')
RETURNS NVARCHAR(max)
AS
BEGIN
RETURN REPLACE(REPLACE(RTRIM(REPLACE(REPLACE(#Input,' ','¦'), #TrimChar, ' ')), ' ', #TrimChar),'¦',' ')
END
Note the dummy character '¦' (Alt+0166) cannot be present in the data (you may wish to test your input string, first, if unsure or use a different character).
To remove both quotes you could do this
SUBSTRING(fieldName, 2, lEN(fieldName) - 2)
you can either assign or project the resulting value
You can use TRIM('"' FROM '"this "is" a test"') which returns: this "is" a test
CREATE FUNCTION dbo.TRIM(#String VARCHAR(MAX), #Char varchar(5))
RETURNS VARCHAR(MAX)
BEGIN
RETURN SUBSTRING(#String,PATINDEX('%[^' + #Char + ' ]%',#String)
,(DATALENGTH(#String)+2 - (PATINDEX('%[^' + #Char + ' ]%'
,REVERSE(#String)) + PATINDEX('%[^' + #Char + ' ]%',#String)
)))
END
GO
Select dbo.TRIM('"this is a test message"','"')
Reference : http://raresql.com/2013/05/20/sql-server-trim-how-to-remove-leading-and-trailing-charactersspaces-from-string/
I use this:
UPDATE DataImport
SET PRIO =
CASE WHEN LEN(PRIO) < 2
THEN
(CASE PRIO WHEN '""' THEN '' ELSE PRIO END)
ELSE REPLACE(PRIO, '"' + SUBSTRING(PRIO, 2, LEN(PRIO) - 2) + '"',
SUBSTRING(PRIO, 2, LEN(PRIO) - 2))
END
Try this:
SELECT left(right(cast(SampleText as nVarchar),LEN(cast(sampleText as nVarchar))-1),LEN(cast(sampleText as nVarchar))-2)
FROM TableName