Maybe this seems like the opposite of what people would normally like to do, but I'd like to duplicate rows in my mysql table.
So, for example, I have a table with 1 row that has project_id, and one row with file_name. Each project has very many files associated with it. I would like to duplicate all rows that exist for one project in to another project. I could write some python script that would do this but I suspect there would be a way to do it from within mysql.
Any ideas? Thanks.
For example, if I have a project that looks like this...
file_id, file_name, project_id
-------, ---------, ----------
1, file1.png, 1
2, file2.png, 1
3, file3.png, 1
...and up to around 100 rows.
What should I type in to get a project that looks like this...
file_id, file_name, project_id
-------, ---------, ----------
1, file1.png, 1
2, file2.png, 1
3, file3.png, 1
4, file1.png, 2
5, file2.png, 2
6, file3.png, 2
In MySQL, you can combine an insert statement with a select statement, such that the values inserted in the new row by the insert statement are the ones selected by the select statement. See INSERT..SELECT for details.
It sounds like what you need is to INSERT from a SELECT. The basic idea for doing this can be found from the link below.
mysql -> insert into tbl (select from another table) and some default values
Side note: If you duplicate the rows completely then you will probably have issues with database keys. If you don't, then your database has design issues.
Try this:
INSERT INTO table_name (file_name, project_id)
SELECT file_name, project_id + 1 FROM table_name;
This selects everything currently in the table named table_name and reinserts the records into table_name with an incremented project_id. It assumes the file_id field is auto incremented.
I think it can be resolve this way, in case you have a main table that holding the entire project id list, project_table in my example, and assuming that file_id in the file_table is set to auto_increment :
INSERT INTO file_table ( file_name, project_id)
VALUES (SELECT file_name, project_table.project_id
FROM project_table
INNER JOIN file_table ON project_id = 1
WHERE project_table.id != 1)
Related
Currently, I find it time consuming to copy specific columns and values from Table 1 and paste the values onto Table 2 manually.
I have two tables ( In the same database ) like this:
How can I save time by doing the following? -
Grab specific ID from Table 1, in this case 1 and 2.
and copy just the Pcode & Desc values onto Table 2?
This is the end result I want to achieve (screenshot below)
The ID will be new, because its a new record. So technically I am updating Table 2 with new values that I have copied from Table 1
Every column is varchar type column expect the Id's
Also, I am using MySql Workbench.
This should do the trick;
INSERT INTO table2 (PCode, Desc)
SELECT Pcode, Desc
FROM table1
WHERE table1.id = 1 or table1.id = 2
Below is the table i am trying to write a query for to add new rows for every user.
My question is how do i add a new row for every user? Which means for userId 2 I add AccId 4 and similarly for 7 and 8. Since there is no concept of for loop in sql, do i make use of while? If so, how to loop through the userIds since the IDs are not in equal increments?
something like this maybe:
Insert Into mytable (UserID, AccID)
Select UserID, max(accId)+1
From MyTable
Group By UserID
You can re-run it every time, you will create the next value.
Untested on a MySql server:
INSERT INTO MyTable ( ID, AccId )
SELECT MyValues.ID, MyValues.Espr1
FROM (SELECT MyTable.ID, Max([AccId]+1) AS Espr1
FROM MyTable
GROUP BY MyTable.ID) AS MyValues;
Basically we prefetch Id a AccId grouping the values of Id and grabbing the Max of AccId.
Then we add these rows to the main table. Repeating the query we will add the value 5 (AccId) and so on, always adding 1
I'm looking for a way I can duplicate all the rows in my database, I tried exporting it and then importing but I get the duplicate key error.
The reason is purely for testing purposes, I just want a load of dummy data in there to test the system I have out.
Is there a direct statement for this? Or is there a way to export all data except ID (or change ID to MAX(ID) + 1 or AUTO INCREMENT)?
You can try this:
INSERT INTO your_table_name(parent_id,priority,text,shortname,weighting,g_or_a,
dept,ksf,day_start,day_end,date_start,date_end,depends_on,is_question,budget,
ccode,responsible,accountable,consulted,informed)
(SELECT parent_id,priority,text,shortname,weighting,g_or_a,dept,ksf,
day_start,day_end,date_start,date_end,depends_on,is_question,budget,ccode,
responsible,accountable,consulted,informed FROM your_table_name);
Firstly, insert one row in the table 'your_table_name'. Replace your_table_name with the actual table name in above code & execute the code repeatedly until it satisfies the required row numbers. I think it should work.
Put 1 record and then run:
insert into mytable select * from mytable
10 times. This will give you 1024 records. Continue until satisfied.
You could use an INSERT and the values would be a SELECT, just don't select the primary key and don't define it in the insert fields.
Imagine a table with 3 fields, the_pk, field_1, field_2
Something like
INSERT INTO the_table(field_1, field_2) (SELECT field_1, field_2 FROM the_table)
I have this Statement:
INSERT INTO qa_costpriceslog (item_code, invoice_code, item_costprice)
VALUES (1, 2, (SELECT item_costprice FROM qa_items WHERE item_code = 1));
I'm trying to insert a value copy the same data of item_costprice, but show me the error:
Error Code: 1136. Column count doesn't match value count at row 1
How i can solve this?
Use numeric literals with aliases inside a SELECT statement. No () are necessary around the SELECT component.
INSERT INTO qa_costpriceslog (item_code, invoice_code, item_costprice)
SELECT
/* Literal number values with column aliases */
1 AS item_code,
2 AS invoice_code,
item_costprice
FROM qa_items
WHERE item_code = 1;
Note that in context of an INSERT INTO...SELECT, the aliases are not actually necessary and you can just SELECT 1, 2, item_costprice, but in a normal SELECT you'll need the aliases to access the columns returned.
You can just simply e.g.
INSERT INTO modulesToSections (fk_moduleId, fk_sectionId, `order`) VALUES
((SELECT id FROM modules WHERE title="Top bar"),0,-100);
I was disappointed at the "all or nothing" answers. I needed (again) to INSERT some data and SELECT an id from an existing table.
INSERT INTO table1 (id_table2, name) VALUES ((SELECT id FROM table2 LIMIT 1), 'Example');
The sub-select on an INSERT query should use parenthesis in addition to the comma as deliminators.
For those having trouble with using a SELECT within an INSERT I recommend testing your SELECT independently first and ensuring that the correct number of columns match for both queries.
Your insert statement contains too many columns on the left-hand side or not enough columns on the right hand side. The part before the VALUES has 7 columns listed, but the second part after VALUES only has 3 columns returned: 1, 2, then the sub-query only returns 1 column.
EDIT: Well, it did before someone modified the query....
As a sidenote to the good answer of Michael Berkowski:
You can also dynamically add fields (or have them prepared if you're working with php skripts) like so:
INSERT INTO table_a(col1, col2, col3)
SELECT
col1,
col2,
CURRENT_TIMESTAMP()
FROM table_B
WHERE b.col1 = a.col1;
If you need to transfer without adding new data, you can use NULL as a placeholder.
If you have multiple string values you want to add, you can put them into a temporary table and then cross join it with the value you want.
-- Create temp table
CREATE TEMPORARY TABLE NewStrings (
NewString VARCHAR(50)
);
-- Populate temp table
INSERT INTO NewStrings (NewString) VALUES ('Hello'), ('World'), ('Hi');
-- Insert desired rows into permanent table
INSERT INTO PermanentTable (OtherID, NewString)
WITH OtherSelect AS (
SELECT OtherID AS OtherID FROM OtherTable WHERE OtherName = 'Other Name'
)
SELECT os.OtherID, ns.NewString
FROM OtherSelect os, NewStrings ns;
This way, you only have to define the strings in one place, and you only have to do the query in one place. If you used subqueries like I initially did and like Elendurwen and John suggest, you have to type the subquery into every row. But using temporary tables and a CTE in this way, you can write the query only once.
First, here's the concise summary of the question:
Is it possible to run an INSERT statement conditionally?
Something akin to this:
IF(expression) INSERT...
Now, I know I can do this with a stored procedure.
My question is: can I do this in my query?
Now, why would I want to do that?
Let's assume we have the following 2 tables:
products: id, qty_on_hand
orders: id, product_id, qty
Now, let's say an order for 20 Voodoo Dolls (product id 2) comes in.
We first check if there's enough Quantity On Hand:
SELECT IF(
( SELECT SUM(qty) FROM orders WHERE product_id = 2 ) + 20
<=
( SELECT qty_on_hand FROM products WHERE id = 2)
, 'true', 'false');
Then, if it evaluates to true, we run an INSERT query.
So far so good.
However, there's a problem with concurrency.
If 2 orders come in at the exact same time, they might both read the quantity-on-hand before any one of them has entered the order.
They'll then both place the order, thus exceeding the qty_on_hand.
So, back to the root of the question:
Is it possible to run an INSERT statement conditionally, so that we can combine both these queries into one?
I searched around a lot, and the only type of conditional INSERT statement that I could find was ON DUPLICATE KEY, which obviously does not apply here.
INSERT INTO TABLE
SELECT value_for_column1, value_for_column2, ...
FROM wherever
WHERE your_special_condition
If no rows are returned from the select (because your special condition is false) no insert happens.
Using your schema from question (assuming your id column is auto_increment):
insert into orders (product_id, qty)
select 2, 20
where (SELECT qty_on_hand FROM products WHERE id = 2) > 20;
This will insert no rows if there's not enough stock on hand, otherwise it will create the order row.
Nice idea btw!
Try:
INSERT INTO orders(product_id, qty)
SELECT 2, 20 FROM products WHERE id = 2 AND qty_on_hand >= 20
If a product with id equal to 2 exists and the qty_on_hand is greater or equal to 20 for this product, then an insert will occur with the values product_id = 2, and qty = 20. Otherwise, no insert will occur.
Note: If your product ids are note unique, you might want to add a LIMIT clause at the end of the SELECT statement.
Not sure about concurrency, you'll need to read up on locking in mysql, but this will let you be sure that you only take 20 items if 20 items are available:
update products
set qty_on_hand = qty_on_hand - 20
where qty_on_hand >= 20
and id=2
You can then check how many rows were affected. If none were affected, you did not have enough stock. If 1 row was affected, you have effectively consumed the stock.
You're probably solving the problem the wrong way.
If you're afraid two read-operations will occur at the same time and thus one will work with stale data, the solution is to use locks or transactions.
Have the query do this:
lock table for read
read table
update table
release lock
I wanted to insert into a table using values so I found this solution to insert the values using the IF condition
DELIMITER $$
CREATE PROCEDURE insertIssue()
BEGIN
IF (1 NOT IN (select I.issue_number from issue as I where I.series_id = 1)) THEN
INSERT IGNORE INTO issue ( issue_number, month_published, year_published, series_id, mcs_issue_id) VALUES (1, 1, 1990, 1, 1);
END IF;
END$$
DELIMITER ;
If you later on want to call the procedure it's as simple as
CALL insertIssue()
You can find more information about PROCEDURES and if conditions in this site