Parameterized nested query - mysql

I'm trying to parameterize the following insert with a nested select.
INSERT IGNORE INTO table1 (creation_timestamp, str1, str2)
(SELECT now(), "param1", str2 FROM table2 WHERE key = "param2");
I'd like something like
INSERT IGNORE INTO table1 (creation_timestamp, str1, str2)
(SELECT now(), ?, str2 FROM table2 WHERE key = ?)
VALUES ("param1", "param2");
Anyone know how I can accomplish something like this?

Not exactly the same, but very similar.
You can use prepared statements:
http://dev.mysql.com/doc/refman/5.7/en/sql-syntax-prepared-statements.html
Example:
PREPARE soExample
FROM 'INSERT
INTO usr (id, username, profile_pic)
VALUES (NULL, ?, (SELECT name
FROM customers
WHERE id = ?
LIMIT 1))';
SET #uname = "someUserNameForTheExample";
SET #id = "1";
EXECUTE soExample USING #uname, #id;
Or you can user procedure or/and functions as well
FUNCTION
DROP FUNCTION IF EXISTS insertExample$$
CREATE FUNCTION insertExample(userNameVar VARCHAR(255), uID INT(11)) RETURNS BOOLEAN
BEGIN
INSERT
INTO usr (id, username, profile_pic)
VALUES (NULL, userNameVar, (SELECT name
FROM customers
WHERE id = uID
LIMIT 1));
IF ROW_COUNT() > 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END$$
FUNCTION USE
SELECT insertExample("SomeUsername" 2);

Perhaps you should start by reading https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html. As Mysql Functions enables parameterized input for pre-build queries.

Related

MySql Function inside stored procedure

Is that possible to write a function inside MySql stored procedure?
I have set of queries like this.
INSERT INTO party (Description, ShortName)
SELECT CompanyName, NULL FROM tempParentSource;
SET #PartyID = LAST_INSERT_ID();
INSERT INTO partyrole (PartyID,RoleTypeID)
SELECT #PartyID , 5;
SET #ParentSourcePartyRoleID = LAST_INSERT_ID();
-- insert parentSource table
INSERT INTO parentsource (OrgPartyRoleID, CompanyName, ContactNumber, ContactName, ContactEmail, Ext, ContactTelephone)
SELECT #ParentSourcePartyRoleID , CompanyName, ContactPhone, ContactName, ContactEmail, Ext, ContactTelephone FROM tempParentSource;
SET #ParentSourceID = LAST_INSERT_ID();
There are few conditions to check and execute given set of queries. Following are the conditions
IF (#ParentSourceID IS NOT NULL AND #ParentSourcePartyRoleID != #CurOrgPartyID)
ELSEIF (#ParentSourceID IS NULL AND #ParentSourcePartyRoleID IS NOT NULL)
ELSEIF (#ParentSourcePartyRoleID IS NULL AND #CompanyName IS NOT NULL)
Inside of these conditions, i need to execute above given set of queries. Instead of repeating those queries inside each and every condition. If that is possible, how can i write a function and call inside those conditions?

Alias a mysql table for a session?

I know you can give an alias to a table for a query, like SELECT 1 FROM table AS t but is there a way to give an alias to a table for a session?
The use case is I have a "query pattern" that should apply to 3 different tables. So I would like to make only one query, using a table alias, and then tell mysql "Execute this query considering that is alias is table1, then execute the same query considering the alias is table2,..."
The use case:
INSERT INTO aliasedTable (id, value) VALUES (1,1)
The tables
CREATE TABLE table1 (id INT UNSIGNED, value TINYINT UNSIGNED)
CREATE TABLE table2 (id INT UNSIGNED, value TINYINT UNSIGNED)
CREATE TABLE table3 (id INT UNSIGNED, value TINYINT UNSIGNED)
The "supposed" syntax
ALIAS table1 AS aliasedTable;
INSERT INTO aliasedTable (id, value) VALUES (1,1)
ALIAS table2 AS aliasedTable;
INSERT INTO aliasedTable (id, value) VALUES (1,1)
ALIAS table3 AS aliasedTable;
INSERT INTO aliasedTable (id, value) VALUES (1,1)
What I thought of, is making a updatable VIEW of the table, but there is no such thing like CREATE TEMPORARY VIEW .... And using a CREATE TEMPORARY TABLE aliasedTable AS (SELECT * FROM table1) would create a table copy, instead of inserting in the original table.
Any suggestion?
Note that I have such case in a PHP code, but also in a procedure:
<?php
$query = 'INSERT INTO aliasedTable (id, value) VALUES (1,1)';
foreach (array('table1', 'table2', 'table3') AS $t) {
// Ideally, I would like to avoid string concat here and tell MySQL
// something like 'ALIAS :placeholder AS aliasedTable', ['placeholder' => $t]
$pdo->query('ALIAS ' . $table1 . ' AS aliasedTable');
$pdo->query($query);
}
or
SET #tables := '["table1","table2","table3"]';
SET #i := JSON_LENGTH(#tables) - 1;
WHILE (#i >= 0) DO
SET #table := JSON_UNQUOTE(JSON_EXTRACT(#tables, CONCAT('$[', #i, ']')));
ALIAS #table AS aliasedTable;
CALL inserting();
SET #i := #i - 1;
END WHILE;
where
CREATE PROCEDURE inserting()
BEGIN
INSERT INTO aliasedTable (id, value) VALUES (1, 1);
END$$
One thing that you could do is switch to a dynamic SQL statement and pass the table name as an input argument to the inserting function:
CREATE PROCEDURE inserting( IN tbl_name VARCHAR(25) )
BEGIN
SET #stmt = CONCAT('INSERT INTO ', tbl_name, ' (id, value) VALUES (1, 1)');
PREPARE stmt FROM #stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
Depending on your call this will insert data to appropriate table. As an example:
CALL inserting('table1');
will execute following statement:
INSERT INTO table1 (id, value) VALUES (1,1);
Then from PHP you could call this procedure for each element in your array passing the current element as an argument to the function.

How to handle concurrency using SELECT?

I need to validate if a record already exists. The portion, in the stored procedure, that does that is:
SELECT EXISTS (SELECT 1 FROM MyTable
WHERE FirstName = #FirstName
AND LastName = #LastName
AND Address = #Address)
BEGIN
SET #IsNewRecord = 1
END
IF #IsNewRecord = 1
BEGIN
INSERT INTO MyTable
VALUES (#FirtName, #LastName, #Addres, #City, #Phone)
END
That works fine, the issue is when the stored procedure is called by several clients at the same time, it will return the #IsNewRecord = 1.
I already tried surrounding the validation among a TRANSACTION BLOCK, but it still creates a new record.
How can I handle concurrency when using SELECT?
do like this
begin transaction
SELECT EXISTS (SELECT 1 FROM MyTable WHERE FirstName = #FirstName AND LastName = #LastName
AND Address = #Address)
BEGIN
INSERT INTO MyTable
VALUES (#FirtName, #LastName, #Addres, #City, #Phone)
END
commit

During Update Perform For Each On Last Insert ID

I have a very simple procedure which performs an update on multiple rows. Is their a way I can loop through the insert id of each updated row?
BEGIN
UPDATE testTable set testValue = 2
where username = inputUser and flag = 1;
//for each update performed, insert LAST_INSERT_ID() into tableB
END
is this possible? If so, can you lead me in the right direction?
LAST_INSERT_ID only gives you one last id. You can do multiple inserts without a loop. You can use the output of SELECT query and insert to the desired table. You can do something like that:
BEGIN
UPDATE testTable set testValue = 2
where username = inputUser and flag = 1;
INSERT into tableB (column1, column2)
SELECT column1, column2 FROM testTable
WHERE username = inputUser and flag = 1;
END
For example:
User (username, password)
UserLoginLog (username, last_log_in_date)
INSERT INTO UserLogInLog (username, last_log_in_date)
SELECT username, NOW()
FROM User
WHERE username = "JohnDoe"

SQL: How to select variable value?

I have a query
INSERT INTO ... SET ....;
SET #last_id = LAST_INSERT_ID();
INSERT INTO ... SET .... ,item_id = #last_id;
INSERT INTO ... SET .... ,item_id = #last_id;
And i want to output to result value of variable. for example:
SELECT #last_id as ID;
query:
INSERT INTO `targets` SET `name` = '123';
SET #target_id = LAST_INSERT_ID();
SELECT #target_id as id;
This is not a query, but rather a set of queries.
Just run them one by one in order.