why we can use = and := both with set? - mysql

Generally we know that '=' operator using for comparison and ':=' for assignment,
But while using with SET both are working as assignment operator why?
below stored procedure
for example:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `substringExample`()
BEGIN
DECLARE x varchar(7);
DECLARE num int;
DECLARE inc int;
SET inc:= 1;
WHILE inc<1400 DO
SELECT SUBSTRING(USER_TEMP_NUM, 8, 13) AS ExtractString
INTO x FROM USER_REGISTRATION_DETAILS where sl_no=inc;
SET num= CONVERT(x,int);
IF (num%2=0) THEN
SELECT num;
END IF;
SET inc:=inc+1;
END WHILE;
END$$
DELIMITER ;
in the above code SET num= CONVERT(x,int); gives the correct output as well as SET num:= CONVERT(x,int);
I am beginner of stored procedure so dont know at expert level

From John Woo's answer:
Both of them are assignment operators but one thing I can find their differences is that = can be used to perform boolean operation while := cannot.
valid: SUM(val = 0)
Invalid: SUM(val := 0)
FROM User-Defined Variables
One more thing, You can also assign a value to a user variable in statements other than SET. In this case, the assignment operator must be := and not = because the latter is treated as the comparison operator = in non-SET statements.
mysql> SET #t1=1, #t2=2, #t3:=4;
mysql> SELECT #t1, #t2, #t3, #t4 := #t1+#t2+#t3;
+------+------+------+--------------------+
| #t1 | #t2 | #t3 | #t4 := #t1+#t2+#t3 |
+------+------+------+--------------------+
| 1 | 2 | 4 | 7 |
+------+------+------+--------------------+
And also check this link, hope it helps you,
What is the difference between := and = mysql assignment operator

Related

mySQL set a varchar without the special characters

I use mySQL as a DBMS,
I have these rows in my table:
product_name | product_code | prod_type
prod1#00X | 1 |
#prod2#00X | 2 |
+prod3##00X | 3 |
I wanna set the prod_type = the product_name without the special characters.
=> prod_type
prod100X
prod200X
prod300X
(I can have other special characters not only '#' and '+')
How can I do that?
Method 1:
You can use the REPLACE() method to remove special characters in mysql, don't know if it's very efficient though. But it should work.
Like Below:
SELECT Replace(Replace(product_name,'#',''),'+','') as prod_type
From Table1
Fiddle Demo
Method 2:
If you have All other Special Charcter then go with this (Source)
-- ----------------------------
-- Function structure for `udf_cleanString`
-- ----------------------------
DROP FUNCTION IF EXISTS `udf_cleanString`;
DELIMITER ;;
CREATE FUNCTION `udf_cleanString`(`in_str` varchar(4096)) RETURNS varchar(4096) CHARSET utf8
BEGIN
DECLARE out_str VARCHAR(4096) DEFAULT '';
DECLARE c VARCHAR(4096) DEFAULT '';
DECLARE pointer INT DEFAULT 1;
IF ISNULL(in_str) THEN
RETURN NULL;
ELSE
WHILE pointer <= LENGTH(in_str) DO
SET c = MID(in_str, pointer, 1);
IF ASCII(c) > 31 AND ASCII(c) < 127 THEN
SET out_str = CONCAT(out_str, c);
END IF;
SET pointer = pointer + 1;
END WHILE;
END IF;
RETURN out_str;
END
;;
DELIMITER ;
After that just call the function as follows:
SELECT product_name, udf_cleanString(product_name) AS 'product_Type'
FROM table1;
SELECT Replace(Replace(product_name,'#',''),'+','')
From Table
in case other special characters try nested Replace
like this
select REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(product_name, '/', ''),'(',''),')',''),' ',''),'+',''),'-',''),'#','');
or try using Regex
What you can do is,
Create a function to remove the special character, you can find how from the refernece
use the query Update YourTable set prod_type = YourFunction(product_name )

Mysql:Query for the table as below

I have the following table:
|-------------------|
| id | Homephone |
|-------------------|
| 1 | 454454125 |
| 2 | 47872154587 |
| 3 | 128795423 |
| 4 | 148784474 |
|-------------------|
I have around 40.000 rows in the table.
I want to format Homephone values as following:
454-454-125
478-721-545-87
128-795-423
148-784-474
i.e. after every 3 numbers I want - (hyphen).
How to achieve this using MySQL?
You need to wite a udf for this
Basically, you need to create your own function (so called UDF - User Defined Function) and run it on the table.
There is a nice function by Andrew Hanna posted in String Functions chapter of the MySQL Reference Manual. I fixed a small mistake there (replaced WHILE (i < str_len) DO by WHILE (i <= str_len) DO.
There are two steps (two SQL queries):
Create the function. It has three parameters: str - the string to be modified, pos - position of the character being inserted into the string, delimit - character(s) to be inserted:
DELIMITER //
CREATE FUNCTION insert_characters(str text, pos int, delimit varchar(124))
RETURNS text
DETERMINISTIC
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE str_len INT;
DECLARE out_str text default '';
SET str_len = length(str);
WHILE (i <= str_len) DO
SET out_str = CONCAT(out_str, SUBSTR(str, i, pos), delimit);
SET i = i + pos;
END WHILE;
-- trim delimiter from end of string
SET out_str = TRIM(trailing delimit from out_str);
RETURN(out_str);
END//
DELIMITER ;
Run the function...
...for testing purpose (select, no update):
SELECT insert_characters(Homephone, 3, "-") AS new_phone FROM my_table;
...to update the records:
UPDATE my_table SET Homephone = insert_characters(Homephone, 3, "-");
Please try to analyze the function line by line. This example may help you to understand the subject.

mysql get ascii code dump for string

In MySQL, is there a way in a simple SELECT to obtain a sequence of ASCII code/code points for each character in a varchar value? I'm more familiar with Oracle, which has the DUMP function that can be used for this.
For example, select some_function('abcd') would return something like 96,97,98,99?
This is about the closest equivalent I'm aware of in MySQL:
mysql> select hex('abcd');
+-------------+
| hex('abcd') |
+-------------+
| 61626364 |
+-------------+
1 row in set (0.00 sec)
I don't know of a mysql_function that will do that, but you can take the string in php, convert to an array, then take the ordinal of the character.
$char_value_array = {};
foreach($mysql_fetched_str as $char)
array_push($char_value_array, ord($char)
You can create a function like this:
CREATE FUNCTION dump (s CHAR(20)) RETURNS CHAR(50) DETERMINISTIC
BEGIN
DECLARE result CHAR(50);
DECLARE i INT;
DECLARE l INT;
SET result = ASCII(SUBSTRING(s,1,1));
SET l = LENGTH(s);
SET i = 2;
WHILE (i <= l) DO
SET result = CONCAT(result, ',', ASCII(SUBSTRING(s,i,1)));
SET i = i + 1;
END WHILE;
RETURN result;
END;
And then use it in the SELECT:
SELECT dump('abcd') FROM test LIMIT 1
Increase CHAR(20) and CHAR(50) definitions if you need to use it with longer strings.

MySQL limit by sum

I want to limit my SELECT results in mySQL by sum.
For Example, this is my table:
(id, val)
Data Entries:
(1,100),
(2,300),
(3,50),
(4,3000)
I want to select first k entries such that the sum of val in those entries is just enough to make it to M.
For example, I want to find entries such that M = 425.
The result should be (1,100),(2,300),(3,50).
How can I do that in a mysql select query?
Try this variant -
SET #sum = 0;
SELECT id, val FROM (
SELECT *, #sum:=#sum + val mysum FROM mytable2 ORDER BY id
) t
WHERE mysum <= 450;
+------+------+
| id | val |
+------+------+
| 1 | 100 |
| 2 | 300 |
| 3 | 50 |
+------+------+
This stored procedure might help:
DELIMITER ;;
CREATE PROCEDURE selectLimitBySum (IN m INT)
BEGIN
DECLARE mTmp INT DEFAULT 0;
DECLARE idTmp INT DEFAULT 0;
DECLARE valTmp INT DEFAULT 0;
DECLARE doneLoop SMALLINT DEFAULT 0;
DECLARE crsSelect CURSOR FOR SELECT id, val FROM test3;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET doneLoop = 1;
OPEN crsSelect;
aloop: LOOP
SET idTmp = 0;
SET valTmp = 0;
FETCH crsSelect INTO idTmp, valTmp;
if doneLoop THEN
LEAVE aloop;
END IF;
SELECT idTmp, valTmp;
SET mTmp = mTmp + valTmp;
if mTmp > m THEN
LEAVE aloop;
END IF;
END LOOP;
CLOSE crsSelect;
END ;;
DELIMITER ;
Please feel free to change the table names or variable names as per your needs.
from mysql reference manual:
The LIMIT clause can be used to constrain the number of rows returned by the SELECT statement. LIMIT takes one or two numeric arguments, which must both be nonnegative integer constants (except when using prepared statements).
So you cannot use limit the way you proposed. To achieve what you want you need to use your application (java, c, php or whatever else), read the result set row by row, and stop when your condition is reached.
or you can use a prepared statement, but anyway you cant have conditional limit (it must be a constant value) and it is not exactly what you asked for.
create table #limit(
id int,
val int
)
declare #sum int, #id int, #val int, #m int;
set #sum=0;
set #m=250; --Value of an entry
declare limit_cursor cursor for
select id, val from your_table order by id
open limit_cursor
fetch next from limit_cursor into #id, #val
while(##fetch_status=0)
begin
if(#sum<#m)
begin
set #sum = #sum+#val;
INSERT INTO #limit values (#id, #val);
fetch next from limit_cursor into #id, #val
end
else
begin
goto case1;
end
end
case1:
close limit_cursor
deallocate limit_cursor
select * from #limit
truncate table #limit

Case-insensitive REPLACE in MySQL?

MySQL runs pretty much all string comparisons under the default collation... except the REPLACE command. I have a case-insensitive collation and need to run a case-insensitive REPLACE. Is there any way to force REPLACE to use the current collation rather than always doing case-sensitive comparisons? I'm willing to upgrade my MySQL (currently running 5.1) to get added functionality...
mysql> charset utf8 collation utf8_unicode_ci;
Charset changed
mysql> select 'abc' like '%B%';
+------------------+
| 'abc' like '%B%' |
+------------------+
| 1 |
+------------------+
mysql> select replace('aAbBcC', 'a', 'f');
+-----------------------------+
| replace('aAbBcC', 'a', 'f') |
+-----------------------------+
| fAbBcC | <--- *NOT* 'ffbBcC'
+-----------------------------+
If replace(lower()) doesn't work, you'll need to create another function.
My 2 cents.
Since many people have migrated from MySQL to MariaDB, those people will have available a new function called REGEXP_REPLACE. Use it as you would a normal replace, but the pattern is a regular expression.
This is a working example:
UPDATE `myTable`
SET `myField` = REGEXP_REPLACE(`myField`, '(?i)my insensitive string', 'new string')
WHERE `myField` REGEXP '(?i)my insensitive string'
The option (?i) makes all the subsequent matches case insensitive (if put at the beginning of the pattern like I have then it all is insensitive).
See here for more information: https://mariadb.com/kb/en/mariadb/pcre/
Edit: as of MySQL 8.0 you can now use the regexp_replace function too, see documentation: https://dev.mysql.com/doc/refman/8.0/en/regexp.html
Alternative function for one spoken by fvox.
DELIMITER |
CREATE FUNCTION case_insensitive_replace ( REPLACE_WHERE text, REPLACE_THIS text, REPLACE_WITH text )
RETURNS text
DETERMINISTIC
BEGIN
DECLARE last_occurency int DEFAULT '1';
IF LCASE(REPLACE_THIS) = LCASE(REPLACE_WITH) OR LENGTH(REPLACE_THIS) < 1 THEN
RETURN REPLACE_WHERE;
END IF;
WHILE Locate( LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE), last_occurency ) > 0 DO
BEGIN
SET last_occurency = Locate(LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE));
SET REPLACE_WHERE = Insert( REPLACE_WHERE, last_occurency, LENGTH(REPLACE_THIS), REPLACE_WITH);
SET last_occurency = last_occurency + LENGTH(REPLACE_WITH);
END;
END WHILE;
RETURN REPLACE_WHERE;
END;
|
DELIMITER ;
Small test:
SET #str = BINARY 'New York';
SELECT case_insensitive_replace(#str, 'y', 'K');
Answers: New Kork
This modification of Luist's answer allows one to replace the needle with a differently cased version of the needle (two lines change).
DELIMITER |
CREATE FUNCTION case_insensitive_replace ( REPLACE_WHERE text, REPLACE_THIS text, REPLACE_WITH text )
RETURNS text
DETERMINISTIC
BEGIN
DECLARE last_occurency int DEFAULT '1';
IF LENGTH(REPLACE_THIS) < 1 THEN
RETURN REPLACE_WHERE;
END IF;
WHILE Locate( LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE), last_occurency ) > 0 DO
BEGIN
SET last_occurency = Locate(LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE), last_occurency);
SET REPLACE_WHERE = Insert( REPLACE_WHERE, last_occurency, LENGTH(REPLACE_THIS), REPLACE_WITH);
SET last_occurency = last_occurency + LENGTH(REPLACE_WITH);
END;
END WHILE;
RETURN REPLACE_WHERE;
END;
|
DELIMITER ;
I went with http://pento.net/2009/02/15/case-insensitive-replace-for-mysql/ (in fvox's answer) which performs the case insensitive search with case sensitive replacement and without changing the case of what should be unaffected characters elsewhere in the searched string.
N.B. the comment further down that same page stating that CHAR(255) should be changed to VARCHAR(255) - this seemed to be required for me as well.
In the previous answers, and the pento.net link, the arguments to LOCATE() are lower-cased.
This is a waste of resources, as LOCATE is case-insensitive by default:
mysql> select locate('el', 'HELLo');
+-----------------------+
| locate('el', 'HELLo') |
+-----------------------+
| 2 |
+-----------------------+
You can replace
WHILE Locate( LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE), last_occurency ) > 0 DO
with
WHILE Locate(REPLACE_THIS, REPLACE_WHERE, last_occurency ) > 0 DO
etc.
In case of 'special' characters there is unexpected behaviour:
SELECT case_insensitive_replace('A', 'Ã', 'a')
Gives
a
Which is unexpected... since we only want to replace the à not A
What is even more weird:
SELECT LOCATE('Ã', 'A');
gives
0
Which is the correct result... seems to have to do with encoding of the parameters of the stored procedure...
I like to use a search and replace function I created when I need to replace without worrying about the case of the original or search strings. This routine bails out quickly if you pass in an empty/null search string or a null replace string without altering the incoming string. I also added a safe count down just in case somehow the search keep looping. This way we don't get stuck in a loop forever. Alter the starting number if you think it is too low.
delimiter //
DROP FUNCTION IF EXISTS `replace_nocase`//
CREATE FUNCTION `replace_nocase`(raw text, find_str varchar(1000), replace_str varchar(1000)) RETURNS text
CHARACTER SET utf8
DETERMINISTIC
BEGIN
declare ret text;
declare len int;
declare hit int;
declare safe int;
if find_str is null or find_str='' or replace_str is null then
return raw;
end if;
set safe=10000;
set ret=raw;
set len=length(find_str);
set hit=LOCATE(find_str,ret);
while hit>0 and safe>0 do
set ret=concat(substring(ret,1,hit-1),replace_str,substring(ret,hit+len));
set hit=LOCATE(find_str,ret,hit+1);
set safe=safe-1;
end while;
return ret;
END//
This question is a bit old but I ran into the same problem and the answers given didn't allow me to solve it entirely.
I wanted the result to retain the case of the original string.
So I made a small modification to the replace_ci function proposed by fvox :
DELIMITER $$
DROP FUNCTION IF EXISTS `replace_ci`$$
CREATE FUNCTION `replace_ci` (str TEXT, needle CHAR(255), str_rep CHAR(255))
RETURNS TEXT
DETERMINISTIC
BEGIN
DECLARE return_str TEXT DEFAULT '';
DECLARE lower_str TEXT;
DECLARE lower_needle TEXT;
DECLARE tmp_needle TEXT;
DECLARE str_origin_char CHAR(1);
DECLARE str_rep_char CHAR(1);
DECLARE final_str_rep TEXT DEFAULT '';
DECLARE pos INT DEFAULT 1;
DECLARE old_pos INT DEFAULT 1;
DECLARE needle_pos INT DEFAULT 1;
IF needle = '' THEN
RETURN str;
END IF;
SELECT LOWER(str) INTO lower_str;
SELECT LOWER(needle) INTO lower_needle;
SELECT LOCATE(lower_needle, lower_str, pos) INTO pos;
WHILE pos > 0 DO
SELECT substr(str, pos, char_length(needle)) INTO tmp_needle;
SELECT '' INTO final_str_rep;
SELECT 1 INTO needle_pos;
WHILE needle_pos <= char_length(tmp_needle) DO
SELECT substr(tmp_needle, needle_pos, 1) INTO str_origin_char;
SELECT SUBSTR(str_rep, needle_pos, 1) INTO str_rep_char;
SELECT CONCAT(final_str_rep, IF(BINARY str_origin_char = LOWER(str_origin_char), LOWER(str_rep_char), IF(BINARY str_origin_char = UPPER(str_origin_char), UPPER(str_rep_char), str_rep_char))) INTO final_str_rep;
SELECT (needle_pos + 1) INTO needle_pos;
END WHILE;
SELECT CONCAT(return_str, SUBSTR(str, old_pos, pos - old_pos), final_str_rep) INTO return_str;
SELECT pos + CHAR_LENGTH(needle) INTO pos;
SELECT pos INTO old_pos;
SELECT LOCATE(lower_needle, lower_str, pos) INTO pos;
END WHILE;
SELECT CONCAT(return_str, SUBSTR(str, old_pos, CHAR_LENGTH(str))) INTO return_str;
RETURN return_str;
END$$
DELIMITER ;
Example of use :
SELECT replace_ci( 'MySQL', 'm', 'e' ) as replaced;
Will return :
| replaced |
| --- |
| EySQL |