Mysql: user defined variable in Insert statement - mysql

I am trying to use following mysql code to insert on column whose name is decided on some value. It gives me error that "some_percent" unknown column 'some_percent' in 'field list'
set #SplitState = `some_percent`;
SET #ID = uuid();
INSERT INTO `rspca_donations`(`id`, `#SplitState`) values (#ID, '100');
Can someone please suggest correct way?

You can't use a user variable to represent a column name in this way. One option here would be to use a prepared statement in MySQL:
SET #SplitState = 'some_percent';
SET #ID = UUID();
SET #sql = CONCAT('INSERT INTO rspca_donations (id, ', #SplitState, ') VALUES (?, 100)');
PREPARE stmt FROM #sql;
EXECUTE stmt USING #ID;

Related

Composing a dynamic query in a stored procedure in MYSQL

I am creating a stored procedure in MySQL in order to execute the same queries in several parts of my application.
One of the two tables, as you can guess from the code, will be different depending on the script that will execute the stored procedure. The fields of the second query will be the same in number and type. The name of the table and the name of a column will change.
In order to make a dynamic query, I have used the CONCAT() command but I don't like it very much because it contains too many fragmented parts and too many quotes. Is there a more elegant way to compose a dynamic query like this?
BEGIN
INSERT IGNORE INTO tag (cod, tag) values (cod_tag_in, tag_in);
SET #query = CONCAT("INSERT INTO ", table_in, " (cod, ", table_field_in, ", tag_cod) values ('", app_cod_in, "','", section_cod_in, "', (SELECT cod FROM tag WHERE tag = '", tag_in, "'))");
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
Here is how I would write this routine if the table name and field name are really dynamic:
BEGIN
INSERT IGNORE INTO tag (cod, tag) values (cod_tag_in, tag_in);
SET #query = CONCAT('INSERT INTO `', table_in, '` (cod, `', table_field_in, '`, tag_cod) values (?, ?, ?)');
SET #cod = app_cod_in, #field = section_code_in, #tag_cod = cod_tag_in;
PREPARE stmt FROM #query;
EXECUTE stmt USING #cod, #field, #tag_cod;
DEALLOCATE PREPARE stmt;
END
Use query parameters so you don't have to use all those meticulous quotes for the values. This also protects you in case the values themselves contain quote characters.
I don't see the need for the subquery, since the value you just inserted in the the tag table should be the same as cod_tag_in anyway.
You do need the breaks in quotes for the dynamic table name and dynamic field name, because you can't use parameters as table or column identifiers.
I put back-ticks around the table and field name, just in case these identifiers require them (conflict with SQL reserved keywords, contain whitespace or punctuation, etc.).
However, you shouldn't even use dynamic SQL for this at all. You should use a CASE statement for the tables you need to support:
BEGIN
INSERT IGNORE INTO tag (cod, tag) values (cod_tag_in, tag_in);
CASE table_in
WHEN 'mytable1' THEN
INSERT INTO mytable1 (cod, myfield1, tag_cod) VALUES (app_cod_in, section_code_in, cod_tag_in);
WHEN 'mytable2' THEN
INSERT INTO mytable2 (cod, myfield2, tag_cod) VALUES (app_cod_in, section_code_in, cod_tag_in);
WHEN 'mytable3' THEN
INSERT INTO mytable3 (cod, myfield3, tag_cod) VALUES (app_cod_in, section_code_in, cod_tag_in);
ELSE
SIGNAL SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Unknown table';
END CASE;
END
This means you don't have to worry about CONCAT()-ing any fragments of SQL, and you don't have to worry about SQL injection risks, and you don't have to worry about table or column identifiers that have conflicting characters.
But you are limited to the tables you have coded in the CASE statement. If you are in the habit of creating new tables on the fly frequently, you'd have to replace the stored procedure with longer and longer CASE statements. But if you need to do that, I'd reconsider the design that so frequently requires new tables of similar structure.

JSON_EXTRACT as VALUES for INSERT INTO?

I expect the following MySQL code:
SET #json= '{"1":{"name":"Name","value":"James Bowery","id":1,"type":"name","first":"James","middle":"","last":"Bowery"},"2":{"name":"Birthdate","value":"06\/23\/2017","id":2,"type":"date-time","date":"06\/23\/2017","time":"","unix":1498176000},"3":{"name":"Gender","value":"Male","value_raw":"Male","id":3,"type":"radio"},"4":{"name":"Ethnicity","value":"European","value_raw":"European","id":4,"type":"radio"},"5":{"name":"Email","value":"jabowery#emailservice.com","id":5,"type":"text"}}';
SET #array = JSON_EXTRACT( #json, '$."1".first','$."1".last','$."5".value','$."2".value','$."3".value','$."4".value');
INSERT INTO user (firstname,lastname,birthdate,gender,ethnicity,email) VALUES (#array);
To insert a row into the user table populated by the named fields extracted from the JSON. However, the INSERT yields a syntax error. What is the proper syntax?
Perhaps try this. Note that I have changed the date format to yyyy-MM-dd. You will need to work on converting this programatically to fit to MySQL. Also, when I ran this, the array had email before birthdate, so I changed the sequence of insert.
SET #json= '{"1":{"name":"Name","value":"James Bowery","id":1,"type":"name","first":"James","middle":"","last":"Bowery"},"2":{"name":"Birthdate","value":"06\/23\/2017","id":2,"type":"date-time","date":"2017-06-23","time":"","unix":1498176000},"3":{"name":"Gender","value":"Male","value_raw":"Male","id":3,"type":"radio"},"4":{"name":"Ethnicity","value":"European","value_raw":"European","id":4,"type":"radio"},"5":{"name":"Email","value":"jabowery#emailservice.com","id":5,"type":"text"}}';
SET #array = JSON_EXTRACT( #json, '$."1".first','$."1".last','$."5".value','$."2".value','$."3".value','$."4".value');
SET #queryString= CONCAT( 'INSERT INTO user (firstname,lastname,email,birthdate,gender,ethnicity) VALUES (',REPLACE(REPLACE(#array, '[',''),']',''),')');
PREPARE stmt FROM #queryString;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

MySQL prepared statement nvarchar

I have a prepared statement which should update an field.
CREATE PROCEDURE `update_table` (in id INT, in col nvarchar(11), in val nvarchar(10))
BEGIN
SET #sql = concat('UPDATE table SET ', col, ' = ', val , ' WHERE id = ', id);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
If I call the procedure with a string containing a hyphen (e.g. A-B)
CALL update_table(1, 'reg', 'A-B');
I get
Error 1054: Unknown column 'A' in 'field list'
Can you please assist in solving the issue?
Edit: I just figuered out the hyphen is not the cause of error. If I try to update with 'AB', the same error comes up.
The field to be updated is nvarchar as well with the same field length.
You're vulnerable to sql injection attacks, basically. Your sproc generated this sql:
UPDATE ... WHERE reg = A-B
Note the lack of quotes around A-B. You're not storing the string A-B in the reg field. You're doing mathematical subtraction: reg = A minus B, and neither A nor B are fields that exist in your table.
At BARE minimum you'd need:
SET #sql = concat('UPDATE table SET ', col, ' = "', val , '" WHERE id = ', id);
^----------^
so you're generating
UPDATE ... reg = "A-B"

MySQL: Match against dynamic values

I have a list of values in a table column that I need to match against table names, preferably just using an SQL statement.
If the values were static, I suppose the SELECT statement would be something like this:
SELECT table_name FROM information_schema.TABLES WHERE
match(table_name) against('124512' +'36326' +'23636' IN BOOLEAN MODE)
However, I need to match against dynamic values coming from a SELECT statement:
SELECT tableid FROM databaseName.tableOverviewTableName
WHERE template = 'templateName')
The tableid above is contained in the table_name for the tables that I want.
Is this possible to achieve with an SQL statement?
You can do this via Prepared statement (not directly via a query)
SET #tq = (SELECT tableid FROM databaseName.tableOverviewTableName WHERE template = 'templateName'));
SET #stmq = CONCAT('SELECT * FROM ', #tq);
Prepare stmt FROM #stmq;
Execute stmt;
DEALLOCATE PREPARE stmt;

Using selects within MySQL Stored Procedures

I have stored procedure in my database and i need to look up a table and cross reference an id, then using the returned row i need to insert information into another table, but i cant seem to use the infomation from the lookup into the insert. This is what i have..
BEGIN
#Routine body goes here...
SET #UID = uid;
SET #UIDTOFB = uid_to;
SET #SQLTEST = CONCAT('SELECT users.user_auto_id FROM users WHERE users.user_fb_uid= #UIDTOFB LIMIT 1');
PREPARE sqlcmd from #SQLTEST;
EXECUTE sqlcmd;
INSERT INTO challenges(challenge_from_uid, challenge_to_uid, challenge_dateadded) VALUES(#UID, #SQLTEST.users.user_auto_id, now());
SET #LASTID = LAST_INSERT_ID();
SELECT #LASTID as id;
END
any help would be much appreciated!
This won't insert the value of #UIDTOFB since you missed some '. It takes this whole statement as one string and therefore the statement fails.
SET #SQLTEST = CONCAT('SELECT users.user_auto_id FROM users WHERE users.user_fb_uid= #UIDTOFB LIMIT 1');
PREPARE sqlcmd from #SQLTEST;
EXECUTE sqlcmd;
Anyway I'd recommend you use parameters like this:
PREPARE sqlcmd from 'SELECT users.user_auto_id FROM users WHERE users.user_fb_uid= ? LIMIT 1';
EXECUTE sqlcmd USING #UIDTOFB;
You can read more about it here in the manual.
UPDATE: Now I get, what you want to do. Do it simply like this:
SELECT #anyVariable:=users.user_auto_id FROM users WHERE users.user_fb_uid= #UIDTOFB LIMIT 1;
INSERT INTO challenges(challenge_from_uid, challenge_to_uid, challenge_dateadded) VALUES(#UID, #anyVariable, now());