Limit concurrently sql queries for one user - mysql

I have a strange problem:
Basically I developed a PHP Form that when is submitted by an user the form will proccess an INSERT query with multiple values:
INSERT INTO tbl_name
(id, colB, colC)
VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?) [,...]
So far there is no problem. The problem is that for a couple of reason (not relevant) I have to insert manually the ID of the rows that I'm going to insert so before this query I'm going to make also this query:
SELECT MAX(id) FROM tbl_name WHERE id < x
So I can take the id where to start my query.
Specifying that the queries will take more than a normal query because they're queries in an external database, it takes about 2-3s for the INSERT query.
The problem is:
If one user is going to submit the form, he take the reference ID, for example 45 and then the INSERT queries are processed:
INSERT INTO tbl_name
(id, colB, colC)
VALUES (45, 2, 2), (46, 5, 7), (47, 1, 4) [,...]
But during the INSERT query another user submit the form and he take as reference ID one of the ID of the rows which is processing the other user.
How can I avoid this problem? I thought about limit concurrently sql queries for one user that I will use just for the website, but I don't have any idea how to do it. There's other solutions? Or maybe MySQL it already has a prevention to this problem? Thanks.

MySQL supports having rows auto increment, which would avoid your problem entirely. Using this would have 2 advantages: that you wouldn't need to worry about concurrent users - the db will just auto add the next id, and also you wouldn't have to hit the db twice - once to select the id and once to insert.
This MySQL link shows how to set the column to auto increment.

Related

MySQL REPLACE without all fields provided

I have mysql query to replace some records:
REPLACE INTO product_core
(id, title, description, category_id)
VALUES (2, 'new_title', 'new_description', 33)
Can I do the same, but not providing all needed values? Example:
REPLACE INTO product_core
(id, title, description, category_id)
VALUES (2, 'new_title', 'new_description') #no category_id
Got error wrong number of values here near
I want to bulk replace many records, but I do not want to query all fields before. In this example, I want to update category_id for some records, but not for all.
REPLACE INTO product_core
(id, title, description, category_id)
VALUES (2, 'new_title_2', 'new_description_2'), #no category_id
(3, 'new_title_3', 'new_description_3', 34) #with category_id
Is it real to do this? Replace some fields for one record and other fields for second record in one query.
Or if is it real to provide special variable meaning that some fields will be the same as before replace (category_id)?
VALUES (2, 'new_title_2', 'new_description_2', #category_id_same_as_before)
Can I do the same, but not providing all needed values? Example:
REPLACE INTO product_core (id, title, description, category_id) VALUES
(2, 'new_title', 'new_description') #no category_id
Yes, the correct query is:
REPLACE INTO product_core
(id, title, description)
VALUES (2, 'new_title', 'new_description') #no category_id
EDIT: As Tom commented below the above might be misleading as for the omitted columns default values will be used, not the ones set for the record which is being replaced.
Is it real to do this? Replace some fields for one record and other fields for second record in one query.
It's not possible in MySQL. The column list is common for all the values sets.
Or if is it real to provide special variable meaning that some fields
will be the same as before replace (category_id)?
It's perhaps possible, but not straightforward and not in all MySQL versions. In the docs they say: "You cannot refer to values from the current row and use them in the new row".
In MySQL > 8.0.19 perhaps VALUES(ROW) can help. Or you can perhaps write you own UDF which does it.
You can't omit these columns from a REPLACE command, unless it is the default value for the column.
According to the documentation:
Any missing columns are set to their default values. [...] You cannot refer to values from the current row and use them in the new row.
It may be better to use a standard UPDATE command instead, which can reference the current column value.

Multiple Insert Queries are not working with TSQLQuery with MySQL [duplicate]

I have 1-many number of records that need to be entered into a table. What is the best way to do this in a query? Should I just make a loop and insert one record per iteration? Or is there a better way?
From the MySQL manual
INSERT statements that use VALUES
syntax can insert multiple rows. To do
this, include multiple lists of column
values, each enclosed within
parentheses and separated by commas.
Example:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
Most of the time, you are not working in a MySQL client and you should batch inserts together using the appropriate API.
E.g. in JDBC:
connection con.setAutoCommit(false);
PreparedStatement prepStmt = con.prepareStatement("UPDATE DEPT SET MGRNO=? WHERE DEPTNO=?");
prepStmt.setString(1,mgrnum1);
prepStmt.setString(2,deptnum1);
prepStmt.addBatch();
prepStmt.setString(1,mgrnum2);
prepStmt.setString(2,deptnum2);
prepStmt.addBatch();
int [] numUpdates=prepStmt.executeBatch();
http://publib.boulder.ibm.com/infocenter/db2luw/v8/index.jsp?topic=/com.ibm.db2.udb.doc/ad/tjvbtupd.htm
Load data infile query is much better option but some servers like godaddy restrict this option on shared hosting so , only two options left then one is insert record on every iteration or batch insert , but batch insert has its limitaion of characters if your query exceeds this number of characters set in mysql then your query will crash , So I suggest insert data in chunks withs batch insert , this will minimize number of connections established with database.best of luck guys
Insert into table(col1,col2) select col1,col2 from table_2;
Please refer to MySQL documentation on INSERT Statement
mysql allows you to insert multiple rows at once INSERT manual
INSERT INTO test_1 VALUES(24, 'B', '1990-12-07'), (25, 'C', '1990-12-08');

mysql prepared statement set default value for insert

I've got a table with two columns that links a row id from one table to a row id of another, basically I need to be able to insert multiple rows on this table where one column is a fixed value for the insert and the other changes. The insert is done in php using prepared statements and there is an unknown number of rows to be inserted (I've solved this part using call_user_func_array).
Here is an example of what I need to do:
example_table (column_A, column_B)
The insert:
INSERT INTO example_table (column_A, column_B) VALUES(a, b), VALUES(a, c), VALUES(a, d);
Translated to prepared statement:
INSERT INTO example_table (column_A, column_B) VALUES(?, ?), VALUES(?, ?), VALUES(?, ?);
values on bind_param:
('ssssss', 'a', 'b', 'a', 'c', 'a', 'd')
As you can see the repetition of 'a'. is there a way to store 'a' and default it to column_A for the current insert only?
example of what i would like to do on bind_param:
('ssss', 'a', 'b', 'c', 'd')
Where 'a' above is used for column_A on all rows inserted (3 rows in the example). Any help would be appreciated
No, it's not possible to "alias" a value multiple times. Each placeholder is unique and must be bound to exactly one value. (It is not even possible to do this reliably with named parameters in PDO.)
If automatically building SQL dynamically (with placeholders) and associated data array, then there is no issue with such "duplication" as it's already handled by the generator.
If transactions are correctly used - which they should be anyway! - then simply calling INSERT in a loop, once for each pair, will likely have similar performance. This avoids needing to build the dynamic SQL (with placeholders) itself, but can increase latency as each command needs to round-trip to the SQL server.
If finding a bunch of such repetition, it might be time to use a Data Access Layer to hind such details; write it, test it, move onto something interesting.
In response to the comment about using SQL variables:
While the following will not improve performance, excepting possibly for ridiculously large values of #v, and makes the code more difficult to understand - it ought to be possible to use user-defined variables in a single insert statement. For instance, consider:
INSERT INTO t VALUES (#v := ?, ?), (#v, ?), (#v, ?)
This is "valid" in MySQL (and is also MySQL-specific), where the placeholders are valid expressions; if it works will depend on how/if such a binding is allowed in a prepared statement.
You may try making a temporary table:
$query='CREATE TEMPORARY TABLE tempTable(column_B VARCHAR(50));';
$mysqli->query($query);
then insert unique values of column_B into this table
and finally
$query="INSERT INTO example_table (column_A, column_B) select $a , column_B from tempTable";
$mysqli->query($query);

MySql Insert to multiple tables based on the ID generated in the first table

I have three tables in my database. A users table, StoreA and StoreB
StoreA and StoreB both have a unique key which is the user ID value.
What I want is; When I create a user and insert them into the database, how can I Insert a row into the other two tables without too many additional queries.
I figure I can do this by inserting the user in one query,
then in another return the newly created user ID,
then in another, using said ID, create rows in StoreA and StoreB
Can I cut out the middle query?
Can I cut out the middle query?
YES
START TRANSACTION;
INSERT INTO user (id, name, other)
VALUES (null, 'John','rest of data');
INSERT INTO storeA (id, user_id, other)
VALUES (null, #user_id:= LAST_INSERT_ID(), 'rest of data');
INSERT INTO storeB (id, user_id, other)
VALUES (null, #user_id, 'rest of data');
COMMIT;
See: http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
It's a good idea to do this in a transaction, you you're not stuck with just a user with no other data if something goes wrong.
It's not a DB requirement though.
Yes - there should be a function available to get the last inserted ID (assuming it's an autoincrement field) without another query. In PHP, it's mysql_insert_id(). Just call that after the first query.
YES
Q1: insert into table1 values (...);
Q2: insert into table2 values (last_insert_id(), ...);
last_insert_id is the default mysql build-in function
Most of the mysql libraries in various programming language did support return last insert id.
But You did not mention what sort of language you are using to connect to mysql.,
so cannot provide any example
I just wanted to share a php solution.
If you're using mysqli, first execute your insert query.
Then do
$db_id = $this->db->insert_id;
Why don't you use their username as the primary key instead of creating an arbitrary user_id field thats auto incremented? Their user names are unique, right?

MySQL LAST_INSERT_ID() used with multiple records INSERT statement

If I insert multiple records with a loop that executes a single record insert, the last insert id returned is, as expected, the last one. But if I do a multiple records insert statement:
INSERT INTO people (name,age)
VALUES ('William',25), ('Bart',15), ('Mary',12);
Let's say the three above are the first records inserted in the table. After the insert statement I expected the last insert id to return 3, but it returned 1. The first insert id for the statement in question.
So can someone please confirm if this is the normal behavior of LAST_INSERT_ID() in the context of multiple records INSERT statements. So I can base my code on it.
Yes. This behavior of last_insert_id() is documented in the MySQL docs:
Important
If you insert multiple rows using a single INSERT statement, LAST_INSERT_ID() returns the value generated for the first inserted row only. The reason for this is to make it possible to reproduce easily the same INSERT statement against some other server.
This behavior is mentioned on the man page for MySQL. It's in the comments but is not challenged, so I'm guessing it's the expected behavior.
I think it's possible if your table has unique autoincrement column (ID) and you don't require them to be returned by mysql itself. I would cost you 3 more DB requests and some processing. It would require these steps:
Get "Before MAX(ID)" right before your insert:
SELECT MAX(id) AS before_max_id FROM table_name`
Make multiple INSERT ... VALUES () query with your data and keep them:
INSERT INTO table_name
(col1, col2)
VALUES
("value1-1" , "value1-2"),
("value2-1" , "value2-2"),
("value3-1" , "value3-2"),
ON DUPLICATE KEY UPDATE
Get "After MAX(ID)" right after your insert:
SELECT MAX(id) AS after_max_id FROM table_name`
Get records with IDs between "Before MAX(ID)" and "After MAX(ID)" including:
SELECT * FROM table_name WHERE id>$before_max_id AND id<=$after_max_id`
Do a check of retrieved data with data you inserted to match them and remove any records that were not inserted by you. The remaining records have your IDs:
foreach ($after_collection as $after_item) {
foreach ($input_collection as $input_item) {
if ( $after_item->compare_content($input_item) ) {
$intersection_array[] = $after_item;
}
}
}
This is just how a common person would solve it in a real world, with parts of code. Thanks to autoincrement it should get smallest possible amount of records to check against, so they will not take lot of processing. This is not the final "copy & paste" code - eg. you have to create your own function compare_content() according you your needs.