Generate a random string in MySQL - mysql

I'm trying to get a random string in phpmyadmin using a function.
I have the following code:
CREATE FUNCTION randomPassword()
RETURNS varchar(128)
BEGIN
SET #chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
SET #charLen = length(#chars);
SET #randomPassword = '';
WHILE length(#randomPassword) < 12
SET #randomPassword = concat(#randomPassword, substring(#chars,CEILING(RAND() * #charLen),1));
END WHILE;
RETURN #randomPassword ;
END;
Now I get the error:
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 5
Does anyone know how I can fix this?

This is faster than concat + substring routine.
select substring(MD5(RAND()),1,20);
As I've tested inserting 1M random data, md5 routine consumes only 1/4 (even less) time of concat + substring routine;
The problem is a md5 string contains only 32 chars so if you need a longer one you'd have to manually generate more md5 strings and substring it yourself.

Try this more simple solution:
SELECT CONV(FLOOR(RAND() * 99999999999999), 10, 36)

SELECT SUBSTRING(REPLACE(REPLACE(REPLACE( TO_BASE64(MD5(RAND())), '=',''),'+',''),'/',''), 2, 40)
This solution to generate a fixed length random string that contains all lower- and upper-case chars and digits.
SELECT SUBSTRING(REPLACE(REPLACE(REPLACE( TO_BASE64(MD5(RAND())), '=',''),'+',''),'/',''), 2, FLOOR(10+RAND()*31))
If you need a random length string (from 10 to 40 symbols in this example)

It's solved by using the Delimiter, i don't know for sure how, but it works
Thanks
DELIMITER $$
CREATE FUNCTION randomPassword()
RETURNS varchar(128)
BEGIN
SET #chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
SET #charLen = length(#chars);
SET #randomPassword = '';
WHILE length(#randomPassword) < 12
DO
SET #randomPassword = concat(#randomPassword, substring(#chars,CEILING(RAND() * #charLen),1));
END WHILE;
RETURN #randomPassword ;
END$$
DELIMITER ;

CREATE FUNCTION randomPassword()
RETURNS varchar(128)
AS
BEGIN
declare #chars nvarchar(25);
declare #charlen int;
declare #randomPassword nvarchar(128);
SET #chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
SET #charLen = len(#chars);
SET #randomPassword = '';
WHILE(LEN(#randomPassword) < 12)
BEGIN
SET #randomPassword = concat(#randomPassword, substring(#chars,CEILING(RAND() * #charLen),1));
END
RETURN #randomPassword
END

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

removing adjacent newline characters sql

Im trying to remove newline characters when the next character is also a newline
using the Function I wrote below, and im running into a problem. When I input this string :
"Line1
Line2
Line3
Line4"
It removes the newlines after line 1 and 2 , but the lines between 3 and 4 remain ? Any ideas as to why the function doesn't work then ?
DELIMITER $$
DROP FUNCTION IF EXISTS removeLines;
CREATE FUNCTION test_dev.removeLines(address varchar(255))
RETURNS varchar(255)
DETERMINISTIC
BEGIN
DECLARE i int;
SET i = 0;
WHILE i < length(address)-1 DO
IF(((SUBSTR(address,i,1) in (CHAR(10) ,CHAR(13))) AND (SUBSTR(address,i+1,1) in (CHAR(10) ,CHAR(13))) ) )
THEN set address = INSERT(address,i,1,'');
SET i= i+1;
ELSE set i= i+1;
END IF;
END WHILE;
RETURN address;
END$$
DELIMITER ;
An alternate way to write your function so you don't have to manually keep track of character indexing.
while instr(address, '\r\n\r\n') do
address = replace(address, '\r\n\r\n', '\r\n');
end while;
I didn't have a chance to test this in a database so the syntax may not be 100% correct.
The problem is that you increment i after you replace a newline. Consider the following simple string:
1\n\n\n2
01 2 3 4 -- indexes
When i is 1, you see that there are newlines at indexes i=1 and i+1=2, so you remove the first one with INSERT(). Now the string is:
1\n\n2
01 2 3
and you do SET i = i + 1. Now i is 2, but indexes i=2 and i+1=3 don't have newlines, so you don't remove the next newline.
Change it so that you only increment i when you don't find a pair of newlines.
IF(((SUBSTR(address,i,1) in (CHAR(10) ,CHAR(13))) AND (SUBSTR(address,i+1,1) in (CHAR(10) ,CHAR(13))) ) )
THEN set address = INSERT(address,i,1,'');
ELSE set i= i+1;
END IF;

phpMyAdmin - mariaDB roman numerals function

can anybody help me with my sorting function - seriously I don't know how can I make it work as supposed to. :( Database is in MariaDB in Xampp. I use phpMyAdmin to execute the query.
DELIMITER $$
DROP FUNCTION IF EXISTS convRomanNumeral$$
CREATE FUNCTION convRomanNumeral (numeral CHAR(4))
RETURNS INT
BEGIN
DECLARE intnum INT;
CASE numeral
WHEN "I" THEN intnum = 1;
WHEN "II" THEN intnum = 2;
END CASE;
RETURN intnum;
END;
$$
SET #iteration = -1;
UPDATE `st0gk_docman_documents`
SET created_on = DATE('2016-06-14') + INTERVAL(#iteration := #iteration + 1) SECOND
WHERE `docman_category_id` = 141 ORDER BY convRomanNumeral(SUBSTRING(SUBSTRING_INDEX(title,'/',1),' ',-2) ASC, SUBSTRING_INDEX(title,'/',-2)+0 ASC;
So what I want to achieve is to sort documents by title. Example titles are:
Document Nr I/36/2006
Document Nr II/36/2006
Document Nr I/32/2006
Document Nr II/19/2006
After sorting them by first Roman number and then by second Arabic number I want to update the date. Code below for updating by only second Arabic number works properly:
SET #iteration = -1;
UPDATE `st0gk_docman_documents`
SET created_on = DATE('2016-06-14') + INTERVAL(#iteration := #iteration + 1) SECOND
WHERE `docman_category_id` = 141 ORDER BY SUBSTRING_INDEX(title,'/',-2)+0 ASC;
I would like to use CASE to return proper variable for Roman values. I know it's not perfect but I can't even make the CASE and FUNCTION work. What I am doing wrong? All suggestions are welcome.
The best way to do this is to add another column that has a sortable equivalent of that string. And use non-SQL code to do the parsing and building of that column before inserting into the table.
First mistake that I was making it was trying to execute the whole query at once... After taking the first lodge out of the way the debugging seemed way simpler. :D
So I created my case function to convert Roman numerals:
DELIMITER $$
DROP FUNCTION IF EXISTS convRomanNumeralSubFunction$$
CREATE FUNCTION convRomanNumeralSubFunction (numeral CHAR(1))
RETURNS INT
BEGIN
DECLARE intnum INT;
CASE numeral
WHEN "I" THEN SELECT 1 INTO intnum;
WHEN "X" THEN SELECT 10 INTO intnum;
WHEN "C" THEN SELECT 100 INTO intnum;
WHEN "M" THEN SELECT 1000 INTO intnum;
WHEN "V" THEN SELECT 5 INTO intnum;
WHEN "L" THEN SELECT 50 INTO intnum;
WHEN "D" THEN SELECT 500 INTO intnum;
END CASE;
RETURN intnum;
END;
$$
After that I declared the second function needed for conversion. I don't know if You can declare function inside function... and I didn't want to waste more time on this. For sure You can declare Function inside Procedure. Anyhow. WARNING: This function is not proof of BAD numerals like IIX. Numerals like that or will be badly counted. Also AXI will not count.
DELIMITER $$
DROP FUNCTION IF EXISTS convRomanNumeral$$
CREATE FUNCTION convRomanNumeral (numeral CHAR(10))
RETURNS INT
BEGIN
DECLARE currentintnum, previntnum, intnum, counter, numerallength INT;
SET numerallength = LENGTH(numeral);
SET counter = numerallength;
SET intnum = 0;
SET previntnum = 0;
WHILE counter > 0 DO
SET currentintnum = CAST(convRomanNumeralSubFunction(SUBSTRING(numeral,counter, 1)) as integer);
IF currentintnum < previntnum THEN
SET intnum = intnum - currentintnum;
ELSE
SET intnum = intnum + currentintnum;
END IF;
SET previntnum = currentintnum;
SET counter = counter - 1;
END WHILE;
RETURN intnum;
END;
$$
So that's it. Now You can convert all kind of Roman numerals and sort them up.
Use this to test the conversion:
SELECT convRomanNumeral("XIX");
This is example sorting code that I in the end used:
SET #iteration = -1;
UPDATE `st0gk_docman_documents`
SET created_on = DATE('2016-06-07') + INTERVAL(#iteration := #iteration + 1) SECOND
WHERE `docman_category_id` = 67 ORDER BY convRomanNumeralBreak(SUBSTRING_INDEX(SUBSTRING_INDEX(title,'/',1),' ',-1)) ASC, SUBSTRING_INDEX(title,'/',-2)+0 ASC;
Also one more thing - if You'll try to excecute this on mySQL then You have to fix this line:
SET currentintnum = CAST(convRomanNumeralSubFunction(SUBSTRING(numeral,counter, 1)) as integer);
into this:
SET currentintnum = CAST(convRomanNumeralSubFunction(SUBSTRING(numeral,counter, 1)) as SIGNED);
This code could be improved but as the #Rick James stated this should be done differently - not in as db update but in different table structure and sorting mechanism.

Query to find all words in a field that contains the letters

I am trying to run a query that can find all the records from a field contains the letters.
For example suppose a state field contains a record value "New York" and another record conatains NY. Now i am searching for NY or New york will return these 2 records. What will be the query.
Currently i am using
like %New York%" or "%NY%"
Any suggestion
No your query is not correct as it searches for anything containing New York or NY.
So if there is PENNY that will be matched although it shouldn't be....
Your query must be something like this.
SELECT * from TABLE where field in ('NEW YORK','NY')
Now to fetch acronym,you can use
delimiter $$
drop function if exists `initials`$$
CREATE FUNCTION `initials`(str text, expr text) RETURNS text CHARSET utf8
begin
declare result text default '';
declare buffer text default '';
declare i int default 1;
if(str is null) then
return null;
end if;
set buffer = trim(str);
while i <= length(buffer) do
if substr(buffer, i, 1) regexp expr then
set result = concat( result, substr( buffer, i, 1 ));
set i = i + 1;
while i <= length( buffer ) and substr(buffer, i, 1) regexp expr do
set i = i + 1;
end while;
while i <= length( buffer ) and substr(buffer, i, 1) not regexp expr do
set i = i + 1;
end while;
else
set i = i + 1;
end if;
end while;
return result;
end$$
drop function if exists `acronym`$$
CREATE FUNCTION `acronym`(str text) RETURNS text CHARSET utf8
begin
declare result text default '';
set result = initials( str, '[[:alnum:]]' );
return result;
end$$
delimiter ;
So,your final query will be something like this.
SELECT * from TABLE where field in ('NEW YORK',select acronym('Come Again? That Cant Help!'))
Source:- Mysql extract first letter of each word in a specific column
Presumably, the logic that you want is:
col like '%New York%' or col like '%NY%'
or, if you want to use regular expressions:
col regexp 'New York|NY'
Select * from table where col like '%N' or col like '%n'

Parsing Integers out of a string in SQL

I have a fairly large database with with a column that has strings that are for the most part really just ints, e.g. "1234" or "345". However some of them have strings prepended to them (of varying length), so e.g. "a123" or "abc123".
Is there a smart way to create a new column with just the integer values? Thus, "abc123" would become "123"? I know I can read all of the rows in PHP and then use a regex to do it pretty easily but I wanted to see if there was a way to let SQL do this for me.
Unfortunately you can't do this in MySQL just by itself. MySQL has regex matching capabilities, but no regex replacement capabilities. Your best option would be to use a regex in PHP to perform your replacement. (Source)
$sql = "SELECT `id`, `myMixedColumn` FROM `myTable` "
. "WHERE `myMixedColumn` NOT RLIKE '^[[:digit:]]+$'";
$r = mysql_query($sql);
$updates = array();
while ($row = mysql_fetch_assoc($r)) {
$updates = sprintf("UPDATE `myTable` SET `myIntField` = %s WHERE `id` = %d",
preg_replace("#\\D#", "", $row['myMixedColumn']),
$row['id']
);
}
If you really want to do it in SQL, just for the sake of not doing in PHP, you could make a small function that does it until MySQL implements a regex replace, but I wouldn't bet anything on the performance.
Something like that would only work if the letters were at the beginning and that there would be no other characters than [a-zA-Z]. And you'd have to check how it runs in different charsets.
CREATE FUNCTION last_letter(s VARCHAR(100)) RETURNS INT
BEGIN
DECLARE last, current INT default 0;
DECLARE letter_a INT;
DECLARE letter_z INT;
DECLARE letter_iter INT;
SELECT ord('a') INTO letter_a;
SELECT ord('z') INTO letter_z;
SET letter_iter = letter_a;
# Will loop for all letters a to z
WHILE letter_iter <= letter_z DO
# Will get the last case-insensitive occurrence of a letter
SELECT LOCATE(CHAR(letter_iter), REVERSE(LOWER(s))) INTO current;
IF current > 0 THEN
SELECT LENGTH(s) - current + 1 INTO current;
END IF;
# Was that the rightmost letter?
IF current > last THEN
SET last = current;
END IF;
SET letter_iter = letter_iter + 1;
END WHILE;
# Return the max we found
RETURN last;
END; //
And then to get the integer values:
UPDATE test_table SET int_result =
CAST(SUBSTR(str_value, last_letter(str_value) + 1) AS SIGNED);