Converter name URI with special characters from PostgreSQL function to MySQL - mysql

I need to convert a function from PostgreSQL toMySql. I need to remove the special characters from a string uri.
CREATE OR REPLACE FUNCTION name2uri(text)
RETURNS text
IMMUTABLE
STRICT
LANGUAGE SQL
AS $$
SELECT REPLACE(TRIM(regexp_replace(translate(
LOWER($1),
'áàâãäåāăąèééêëēĕėęěìíîïìĩīĭḩóôõöōŏőùúûüũūŭůäàáâãåæçćĉčöòóôõøüùúûßéèêëýñîìíïş',
'aaaaaaaaaeeeeeeeeeeiiiiiiiihooooooouuuuuuuuaaaaaaeccccoooooouuuuseeeeyniiiis'
), '[^a-z0-9\-]+', ' ', 'g')),' ', '-');
$$;
how do I do that? Tks.

Solution
DROP FUNCTION IF EXISTS translate;
DELIMITER //
CREATE FUNCTION translate(subject varchar(255), what varchar(255), replace_to varchar(255))
RETURNS varchar(255)
DETERMINISTIC
begin
declare c int unsigned default 0;
declare result varchar(255);
set result = subject;
while c <= length(subject) do
set result = replace(result, mid(what, c, 1), mid(replace_to, c, 1) );
set c=c+1;
end while;
return result;
end
and
DROP FUNCTION IF EXISTS name2uri;
DELIMITER //
CREATE FUNCTION name2uri(i text)
RETURNS longtext
DETERMINISTIC
BEGIN
declare result longtext;
set result = REPLACE(TRIM(regexp_replace(translate(
LOWER(i),
'áàâãäåāăąèééêëēĕėęěìíîïìĩīĭḩóôõöōŏőùúûüũūŭůäàáâãåæçćĉčöòóôõøüùúûßéèêëýñîìíïş',
'aaaaaaaaaeeeeeeeeeeiiiiiiiihooooooouuuuuuuuaaaaaaeccccoooooouuuuseeeeyniiiis'
), '[^a-z0-9-]+', ' ',1,0,'c')),' ', '-');
return result;
end
select name2uri(' fáBIO rodrígues') with space before or after the string comes out ok! --> fabio-rodrigues
select name2uri('fáBIO rodrígues') without space before or after the string quits not ok! --> fabio-rodr-gues (the char i is replace by -)
Why did not correctly replace the í character with i?

Related

mysql delimit and search column data

MySQL version = 5.7.29
I want to do a MySQL search on a column which has delimited data. For example:
'field_black:1, field_white:2, field1_black:5, field_green:3'
I want a function which takes input the color and returns only the delimited values which do not have the input color.
func(input, color, delimiter)
func('field_black:1, field_white:2, field1_black:5, field1_green:3', 'black', ',') = 'field_white:2, field1_green:3'
This is pretty easy to implement in python using string split on delimiter and returning result set where the color is not in the given input.
def func(inp, col, delim):
inp = inp.split(delim)
res = []
for data in inp:
if col not in data:
res.append(data)
return (','.join(res))
Can anyone help me with an equivalent implementation in MySQL.
Thank you for the help!
CREATE FUNCTION func (input TEXT, color TEXT, delimiter CHAR(1))
RETURNS TEXT
DETERMINISTIC
BEGIN
DECLARE piece TEXT;
DECLARE result TEXT DEFAULT '';
/* SET color = CONCAT('field_', color); */ /* uncomment if needed */
REPEAT
SET piece = SUBSTRING_INDEX(input, delimiter, 1);
SET input = SUBSTRING(input FROM 2 + LENGTH(piece) FOR LENGTH(input));
IF NOT LOCATE(color, piece) THEN
SET result = CONCAT(result, delimiter, TRIM(piece));
END IF;
UNTIL input = ''
END REPEAT;
RETURN TRIM(BOTH delimiter FROM result);
END
fiddle
PS. Of course you may use multi-char delimiter if needed - alter input parameter type simply.
Just cracked this after a few iterations due to unfamiliarity with MySQL syntax. This is unnecessarily complicated though.
Answer by Akina is more simple and elegant: mysql delimit and search column data
CREATE FUNCTION `new_function`(input longtext, col TEXT, delim CHAR(1)) RETURNS longtext CHARSET utf8
DETERMINISTIC
BEGIN
declare result longtext default '';
declare piece longtext default '';
declare inptext longtext default '';
set inptext = input;
while (substring_index(inptext,delim,1) = '') = 0 DO
set piece = substring_index(inptext,delim,1);
IF NOT LOCATE(col, piece) THEN
set result = concat(result, piece, delim);
END IF;
set inptext = substr(inptext, length(SUBSTRING_INDEX(inptext, '|', 1) ) + 2);
END WHILE;
set result = left(result, length(result) -1);
RETURN result;
END

Merges columns outputs it as string

I am new to mySQL and got the exercise to implement a function which merges columns from one table and outputs it as a string, separated by CR (a CR after each record, i.e. separate the records by “\n”).
I have tried it already, but there appears an error which say: "SELECT MergeTablesAndOutputString(1) LIMIT 0, 1000.
What do I have to do differently that it works?
DELIMITER //
CREATE FUNCTION MergeTablesAndOutputString
(owner_id int)
RETURNS varchar(50)
DETERMINISTIC
BEGIN
DECLARE bname varchar(30);
DECLARE apno int(30);
DECLARE gno int(30);
set bname = Building.buildingName;
set apno = Building.apartmentno;
set gno = Building.garageno;
RETURN CONCAT(bname, '\n' + apno, ' \n', gno);
END//
DELIMITER ;

How to convert TSQL query into MYSQL query?

I have developed a function for split string in tsql but mysql don't have some built in functions. I needed to function in MYSQL as i am new in mysql. Function should accept 2 parameters
1. String to be split
2. separator (',' or whatever)
Kindly reply me.
i had found solution on the internet you can into that.
DELIMITER //
DROP FUNCTION IF EXISTS `splitAndTranslate` //
CREATE FUNCTION splitAndTranslate(str TEXT, delim VARCHAR(124))
RETURNS TEXT
DETERMINISTIC
BEGIN
DECLARE i INT DEFAULT 0; -- total number of delimiters
DECLARE ctr INT DEFAULT 0; -- counter for the loop
DECLARE str_len INT; -- string length,self explanatory
DECLARE out_str text DEFAULT ''; -- return string holder
DECLARE temp_str text DEFAULT ''; -- temporary string holder
DECLARE temp_val VARCHAR(255) DEFAULT ''; -- temporary string holder for query
-- get length
SET str_len=LENGTH(str);
SET i = (LENGTH(str)-LENGTH(REPLACE(str, delim, '')))/LENGTH(delim) + 1;
-- get total number delimeters and add 1
-- add 1 since total separated values are 1 more than the number of delimiters
-- start of while loop
WHILE(ctr<i) DO
-- add 1 to the counter, which will also be used to get the value of the string
SET ctr=ctr+1;
-- get value separated by delimiter using ctr as the index
SET temp_str = REPLACE(SUBSTRING(SUBSTRING_INDEX(str, delim, ctr), LENGTH(SUBSTRING_INDEX(str, delim,ctr - 1)) + 1), delim, '');
-- query real value and insert into temporary value holder, temp_str contains the exploded ID
SELECT <real_value_column> INTO temp_val FROM <my_table> WHERE <table_id>=temp_str;
-- concat real value into output string separated by delimiter
SET out_str=CONCAT(out_str, temp_val, ',');
END WHILE;
-- end of while loop
-- trim delimiter from end of string
SET out_str=TRIM(TRAILING delim FROM out_str);
RETURN(out_str); -- return
END//
reference http://www.slickdev.com/2008/09/15/mysql-query-real-values-from-delimiter-separated-string-ids/
In mysql they they dont support some functionality like sqlserver. so spliting will be difficult in mysql
SELECT e.`studentId`, SPLIT(",", c.`courseNames`)[e.`courseId`]
FROM ..
SELECT TRIM(SUBSTRING_INDEX(yourcolumn,',',1)), TRIM(SUBSTRING_INDEX(yourcolumn,',',-1)) FROM yourtable
CREATE FUNCTION [dbo].[SplitString]
(
#RowData nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
--Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
While (Charindex(#SplitOn,#RowData)>0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END

MySQL replace only first occurence in text field/column

I wrote a function to replace first occurence in MySQL Text colum, but it's a little bit complicated...
UPDATE
table_name
SET
column=CONCAT(
LEFT(column,LOCATE('some string', column)-1),
CONCAT(substring(column, LOCATE('some string', column) + $length),
'new string'))
Where $length is length of string, that we want to replace. If we use php it is strlen() function but in MySQL it would be CHAR_LENGTH() function.
Do you know better way to replace only first match in text columns ?
You could use TRIM:
UPDATE table_name SET column = TRIM(LEADING 'some string' FROM column);
assuming 'some string' does not have more than 1 consecutive occurrence at the start of the contents of 'column'.
So, it would work if column contained:
"some string foo some string"
but not for:
"some string some string foo some string"
Edit - Added MySQL function to simplify process
I can't see an alternative to the mechanism you are using, but executing it could be simplified by creating a function in MySQL (if you have the privilege):
delimiter $$
create function replace_first(
p_text_to_search varchar(255),
p_text_to_replace varchar(255)
)
returns varchar(255)
begin
declare v_found_pos int(11);
declare v_found_len int(11);
declare v_text_with_replacement varchar(255);
select locate(p_text_to_replace, p_text_to_search)
into v_found_pos;
select char_length(p_text_to_replace)
into v_found_len;
select concat(
left(p_text_to_search, v_found_pos-1),
mid(p_text_to_search, (v_found_pos + v_found_len))
)
into v_text_with_replacement;
return v_text_with_replacement;
end$$
delimiter ;
then you can call it using:
select replace_first('bar foo foo baz foo', 'foo');
result:
'bar foo baz'
I have created function can replace any index of text:
/************** REPLACE_TEXT_OF_INDEX ***************/
DROP FUNCTION IF EXISTS REPLACE_TEXT_OF_INDEX;
DELIMITER $$
CREATE FUNCTION REPLACE_TEXT_OF_INDEX(_text VARCHAR(3072), _subText VARCHAR(1024), _toReplaceText VARCHAR(1024), _index INT UNSIGNED)
RETURNS VARCHAR(3072)
BEGIN
DECLARE _prefixText, _sufixText VARCHAR(3072);
DECLARE _starIndex INT;
DECLARE _loopIndex, _textIndex INT UNSIGNED DEFAULT 0;
IF _text IS NOT NULL AND LENGTH(_text) > 0 AND
_subText IS NOT NULL AND LENGTH(_subText) > 0 AND
_toReplaceText IS NOT NULL AND _index > 0 THEN
WHILE _loopIndex < LENGTH(_text) AND _textIndex < _index DO
SELECT LOCATE(_subText, _text, _loopIndex + 1) INTO _loopIndex;
IF _loopIndex > 0 THEN
SET _textIndex = _textIndex + 1;
ELSE
SET _loopIndex = LENGTH(_text) + 1;
END IF;
END WHILE;
IF _textIndex = _index THEN
SELECT LOCATE(_subText, _text, _loopIndex) INTO _starIndex;
SELECT SUBSTRING(_text, 1, _starIndex -1) INTO _prefixText;
SELECT SUBSTRING(_text, _starIndex + LENGTH(_subText), LENGTH(_text)) INTO _sufixText;
RETURN CONCAT(_prefixText, _toReplaceText, _sufixText);
END IF;
END IF;
RETURN _text;
END;
$$
DELIMITER ;
SELECT REPLACE_TEXT_OF_INDEX('WORD1 WORD2 WORD3 WORD4 WORD5', 'WORD', '*',1);

How can I pass an "array" of values to my stored procedure?

I want to be able to pass an "array" of values to my stored procedure, instead of calling "Add value" procedure serially.
Can anyone suggest a way to do it? am I missing something here?
Edit: I will be using PostgreSQL / MySQL, I haven't decided yet.
As Chris pointed, in PostgreSQL it's no problem - any base type (like int, text) has it's own array subtype, and you can also create custom types including composite ones. For example:
CREATE TYPE test as (
n int4,
m int4
);
Now you can easily create array of test:
select ARRAY[
row(1,2)::test,
row(3,4)::test,
row(5,6)::test
];
You can write a function that will multiply n*m for each item in array, and return sum of products:
CREATE OR REPLACE FUNCTION test_test(IN work_array test[]) RETURNS INT4 as $$
DECLARE
i INT4;
result INT4 := 0;
BEGIN
FOR i IN SELECT generate_subscripts( work_array, 1 ) LOOP
result := result + work_array[i].n * work_array[i].m;
END LOOP;
RETURN result;
END;
$$ language plpgsql;
and run it:
# SELECT test_test(
ARRAY[
row(1, 2)::test,
row(3,4)::test,
row(5,6)::test
]
);
test_test
-----------
44
(1 row)
If you plan to use MySQL 5.1, it is not possible to pass in an array.
See the MySQL 5.1 faq
If you plan to use PostgreSQL, it is possible look here
I don't know about passing an actual array into those engines (I work with sqlserver) but here's an idea for passing a delimited string and parsing it in your sproc with this function.
CREATE FUNCTION [dbo].[Split]
(
#ItemList NVARCHAR(4000),
#delimiter CHAR(1)
)
RETURNS #IDTable TABLE (Item VARCHAR(50))
AS
BEGIN
DECLARE #tempItemList NVARCHAR(4000)
SET #tempItemList = #ItemList
DECLARE #i INT
DECLARE #Item NVARCHAR(4000)
SET #tempItemList = REPLACE (#tempItemList, ' ', '')
SET #i = CHARINDEX(#delimiter, #tempItemList)
WHILE (LEN(#tempItemList) > 0)
BEGIN
IF #i = 0
SET #Item = #tempItemList
ELSE
SET #Item = LEFT(#tempItemList, #i - 1)
INSERT INTO #IDTable(Item) VALUES(#Item)
IF #i = 0
SET #tempItemList = ''
ELSE
SET #tempItemList = RIGHT(#tempItemList, LEN(#tempItemList) - #i)
SET #i = CHARINDEX(#delimiter, #tempItemList)
END
RETURN
END
You didn't indicate, but if you are referring to SQL server, here's one way.
And the MS support ref.
For PostgreSQL, you could do something like this:
CREATE OR REPLACE FUNCTION fnExplode(in_array anyarray) RETURNS SETOF ANYELEMENT AS
$$
SELECT ($1)[s] FROM generate_series(1,array_upper($1, 1)) AS s;
$$
LANGUAGE SQL IMMUTABLE;
Then, you could pass a delimited string to your stored procedure.
Say, param1 was an input param containing '1|2|3|4|5'
The statement:
SELECT CAST(fnExplode(string_to_array(param1, '|')) AS INTEGER);
results in a result set that can be joined or inserted.
Likewise, for MySQL, you could do something like this:
DELIMITER $$
CREATE PROCEDURE `spTest_Array`
(
v_id_arr TEXT
)
BEGIN
DECLARE v_cur_position INT;
DECLARE v_remainder TEXT;
DECLARE v_cur_string VARCHAR(255);
CREATE TEMPORARY TABLE tmp_test
(
id INT
) ENGINE=MEMORY;
SET v_remainder = v_id_arr;
SET v_cur_position = 1;
WHILE CHAR_LENGTH(v_remainder) > 0 AND v_cur_position > 0 DO
SET v_cur_position = INSTR(v_remainder, '|');
IF v_cur_position = 0 THEN
SET v_cur_string = v_remainder;
ELSE
SET v_cur_string = LEFT(v_remainder, v_cur_position - 1);
END IF;
IF TRIM(v_cur_string) != '' THEN
INSERT INTO tmp_test
(id)
VALUES
(v_cur_string);
END IF;
SET v_remainder = SUBSTRING(v_remainder, v_cur_position + 1);
END WHILE;
SELECT
id
FROM
tmp_test;
DROP TEMPORARY TABLE tmp_test;
END
$$
Then simply CALL spTest_Array('1|2|3|4|5') should produce the same result set as the above PostgreSQL query.
Thanks to JSON support in MySQL you now actually have the ability to pass an array to your MySQL stored procedure. Create a JSON_ARRAY and simply pass it as a JSON argument to your stored procedure.
Then in procedure, using MySQL's WHILE loop and MySQL's JSON "pathing" , access each of the elements in the JSON_ARRAY and do as you wish.
An example here https://gist.githubusercontent.com/jonathanvx/513066eea8cb5919b648b2453db47890/raw/22f33fdf64a2f292688edbc67392ba2ccf8da47c/json.sql
Incidently, here is how you would add the array to a function (stored-proc) call:
CallableStatement proc = null;
List<Integer> faultcd_array = Arrays.asList(1003, 1234, 5678);
//conn - your connection manager
conn = DriverManager.getConnection(connection string here);
proc = conn.prepareCall("{ ? = call procedureName(?) }");
proc.registerOutParameter(1, Types.OTHER);
//This sets-up the array
Integer[] dataFaults = faultcd_array.toArray(new Integer[faultcd_array.size()]);
java.sql.Array sqlFaultsArray = conn.createArrayOf("int4", dataFaults);
proc.setArray(2, sqlFaultsArray);
//:
//add code to retrieve cursor, use the data.
//: