How to generate 5 random numbers in mysql stored procedure - mysql

How can I generate 5 unique random numbers?
Now I have something like
declare v_counter integer;
declare v_random integer;
declare v_result varchar(10);
select FLOOR(1+(rand()*50)) into v_result;
set v_counter=0;
while v_counter < 4 then
select FLOOR(1+(rand()*50)) into v_random;
set v_result = concat(v_result,'|',v_random;
v_counter = v_counter + 1;
end while;
The result can look like this:
12|22|3|46|3
The numbers need to be unique and sorted so it looks like:
1|2|3|4|5
Any idea?

If your range is small, and you have an integers table, a naive approach might work:
SELECT GROUP_CONCAT(i SEPARATOR '|')
FROM ( SELECT i
FROM ( SELECT i
FROM integers
WHERE i BETWEEN 1 AND 50
ORDER BY RAND()
LIMIT 5) sort_these_five
ORDER BY i) concat_these_five;

Related

SQL Cursor to determine median value

I am trying to write a Stored Procedure to retrieve the median salary from a table and am having trouble figuring out how to retrieve the data from the cursor.
Currently my code is:
DELIMITER //
CREATE PROCEDURE MedianSalary(OUT median INT)
BEGIN
DECLARE counter int(5) DEFAULT 0;
DECLARE set_size int(5) DEFAULT (SELECT count(*) from employee);
DECLARE median_index int(5) DEFAULT (SELECT floor(count/2));
DECLARE all_salaries CURSOR
FOR SELECT salary from employee,
OPEN all_salaries;
WHILE #counter != #median_index
BEGIN
SET #counter = #counter + 1,
FETCH NEXT from all_salaries,
END;
FETCH all_salaries INTO median;
CLOSE all_salaries;
END //
DELIMITER ;
I can't seem to find any documentation similar to what I am trying to achieve, any help would be greatly appreciated.
I don't have an answer to your stored procedure problem, but note that we can actually find the median from a table in MySQL fairly easily using session variables to simulate the row number:
SET #row_number = 0;
SET #row_count = (SELECT COUNT(*) FROM yourtable);
SELECT AVG(salary) AS median
FROM
(
SELECT (#row_number:=#row_number + 1) AS rn, salary
FROM yourTable
ORDER BY salary
) t
WHERE
(#row_count % 2 = 0 AND rn IN (#row_count / 2, (#row_count / 2) + 1) OR
#row_count % 2 <> 0 AND rn = #row_count / 2);
Demo
Note the ugliness in the WHERE clause has to do with the edge case of your table having an even number of records. In this case, there technically is not a single median record, so instead I report the mean of the two records which sit about the median on either side.

Mysql: Finding longest character sequence in a string

In mySQL, how can I find the length of the longest sequence of a given character? For example, in the following string
1325******2h3n***3k2n*
If I were looking for the * character, the result should be 6 because the chain of 6 * characters is the longest present in the string.
You can use instr and and generated table with UNION to get it.
-- This query can find up to 10. If more need, need to update the `UNION`.
select max((instr('1325*****2h3n***3k2n*',repeat('*', times)) != 0) * times ) longest_seq
from (select 1 times union select 2 union select 3 union select 4 union select 5
union select 6 union select 7 union select 8 union select 9 union select 10) t;
Demo:
mysql> select max((instr('1325*****2h3n***3k2n*',repeat('*', times)) != 0) * times ) longest_seq
-> from (select 1 times union select 2 union select 3 union select 4 union select 5
-> union select 6 union select 7 union select 8 union select 9 union select 10) t;
+-------------+
| longest_seq |
+-------------+
| 5 |
+-------------+
1 row in set (0.01 sec)
what your looking for is basically the length of the longest substring,
you can find the algorithm for it here
Trying to achieve this with a query would not be such a good idea,
I suggest, using a stored procedure instead.
Dylan Su's solution is clever and works well if you know the maximum number of characters is small or don't want the overhead of building a function.
On the other hand one of the following function definitions will work regardless of character length without having to add new UNION statements indefinitely.
This function loops over each of the characters in the string, and if they match the repeat character, increments a length counter. It then returns the max length.
DELIMITER //
CREATE FUNCTION LONGEST_CHARACTER_SEQUENCE(input VARCHAR(255), repeat_character CHAR(1))
RETURNS TINYINT UNSIGNED DETERMINISTIC NO SQL
BEGIN
DECLARE max_length TINYINT UNSIGNED DEFAULT 0;
DECLARE length TINYINT UNSIGNED DEFAULT 0;
DECLARE in_sequence BOOLEAN DEFAULT 0;
DECLARE position INT DEFAULT 1;
WHILE position <= LENGTH(input) DO
IF SUBSTRING(input, position, 1) = repeat_character THEN
IF in_sequence THEN
SET length = length + 1;
ELSE
SET length = 1;
END IF;
IF length > max_length THEN
SET max_length = length;
END IF;
SET in_sequence = 1;
ELSE
SET in_sequence = 0;
END IF;
SET position = position + 1;
END WHILE;
RETURN max_length;
END//
DELIMITER ;
SELECT LONGEST_CHARACTER_SEQUENCE('1325******2h3n***3k2n*', '*');
-- Returns: 6
Inspired by Dylan Su's answer, this function increments a length counter until INSTR no longer returns true. I think it's simpler.
DELIMITER //
CREATE FUNCTION LONGEST_CHARACTER_SEQUENCE(input VARCHAR(255), repeat_character CHAR(1))
RETURNS TINYINT UNSIGNED DETERMINISTIC NO SQL
BEGIN
DECLARE length TINYINT UNSIGNED DEFAULT 0;
WHILE INSTR(input, REPEAT(repeat_character, length + 1)) DO
SET length = length + 1;
END WHILE;
RETURN length;
END//
DELIMITER ;
SELECT LONGEST_CHARACTER_SEQUENCE('1325******2h3n***3k2n*', '*');
-- Also returns: 6

How to change my sql to loop in MySql stored procedure in mysql?

When I write my sql in each statement,it works well.Now my sql is:
SELECT COUNT(*) INTO v_Point1Num from tbpoint where Point=1;
SELECT COUNT(*) INTO v_Point2Num from tbpoint where Point=2;
SELECT COUNT(*) INTO v_Point3Num from tbpoint where Point=3;
SELECT COUNT(*) INTO v_Point4Num from tbpoint where Point=4;
SELECT COUNT(*) INTO v_Point5Num from tbpoint where Point=5;
and it work well.
Now I try to change it to loop,but it is wrong,how to fix it?I wonder it is the reason that I do not use "#" like "#v".
--can not work.
CREATE `SP_Point`()
BEGIN
DECLARE v INT DEFAULT(0);
DECLARE pointlStr VARCHAR(800);
SET v = 1;
WHILE v <= 5 DO
SELECT COUNT(*) INTO
(case v
when 1 then concat('v_Point',v,'Num')
when 2 then concat('v_Point',v,'Num')
when 3 then concat('v_Point',v,'Num')
when 4 then concat('v_Point',v,'Num')
when 5 then concat('v_Point',v,'Num')
)
from tbpoint
where Point=v;
SET v = v + 1;
END WHILE;
END
I try to change it to the other way,but it is still wrong.
SET v = 1;
WHILE v <= 5 DO
set pointlStr=
'SELECT COUNT(*) INTO #v_Point'+#v+'Num from tbpoint
where Point='+#v;
prepare stmt from #pointlStr;
execute stmt;
SET v = v + 1;
END WHILE;
You are trying to create a new variables(v_Point1Num, v_Point2Num.... etc) at run time which is not possible into mysql. you must declare a variable before using it.
You can achieve the same output by running single query as well... rather then running multiple queries
SELECT Point, COUNT(*) from tbpoint
group by Point
having point > 0 and point <= 5;
Concat() function return the varchar/String not the variable name. declare only one variable "v_pointNum"... fetch the value into variable inside loop.... and in the same loop update the other table as well. –
CREATE `SP_Point`()
BEGIN
DECLARE v INT DEFAULT(0);
-- declare a variable to hold count value
DECLARE v_pointNum INT DEFAULT(0);
DECLARE serviceAttitudeLevelStr VARCHAR(800);
SET v = 1;
WHILE v <= 5 DO
SELECT COUNT(*) INTO v_pointNum from tbpoint where Point=v;
-- update another table
update <mytable> set <mycol> = v_pointNum where <condition>;
SET v = v + 1;
END WHILE;
END

MySQL function declare 2 variables with one select

I'd like to know how I can create a MySQL function that declares 2 variables by using 1 select statement.
Something like this:
CREATE FUNCTION `inHashtagCampaign` (campaignId INT,startDateTime DATETIME,endDateTime DATETIME)
RETURNS TEXT
LANGUAGE SQL
DETERMINISTIC
BEGIN
DECLARE result TEXT;
DECLARE limit BIGINT(11);
DECLARE suspended TINYINT(1);
#
#I don't know how to do this, but I'd like to use the result of this query:
#
result = SELECT `limit`,`suspended` FROM `settings` WHERE `campaignId` = 2;
limit = result.limit;
suspended = result.suspended;
END;
I know this function is far from complete, but I'm kinda stuck on this thing already.
I think what you are trying to do is like this
DECLARE #limit BIGINT(11);
DECLARE #suspended TINYINT(1);
SELECT #limit := `limit`, #suspended := `suspended` FROM `settings`
WHERE `campaignId` = 2;
(OR)
DECLARE limit1 BIGINT(11);
DECLARE suspended1 TINYINT(1);
SELECT `limit`,`suspended` into limit1, suspended1
FROM `settings` WHERE `campaignId` = 2;

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