Set user variable from result of query - mysql

Is it possible to set a user variable based on the result of a query in MySQL?
What I want to achieve is something like this (we can assume that both USER and GROUP are unique):
set #user = 123456;
set #group = select GROUP from USER where User = #user;
select * from USER where GROUP = #group;
Please note that I know it's possible but I do not wish to do this with nested queries.

Yes, but you need to move the variable assignment into the query:
SET #user := 123456;
SELECT #group := `group` FROM user WHERE user = #user;
SELECT * FROM user WHERE `group` = #group;
Test case:
CREATE TABLE user (`user` int, `group` int);
INSERT INTO user VALUES (123456, 5);
INSERT INTO user VALUES (111111, 5);
Result:
SET #user := 123456;
SELECT #group := `group` FROM user WHERE user = #user;
SELECT * FROM user WHERE `group` = #group;
+--------+-------+
| user | group |
+--------+-------+
| 123456 | 5 |
| 111111 | 5 |
+--------+-------+
2 rows in set (0.00 sec)
Note that for SET, either = or := can be used as the assignment operator. However inside other statements, the assignment operator must be := and not = because = is treated as a comparison operator in non-SET statements.
UPDATE:
Further to comments below, you may also do the following:
SET #user := 123456;
SELECT `group` FROM user LIMIT 1 INTO #group;
SELECT * FROM user WHERE `group` = #group;

Just add parenthesis around the query:
set #user = 123456;
set #group = (select GROUP from USER where User = #user);
select * from USER where GROUP = #group;

First lets take a look at how can we define a variable in mysql
To define a varible in mysql
it should start with '#' like #{variable_name} and this '{variable_name}', we can replace it with our variable name.
Now, how to assign a value in a variable in mysql. For this we have many ways to do that
Using keyword 'SET'.
Example :-
mysql > SET #a = 1;
Without using keyword 'SET' and using ':='.
Example:-
mysql > #a:=1;
By using 'SELECT' statement.
Example:-
mysql > select 1 into #a;
Here #a is user defined variable and 1 is going to be assigned in #a.
Now how to get or select the value of #{variable_name}.
we can use select statement like
Example :-
mysql > select #a;
it will show the output and show the value of #a.
Now how to assign a value from a table in a variable.
For this we can use two statement like :-
1.
#a := (select emp_name from employee where emp_id = 1);
select emp_name into #a from employee where emp_id = 1;
Always be careful emp_name must return single value otherwise it will throw you a error in this type statements.
refer this:-
http://www.easysolutionweb.com/sql-pl-sql/how-to-assign-a-value-in-a-variable-in-mysql

Use this way so that result will not be displayed while running stored procedure.
The query:
SELECT a.strUserID
FROM tblUsers a
WHERE a.lngUserID = lngUserID
LIMIT 1
INTO #strUserID;

Related

iterating over arrays in MYSQL

Is there a way to pass an array into a MySQL query and return the results as another array ?(apart from using cursors which would be an overkill for my use case)
For a single id, my query looks like this.
SET #userId = '04b452cd59dcc656'
Select user_account_number from userstore where u_id = #userId ;
Instead of sending each id at a time, I am trying to send a list and return a list
SET #userId = ('04b452cd59dcc656','eqwe52cddasfsd656');
<query returning the list of account numbers>
Also - I think this would be efficient over just sending one id at a time. Thoughts ?
You can use IN:
select user_account_number
from userstore
where u_id in ('04b452cd59dcc656', 'eqwe52cddasfsd656') ;
Using variables is trickier. If you know a maximum number, you can do:
select user_account_number
from userstore
where u_id in (#id1, #id2);
Not satisfying, but it does the job. Similarly unsatisfying is FIND_IN_SET():
set #ids = '04b452cd59dcc656,eqwe52cddasfsd656';
select user_account_number
from userstore
where find_in_set(u_id, #ids) > 0;
Alas, this won't use an index.
Finally there is dynamic SQL:
set #sql = concat('select user_account_number from userstore where u_id in (''',
replace(ids, ',', ''','''),
''')'
);
prepare s from #sql;
execute s;

SQLserver Store Column as variable and loop through it

I am still pretty new to SQL server and I am not sure how to do this. I am first creating a table with just the IDs I need:
SELECT DISTINCT
ID_NUMBER
INTO
#IDlist
FROM
V_Rpt_IDs WITH (NOLOCK)
WHERE
ID_NUMBER in (
'1000764169'
,'1005870537'
,'1008053856'
,'1008054376'
,'1008410224'
,'1008411317'
,'1008465318'
,'1008466074'
,'1008492967'
,'1010546872'
,'1010554301')
Select * from #IDlist
And this works fine. But now I would like to declare a variable to represent this column, or each item in this column, so that I can then do a loop where it loops through each ID Number and returns information about each one and then presents all of that as a table. Here is my shot at that:
Declare #IDNumber as VARCHAR(10)
Set #IDNumber = #IDlist.ID_NUMBER
DECLARE #cnt INT = 0
WHILE #cnt < (Select Count(*) From #IDlist)
BEGIN
SELECT TOP 1
NAME
,MAILING_ADDRESS_1
,MAILING_ADDRESS_CITY
,MAILING_STATE
,MAILING_ZIP
from
V_Rpt_Info
WHERE
ID_NUMBER = #IDNumber
SET #cnt = #cnt + 1
END
DROP TABLE #IDlist
But when I Set the #IDNumber variable to #IDlist.ID_NUMBER, it says The multi-part identifier "#IDlist.ID_NUMBER" could not be bound.
How do I do this?
Thanks
The way you set the variable is not correct, SQL doesn't know which ID_NUMBER row it should assign to the #IDNumber variable.
You should do this with a SELECT, for example
SET #IDNumber = SELECT TOP 1 ID_NUMBER FROM #IDlist
But, why would you like to loop through this temporary table this way ? Isn't it possible to join the necessary data with this table instead of doing it one by one ?
Rather then loop through, you're going to want to join your ID table to your V_Rpt_Info view.
SELECT
NAME
, MAILING_ADDRESS_1
, MAILING_ADDRESS_CITY
, MAILING_STATE
, MAILING_ZIP
FROM V_Rpt_Info V
INNER JOIN #IDlist ID
ON V.ID_NUMBER = ID.ID_NUMBER

mysql update column then select updated value

I have a table like this
tbl_user
id
user_id
amount
first i want to update a row based on id
$amount = 123; // dyanamic value
$sql = "UPDATE tbl_user SET amount=amount-'$amount' WHERE id='$id' LIMIT 1 ";
now i want to get updated value of amount column i have applied this sql
$sql = "SELECT amount FROM tbl_user WHERE id='$id' LIMIT 1 ";
my question is can i combine both of above sql or any single query to achieve above task?
The best you could imitate is to use two lines of queries, probably using a variable like:
UPDATE tbl_user SET
amount = #amount := amount-'$amount'
WHERE id='$id' LIMIT 1;
SELECT #amount;
The best you could do then is to create a Stored Procedure like:
DELIMITER //
CREATE PROCEDURE `return_amount` ()
BEGIN
UPDATE tbl_user SET
amount = #amount := amount-'$amount'
WHERE id='$id' LIMIT 1;
SELECT #amount;
END //
And then call Stored Procedure in your PHP.
Note: PostgreSQL has this kind of option using RETURNING statement that would look like this:
UPDATE tbl_user SET amount=amount-'$amount'
WHERE id='$id' LIMIT 1
RETURNING amount
See here
A function can do this easily. It sounds like you want to limit how many times your code connects to the database. With a stored function or procedure, you are only making one connection. Yes, the stored function has two queries inside it (update then select), but these are executed on the server side without stopping to do round trips to the client.
http://sqlfiddle.com/#!2/0e6a09/1/0
Here's my skeleton of your table:
CREATE TABLE tbl_user (
id VARCHAR(100) PRIMARY KEY,
user_id VARCHAR(100),
amount DECIMAL(17,4) );
INSERT INTO tbl_user VALUES ('1', 'John', '100.00');
And the proposed function:
CREATE FUNCTION incrementAmount
(p_id VARCHAR(100), p_amount DECIMAL(17,4))
RETURNS DECIMAL(17,4)
BEGIN
UPDATE tbl_user
SET amount = amount + p_amount
WHERE id = p_id;
RETURN (SELECT amount FROM tbl_user WHERE id = p_id);
END
//
Then you just run one query, a SELECT on the function you just created:
SELECT incrementAmount('1', 5.00)
The query result is:
105
It is not possible with a single query, but you can combine multiple commands into a script and execute them with a single request to the database server.
Run this script:
"UPDATE tbl_user SET amount=amount-'$amount' WHERE id='".$id."';SELECT amount FROM tbl_user WHERE id='".$id."'; "
Also, you might want to check whether $id is a number, as I do not see a protection against SQL injection inside your code. SQL injection is a serious threat, you would do better to prepare and protect yourself against it.
We can also use:
UPDATE tbl_user SET id = LAST_INSERT_ID(id), amount = 2.4,user_id=4 WHERE id = 123;
// SELECT
$id =SELECT LAST_INSERT_ID();
SELECT amount,user_id FROM tbl_user WHERE id = $id LIMIT 1
Here would be the procedure
CREATE PROCEDURE UpdateAndSelect
(
#amount MONEY,
#id INT
)
AS
BEGIN
UPDATE tbl_user
SET amount = #amount
WHERE id = #id
LIMIT 1
SELECT amount
FROM tbl_user
WHERE id = #id
LIMIT 1
END
GO
You would call this stored procedure by setting your variables (#amoutn and #id) and then calling:
exec UpdateAndSelect
Hope this helps solve your problem

How can I simulate an array variable in MySQL?

It appears that MySQL doesn't have array variables. What should I use instead?
There seem to be two alternatives suggested: A set-type scalar and temporary tables. The question I linked to suggests the former. But is it good practice to use these instead of array variables? Alternatively, if I go with sets, what would be the set-based idiom equivalent to foreach?
Well, I've been using temporary tables instead of array variables. Not the greatest solution, but it works.
Note that you don't need to formally define their fields, just create them using a SELECT:
DROP TEMPORARY TABLE IF EXISTS my_temp_table;
CREATE TEMPORARY TABLE my_temp_table
SELECT first_name FROM people WHERE last_name = 'Smith';
(See also Create temporary table from select statement without using Create Table.)
You can achieve this in MySQL using WHILE loop:
SET #myArrayOfValue = '2,5,2,23,6,';
WHILE (LOCATE(',', #myArrayOfValue) > 0)
DO
SET #value = ELT(1, #myArrayOfValue);
SET #myArrayOfValue= SUBSTRING(#myArrayOfValue, LOCATE(',',#myArrayOfValue) + 1);
INSERT INTO `EXEMPLE` VALUES(#value, 'hello');
END WHILE;
EDIT:
Alternatively you can do it using UNION ALL:
INSERT INTO `EXEMPLE`
(
`value`, `message`
)
(
SELECT 2 AS `value`, 'hello' AS `message`
UNION ALL
SELECT 5 AS `value`, 'hello' AS `message`
UNION ALL
SELECT 2 AS `value`, 'hello' AS `message`
UNION ALL
...
);
Try using FIND_IN_SET() function of MySql
e.g.
SET #c = 'xxx,yyy,zzz';
SELECT * from countries
WHERE FIND_IN_SET(countryname,#c);
Note: You don't have to SET variable in StoredProcedure if you are passing parameter with CSV values.
Nowadays using a JSON array would be an obvious answer.
Since this is an old but still relevant question I produced a short example.
JSON functions are available since mySQL 5.7.x / MariaDB 10.2.3
I prefer this solution over ELT() because it's really more like an array and this 'array' can be reused in the code.
But be careful: It (JSON) is certainly much slower than using a temporary table. Its just more handy. imo.
Here is how to use a JSON array:
SET #myjson = '["gmail.com","mail.ru","arcor.de","gmx.de","t-online.de",
"web.de","googlemail.com","freenet.de","yahoo.de","gmx.net",
"me.com","bluewin.ch","hotmail.com","hotmail.de","live.de",
"icloud.com","hotmail.co.uk","yahoo.co.jp","yandex.ru"]';
SELECT JSON_LENGTH(#myjson);
-- result: 19
SELECT JSON_VALUE(#myjson, '$[0]');
-- result: gmail.com
And here a little example to show how it works in a function/procedure:
DELIMITER //
CREATE OR REPLACE FUNCTION example() RETURNS varchar(1000) DETERMINISTIC
BEGIN
DECLARE _result varchar(1000) DEFAULT '';
DECLARE _counter INT DEFAULT 0;
DECLARE _value varchar(50);
SET #myjson = '["gmail.com","mail.ru","arcor.de","gmx.de","t-online.de",
"web.de","googlemail.com","freenet.de","yahoo.de","gmx.net",
"me.com","bluewin.ch","hotmail.com","hotmail.de","live.de",
"icloud.com","hotmail.co.uk","yahoo.co.jp","yandex.ru"]';
WHILE _counter < JSON_LENGTH(#myjson) DO
-- do whatever, e.g. add-up strings...
SET _result = CONCAT(_result, _counter, '-', JSON_VALUE(#myjson, CONCAT('$[',_counter,']')), '#');
SET _counter = _counter + 1;
END WHILE;
RETURN _result;
END //
DELIMITER ;
SELECT example();
Dont know about the arrays, but there is a way to store comma-separated lists in normal VARCHAR column.
And when you need to find something in that list you can use the FIND_IN_SET() function.
I know that this is a bit of a late response, but I recently had to solve a similar problem and thought that this may be useful to others.
Background
Consider the table below called 'mytable':
The problem was to keep only latest 3 records and delete any older records whose systemid=1 (there could be many other records in the table with other systemid values)
It would be good if you could do this simply using the statement
DELETE FROM mytable WHERE id IN (SELECT id FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3)
However this is not yet supported in MySQL and if you try this then you will get an error like
...doesn't yet support 'LIMIT & IN/ALL/SOME subquery'
So a workaround is needed whereby an array of values is passed to the IN selector using variable. However, as variables need to be single values, I would need to simulate an array. The trick is to create the array as a comma separated list of values (string) and assign this to the variable as follows
SET #myvar = (SELECT GROUP_CONCAT(id SEPARATOR ',') AS myval FROM (SELECT * FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3 ) A GROUP BY A.systemid);
The result stored in #myvar is
5,6,7
Next, the FIND_IN_SET selector is used to select from the simulated array
SELECT * FROM mytable WHERE FIND_IN_SET(id,#myvar);
The combined final result is as follows:
SET #myvar = (SELECT GROUP_CONCAT(id SEPARATOR ',') AS myval FROM (SELECT * FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3 ) A GROUP BY A.systemid);
DELETE FROM mytable WHERE FIND_IN_SET(id,#myvar);
I am aware that this is a very specific case. However it can be modified to suit just about any other case where a variable needs to store an array of values.
I hope that this helps.
DELIMITER $$
CREATE DEFINER=`mysqldb`#`%` PROCEDURE `abc`()
BEGIN
BEGIN
set #value :='11,2,3,1,';
WHILE (LOCATE(',', #value) > 0) DO
SET #V_DESIGNATION = SUBSTRING(#value,1, LOCATE(',',#value)-1);
SET #value = SUBSTRING(#value, LOCATE(',',#value) + 1);
select #V_DESIGNATION;
END WHILE;
END;
END$$
DELIMITER ;
Maybe create a temporary memory table with columns (key, value) if you want associative arrays. Having a memory table is the closest thing to having arrays in mysql
Here’s how I did it.
First, I created a function that checks whether a Long/Integer/whatever value is in a list of values separated by commas:
CREATE DEFINER = 'root'#'localhost' FUNCTION `is_id_in_ids`(
`strIDs` VARCHAR(255),
`_id` BIGINT
)
RETURNS BIT(1)
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE strLen INT DEFAULT 0;
DECLARE subStrLen INT DEFAULT 0;
DECLARE subs VARCHAR(255);
IF strIDs IS NULL THEN
SET strIDs = '';
END IF;
do_this:
LOOP
SET strLen = LENGTH(strIDs);
SET subs = SUBSTRING_INDEX(strIDs, ',', 1);
if ( CAST(subs AS UNSIGNED) = _id ) THEN
-- founded
return(1);
END IF;
SET subStrLen = LENGTH(SUBSTRING_INDEX(strIDs, ',', 1));
SET strIDs = MID(strIDs, subStrLen+2, strLen);
IF strIDs = NULL or trim(strIds) = '' THEN
LEAVE do_this;
END IF;
END LOOP do_this;
-- not founded
return(0);
END;
So now you can search for an ID in a comma-separated list of IDs, like this:
select `is_id_in_ids`('1001,1002,1003',1002);
And you can use this function inside a WHERE clause, like this:
SELECT * FROM table1 WHERE `is_id_in_ids`('1001,1002,1003',table1_id);
This was the only way I found to pass an "array" parameter to a PROCEDURE.
I'm surprised none of the answers mention ELT/FIELD.
ELT/FIELD works very similar to an array especially if you have static data.
FIND_IN_SET also works similar but doesn't have a built in complementary
function but it's easy enough to write one.
mysql> select elt(2,'AA','BB','CC');
+-----------------------+
| elt(2,'AA','BB','CC') |
+-----------------------+
| BB |
+-----------------------+
1 row in set (0.00 sec)
mysql> select field('BB','AA','BB','CC');
+----------------------------+
| field('BB','AA','BB','CC') |
+----------------------------+
| 2 |
+----------------------------+
1 row in set (0.00 sec)
mysql> select find_in_set('BB','AA,BB,CC');
+------------------------------+
| find_in_set('BB','AA,BB,CC') |
+------------------------------+
| 2 |
+------------------------------+
1 row in set (0.00 sec)
mysql> SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('AA,BB,CC',',',2),',',-1);
+-----------------------------------------------------------+
| SUBSTRING_INDEX(SUBSTRING_INDEX('AA,BB,CC',',',2),',',-1) |
+-----------------------------------------------------------+
| BB |
+-----------------------------------------------------------+
1 row in set (0.01 sec)
Is an array variable really necessary?
I ask because I originally landed here wanting to add an array as a MySQL table variable. I was relatively new to database design and trying to think of how I'd do it in a typical programming language fashion.
But databases are different. I thought I wanted an array as a variable, but it turns out that's just not a common MySQL database practice.
Standard Practice
The alternative solution to arrays is to add an additional table, and then reference your original table with a foreign key.
As an example, let's imagine an application that keeps track of all the items every person in a household wants to buy at the store.
The commands for creating the table I originally envisioned would have looked something like this:
#doesn't work
CREATE TABLE Person(
name VARCHAR(50) PRIMARY KEY
buy_list ARRAY
);
I think I envisioned buy_list to be a comma-separated string of items or something like that.
But MySQL doesn't have an array type field, so I really needed something like this:
CREATE TABLE Person(
name VARCHAR(50) PRIMARY KEY
);
CREATE TABLE BuyList(
person VARCHAR(50),
item VARCHAR(50),
PRIMARY KEY (person, item),
CONSTRAINT fk_person FOREIGN KEY (person) REFERENCES Person(name)
);
Here we define a constraint named fk_person. It says that the 'person' field in BuyList is a foreign key. In other words, it's a primary key in another table, specifically the 'name' field in the Person table, which is what REFERENCES denotes.
We also defined the combination of person and item to be the primary key, but technically that's not necessary.
Finally, if you want to get all the items on a person's list, you can run this query:
SELECT item FROM BuyList WHERE person='John';
This gives you all the items on John's list. No arrays necessary!
This is my solution to use a variable containing a list of elements.
You can use it in simple queries (no need to use store procedures or create tables).
I found somewhere else on the site the trick to use the JSON_TABLE function (it works in mysql 8, I dunno of it works in other versions).
set #x = '1,2,3,4' ;
select c.NAME
from colors c
where
c.COD in (
select *
from json_table(
concat('[',#x,']'),
'$[*]' columns (id int path '$') ) t ) ;
Also, you may need to manage the case of one or more variables set to empty_string.
In this case I added another trick (the query does not return error even if x, y, or both x and y are empty strings):
set #x = '' ;
set #y = 'yellow' ;
select c.NAME
from colors
where
if(#y = '', 1 = 1, c.NAME = #y)
and if(#x = '', 1, c.COD) in (
select *
from json_table(
concat('[',if(#x = '', 1, #x),']'),
'$[*]' columns (id int path '$') ) t) ;
This works fine for list of values:
SET #myArrayOfValue = '2,5,2,23,6,';
WHILE (LOCATE(',', #myArrayOfValue) > 0)
DO
SET #value = ELT(1, #myArrayOfValue);
SET #STR = SUBSTRING(#myArrayOfValue, 1, LOCATE(',',#myArrayOfValue)-1);
SET #myArrayOfValue = SUBSTRING(#myArrayOfValue, LOCATE(',', #myArrayOfValue) + 1);
INSERT INTO `Demo` VALUES(#STR, 'hello');
END WHILE;
Both versions using sets didn't work for me (tested with MySQL 5.5). The function ELT() returns the whole set. Considering the WHILE statement is only avaible in PROCEDURE context i added it to my solution:
DROP PROCEDURE IF EXISTS __main__;
DELIMITER $
CREATE PROCEDURE __main__()
BEGIN
SET #myArrayOfValue = '2,5,2,23,6,';
WHILE (LOCATE(',', #myArrayOfValue) > 0)
DO
SET #value = LEFT(#myArrayOfValue, LOCATE(',',#myArrayOfValue) - 1);
SET #myArrayOfValue = SUBSTRING(#myArrayOfValue, LOCATE(',',#myArrayOfValue) + 1);
END WHILE;
END;
$
DELIMITER ;
CALL __main__;
To be honest, i don't think this is a good practice. Even if its realy necessary, this is barely readable and quite slow.
Isn't the point of arrays to be efficient? If you're just iterating through values, I think a cursor on a temporary (or permanent) table makes more sense than seeking commas, no? Also cleaner. Lookup "mysql DECLARE CURSOR".
For random access a temporary table with numerically indexed primary key. Unfortunately the fastest access you'll get is a hash table, not true random access.
Another way to see the same problem.
Hope helpfull
DELIMITER $$
CREATE PROCEDURE ARR(v_value VARCHAR(100))
BEGIN
DECLARE v_tam VARCHAR(100);
DECLARE v_pos VARCHAR(100);
CREATE TEMPORARY TABLE IF NOT EXISTS split (split VARCHAR(50));
SET v_tam = (SELECT (LENGTH(v_value) - LENGTH(REPLACE(v_value,',',''))));
SET v_pos = 1;
WHILE (v_tam >= v_pos)
DO
INSERT INTO split
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(v_value,',',v_pos),',', -1);
SET v_pos = v_pos + 1;
END WHILE;
SELECT * FROM split;
DROP TEMPORARY TABLE split;
END$$
CALL ARR('1006212,1006404,1003404,1006505,444,');
If we have one table like that
mysql> select * from user_mail;
+------------+-------+
| email | user |
+------------+-------+-
| email1#gmail | 1 |
| email2#gmail | 2 |
+------------+-------+--------+------------+
and the array table:
mysql> select * from user_mail_array;
+------------+-------+-------------+
| email | user | preferences |
+------------+-------+-------------+
| email1#gmail | 1 | 1 |
| email1#gmail | 1 | 2 |
| email1#gmail | 1 | 3 |
| email1#gmail | 1 | 4 |
| email2#gmail | 2 | 5 |
| email2#gmail | 2 | 6 |
We can select the rows of the second table as one array with CONCAT function:
mysql> SELECT t1.*, GROUP_CONCAT(t2.preferences) AS preferences
FROM user_mail t1,user_mail_array t2
where t1.email=t2.email and t1.user=t2.user
GROUP BY t1.email,t1.user;
+------------+-------+--------+------------+-------------+
| email | user | preferences |
+------------+-------+--------+------------+-------------+
|email1#gmail | 1 | 1,3,2,4 |
|email2#gmail | 2 | 5,6 |
+------------+-------+--------+------------+-------------+
In MYSQL version after 5.7.x, you can use JSON type to store an array. You can get value of an array by a key via MYSQL.
Inspired by the function ELT(index number, string1, string2, string3,…),I think the following example works as an array example:
set #i := 1;
while #i <= 3
do
insert into table(val) values (ELT(#i ,'val1','val2','val3'...));
set #i = #i + 1;
end while;
Hope it help.
Here is an example for MySQL for looping through a comma delimited string.
DECLARE v_delimited_string_access_index INT;
DECLARE v_delimited_string_access_value VARCHAR(255);
DECLARE v_can_still_find_values_in_delimited_string BOOLEAN;
SET v_can_still_find_values_in_delimited_string = true;
SET v_delimited_string_access_index = 0;
WHILE (v_can_still_find_values_in_delimited_string) DO
SET v_delimited_string_access_value = get_from_delimiter_split_string(in_array, ',', v_delimited_string_access_index); -- get value from string
SET v_delimited_string_access_index = v_delimited_string_access_index + 1;
IF (v_delimited_string_access_value = '') THEN
SET v_can_still_find_values_in_delimited_string = false; -- no value at this index, stop looping
ELSE
-- DO WHAT YOU WANT WITH v_delimited_string_access_value HERE
END IF;
END WHILE;
this uses the get_from_delimiter_split_string function defined here: https://stackoverflow.com/a/59666211/3068233
I Think I can improve on this answer. Try this:
The parameter 'Pranks' is a CSV. ie. '1,2,3,4.....etc'
CREATE PROCEDURE AddRanks(
IN Pranks TEXT
)
BEGIN
DECLARE VCounter INTEGER;
DECLARE VStringToAdd VARCHAR(50);
SET VCounter = 0;
START TRANSACTION;
REPEAT
SET VStringToAdd = (SELECT TRIM(SUBSTRING_INDEX(Pranks, ',', 1)));
SET Pranks = (SELECT RIGHT(Pranks, TRIM(LENGTH(Pranks) - LENGTH(SUBSTRING_INDEX(Pranks, ',', 1))-1)));
INSERT INTO tbl_rank_names(rank)
VALUES(VStringToAdd);
SET VCounter = VCounter + 1;
UNTIL (Pranks = '')
END REPEAT;
SELECT VCounter AS 'Records added';
COMMIT;
END;
This method makes the searched string of CSV values progressively shorter with each iteration of the loop, which I believe would be better for optimization.
I would try something like this for multiple collections. I'm a MySQL beginner. Sorry about the function names, couldn't decide on what names would be best.
delimiter //
drop procedure init_
//
create procedure init_()
begin
CREATE TEMPORARY TABLE if not exists
val_store(
realm varchar(30)
, id varchar(30)
, val varchar(255)
, primary key ( realm , id )
);
end;
//
drop function if exists get_
//
create function get_( p_realm varchar(30) , p_id varchar(30) )
returns varchar(255)
reads sql data
begin
declare ret_val varchar(255);
declare continue handler for 1146 set ret_val = null;
select val into ret_val from val_store where id = p_id;
return ret_val;
end;
//
drop procedure if exists set_
//
create procedure set_( p_realm varchar(30) , p_id varchar(30) , p_val varchar(255) )
begin
call init_();
insert into val_store (realm,id,val) values (p_realm , p_id , p_val) on duplicate key update val = p_val;
end;
//
drop procedure if exists remove_
//
create procedure remove_( p_realm varchar(30) , p_id varchar(30) )
begin
call init_();
delete from val_store where realm = p_realm and id = p_id;
end;
//
drop procedure if exists erase_
//
create procedure erase_( p_realm varchar(30) )
begin
call init_();
delete from val_store where realm = p_realm;
end;
//
call set_('my_array_table_name','my_key','my_value');
select get_('my_array_table_name','my_key');
Rather than Saving data as a array or in one row only you should be making diffrent rows for every value received. This will make it much simpler to understand rather than putting all together.
Have you tried using PHP's serialize()?
That allows you to store the contents of a variable's array in a string PHP understands and is safe for the database (assuming you've escaped it first).
$array = array(
1 => 'some data',
2 => 'some more'
);
//Assuming you're already connected to the database
$sql = sprintf("INSERT INTO `yourTable` (`rowID`, `rowContent`) VALUES (NULL, '%s')"
, serialize(mysql_real_escape_string($array, $dbConnection)));
mysql_query($sql, $dbConnection) or die(mysql_error());
You can also do the exact same without a numbered array
$array2 = array(
'something' => 'something else'
);
or
$array3 = array(
'somethingNew'
);

Chaining SQL queries

Right now I'm running
SELECT formula('FOO') FROM table1
WHERE table1.foo = 'FOO' && table1.bar = 'BAR';
but I would like to run this not on the constant FOO but on each value from the query
SELECT foos FROM table2
WHERE table2.bar = 'BAR';
How can I do this?
Edit: Important change: added FOO to the arguments of function.
Illustration:
SELECT foo FROM table1 WHERE foo = 'FOO' && table1.bar = 'BAR';
gives a column with FOOa, FOOb, FOOc.
SELECT formula('FOO') FROM table1
WHERE table1.foo = 'FOO' && table1.bar = 'BAR';
gives a single entry, say sum(FOO) (actually much more complicated, but it uses aggregates at some point to combine the results).
I want some query which gives a column with sum(FOO1), sum(FOO2), ... where each FOOn is computed in like manner to FOO. But I'd like to do this with one query rather than n queries (because n may be large and in any case the particular values of FOOn vary from case to case).
Try this one:
SELECT formula FROM table1
WHERE table1.foo IN(SELECT foos FROM table2
WHERE table2.bar = 'BAR';
) AND table1.bar = 'BAR';
SELECT formula FROM table1 WHERE bar = 'BAR' AND foo IN (SELECT foos FROM table2 WHERE bar = 'BAR');
EDIT:
This isn't tested, but perhaps this will work?
SELECT formula(q1.foo) FROM table1 INNER JOIN (SELECT foo, bar FROM table2) q1 ON table1.foo = q1.foo WHERE table1.bar = 'BAR';
You will have to use dynamic SQL statements.
The way this works is that you just string the SQL statement together using parameters.
You will need to be careful though not to allow users to feed that data, because escaping cannot protect you against SQL-injection. You will need to check every column name against a whitelist.
Here's example code in a stored procedure.
The way this works, is that you have a (temporary) table with column names and the stored procedure builds this into a query:
dynamic /*holds variable parts of an SQL statement
-----------
id integer PK
column_name varchar(255)
operation ENUM('what','from','where','group by','having','order by','limit')
function_name varchar(255) /*function desc with a '#' placeholder where */
/* the column-name goes */
whitelist /*holds all allowed column names*/
-----------
id integer PK
allowed varchar(255) /*allowed column of table name*/
item ENUM('column','table')
Dynamic SQL stored procedure. Expects two tables: dynamic and whitelist to be prefilled.
DELIMITER $$
CREATE PROCEDURE dynamic_example;
BEGIN
DECLARE vwhat VARCHAR(65000);
DECLARE vfrom VARCHAR(65000);
DECLARE vwhere VARCHAR(65000);
DECLARE vQuery VARCHAR(65000);
SELECT group_concat(REPLACE(function_name,'#',column_name)) INTO vwhat
FROM dynamic
INNER JOIN whitelist wl ON (wl.allowed LIKE column_name
AND wl.item = 'column')
WHERE operation = 'what' AND
SELECT group_concat(REPLACE(function_name,'#',column_name)) INTO vfrom
FROM dynamic
INNER JOIN whitelist wl ON (wl.allowed LIKE column_name
AND wl.item = 'table')
WHERE operation = 'from';
SELECT group_concat(REPLACE(function_name,'#',column_name)) INTO vwhere
FROM dynamic
INNER JOIN whitelist wl ON (wl.allowed LIKE column_name
AND wl.item = 'column')
WHERE operation = 'where';
IF vwhat IS NULL THEN SET vwhat = ' * ';
IF vwhere IS NOT NULL THEN SET vwhere = CONCAT(' WHERE ',vwhere); END IF;
SET vQuery = CONCAT(' SELECT ',vwhat,' FROM ',vfrom,IFNULL(vwhere,''));
PREPARE dSQL FROM vQuery;
EXECUTE dSQL;
DEALLOCATE PREPARE dSQL;
END $$
DELIMITER ;
Try:
SELECT formula FROM table1, table2
WHERE table1.foo = table2.foo AND table1.bar = table2.bar;