254

I have a large number of rows that I would like to copy, but I need to change one field.

I can select the rows that I want to copy:

select * from Table where Event_ID = "120"

Now I want to copy all those rows and create new rows while setting the Event_ID to 155. How can I accomplish this?

Andrew
  • 227,796
  • 193
  • 515
  • 708

8 Answers8

357
INSERT INTO Table
          ( Event_ID
          , col2
           ...
          )
     SELECT "155"
          , col2
           ...
      FROM Table WHERE Event_ID = "120"

Here, the col2, ... represent the remaining columns (the ones other than Event_ID) in your table.

dcp
  • 54,410
  • 22
  • 144
  • 164
  • 72
    is there any way to do it without having to specify the column names? – Andrew May 06 '10 at 18:00
  • 4
    Not that I'm aware of. Of course, if your table has like 1000 columns or something and you don't want to type them all, then you could write a SQL statement to build your SQL statement :). The way you would do it would be to use the information_schema to get the column names for the table. But that's really overkill, I'd just type out the column names. – dcp May 06 '10 at 18:21
  • 3
    Would this be possible using an asterisk to get the remaining columns? – Peter Apr 14 '15 at 13:44
  • @Peter - No, it wouldn't. – dcp Apr 14 '15 at 14:22
  • @dcp Too bad, I need to do this for alot of tables and don't want to go and write down all those column names. – Peter Apr 14 '15 at 14:24
  • As @dcp wrote, you can do an SQL statement to write it for you, or even - if it's a script or anything like that you're running - you could make SQL to print the query for you, and then just make a copy paste - so SQL wouldn't have to recalculate everything on every operation, but having it written for you in stead. – Unapedra May 04 '15 at 07:51
  • The hint below the code is not correct. `col2, ...` are the columns you **can** and **want** to copy. All missing fields should be defaulted. And you can't copy primary keys of course. – Bitterblue Mar 06 '20 at 13:15
  • 2
    @Bitterblue - Sorry, I don't understand your comment. I never said col2, ... were columns that you don't want to copy, I just said they represent the remaining columns from the table. It's obvious that they will be copied, otherwise, they wouldn't be in the SQL statement at all. – dcp Mar 06 '20 at 14:59
  • How would you go about this if you wanted the PK to be randomly generated in the copied row? – Takahashinator Oct 13 '22 at 16:51
  • 1
    @Takahashinator - You could just add the column name for the primary key in your list of columns you are inserting, then in your SELECT you would add a function call to generate the random primary key value. You could use something like UUID to generate the key (https://mysqlcode.com/mysql-uuid/) – dcp Oct 13 '22 at 20:32
196

This is a solution where you have many fields in your table and don't want to get a finger cramp from typing all the fields, just type the ones needed :)

How to copy some rows into the same table, with some fields having different values:

  1. Create a temporary table with all the rows you want to copy
  2. Update all the rows in the temporary table with the values you want
  3. If you have an auto increment field, you should set it to NULL in the temporary table
  4. Copy all the rows of the temporary table into your original table
  5. Delete the temporary table

Your code:

CREATE table temporary_table AS SELECT * FROM original_table WHERE Event_ID="155";

UPDATE temporary_table SET Event_ID="120";

UPDATE temporary_table SET ID=NULL;

INSERT INTO original_table SELECT * FROM temporary_table;

DROP TABLE temporary_table;

General scenario code:

CREATE table temporary_table AS SELECT * FROM original_table WHERE <conditions>;

UPDATE temporary_table SET <fieldx>=<valuex>, <fieldy>=<valuey>, ...;

UPDATE temporary_table SET <auto_inc_field>=NULL;

INSERT INTO original_table SELECT * FROM temporary_table;

DROP TABLE temporary_table

Simplified/condensed code:

CREATE TEMPORARY TABLE temporary_table AS SELECT * FROM original_table WHERE <conditions>;

UPDATE temporary_table SET <auto_inc_field>=NULL, <fieldx>=<valuex>, <fieldy>=<valuey>, ...;

INSERT INTO original_table SELECT * FROM temporary_table;

As creation of the temporary table uses the TEMPORARY keyword it will be dropped automatically when the session finishes (as @ar34z suggested).

clemlatz
  • 7,543
  • 4
  • 37
  • 51
Alex Christodoulou
  • 2,873
  • 2
  • 16
  • 18
  • 10
    MySQL supports the `TEMPORARY` keyword to create temporary tables. Usage of `CREATE TEMPORARY TABLE` will automagically drop the table when the session (a serie of SQL queries) is finished. Dropping the table wouldn't be necessary and it doesn't conflict with other temporary tables using the same name. (e.g. when live hacking (which I wouldn't recommend)) – ar34z Aug 13 '14 at 08:52
  • 1
    this code only works if you user #temporary_table instead of temporary_table, maybe a MSSQL issue? – TruthOf42 Dec 18 '14 at 18:23
  • The syntax "CREATE table (temp|#temp) AS SELECT ..." does not work in SQL server 2014. You have to use SELECT ... INTO #temp FROM ..." – needfulthing Apr 21 '15 at 10:43
  • 26
    This basically worked perfectly for me, but I did have to overcome a Not Null constraint on the primary key in the temp table that seems to get copied from the original table. I fixed this by altering the temp table before the update as follows: `ALTER TABLE temporary_table MODIFY INT;` Then the update of the primary key to Null would not fail. – snorris Oct 11 '15 at 05:16
  • 1
    I can't get it to work in PostgreSQL 9.4: `Exception: null value in column violates not-null constraint`. I tried `ALTER TABLE temporary_table ALTER COLUMN DROP NOT NULL;` – n1000 Oct 19 '15 at 14:38
  • 1
    I tested with different MySQL and MariaDB versions. Works perfect for me and I prefer this version to the accepted answer, which actually happens quite often here :) – hexerei software Mar 13 '16 at 18:47
  • 1
    This is a great option because you get to see exactly what will be inserted into your table in the end. It's a good check for yourself even if it does take a bit more time. – pinksharpii Sep 19 '17 at 22:11
  • 1
    @n1000 - instead of `null`, set `auto-increment` column's value to `0`. – ToolmakerSteve May 14 '19 at 19:12
  • @Andrew Please consider making this answer the accepted answer. – Tilman Vogel Jun 08 '20 at 15:35
  • at the start of the code, this was usefull to me: DROP TABLE IF EXISTS `temporary_table`; – clockw0rk Nov 27 '20 at 14:08
  • For Postgres use: `ALTER TABLE temporary_table DROP COLUMN ;` instead of `MODIFY`ing the column type and setting it to `NULL`. It simply removes the protected column. – Kevin Katzke Mar 07 '23 at 19:39
  • This is not useful as we need to keep the definition of a table with hundreds of columns in the code. Far from practical. – Predrag Manojlovic Jun 26 '23 at 21:13
53

Let's say your table has two other columns: foo and bar

INSERT INTO Table (foo, bar, Event_ID)
SELECT foo, bar, "155"
  FROM Table
 WHERE Event_ID = "120"
Peter Bailey
  • 105,256
  • 31
  • 182
  • 206
12

If you have loads of columns in your table and don't want to type out each one you can do it using a temporary table, like;

SELECT *
INTO #Temp
FROM Table WHERE Event_ID = "120"
GO

UPDATE #TEMP
SET Column = "Changed"
GO

INSERT INTO Table
SELECT *
FROM #Temp
Davethebfg
  • 203
  • 3
  • 8
6

Hey how about to copy all fields, change one of them to the same value + something else.

INSERT INTO Table (foo, bar, Event_ID)
SELECT foo, bar, Event_ID+"155"
  FROM Table
 WHERE Event_ID = "120"

??????????

thkala
  • 84,049
  • 23
  • 157
  • 201
Dimitar
  • 85
  • 1
  • 1
3

As long as Event_ID is Integer, do this:

INSERT INTO Table (foo, bar, Event_ID)
SELECT foo, bar, (Event_ID + 155)
  FROM Table
WHERE Event_ID = "120"
0

Adding to the answer by @DaveTheBFG: If you have an identity column ("Table_PK" in the below example), the INSERT line would fail, but you can do the following (SQL Server-specific, but the concept may apply to other databases):

SELECT *
INTO #Temp
FROM Table WHERE Event_ID = "120"

UPDATE #TEMP
SET Column = "Changed"

ALTER TABLE #TEMP DROP COLUMN Table_PK

EXEC sp_executesql N'INSERT INTO Table SELECT * FROM #Temp'
Aron
  • 45
  • 6
0

If you don't mind doing it in your code, its much easier to do. For example, in php you can do

function copyQuery($table, $row){
    $queryColumns = $queryValues = '';
    foreach ($row as $key => $value) {
        $queryColumns .= $key.', ';
        $queryValues .= "'$value', ";
    }
    $queryColumns = rtrim($queryColumns, ', ');
    $queryValues = rtrim($queryValues, ', ');

    return "INSERT INTO $table ($queryColumns) VALUES ($queryValues)";
}

$records = mysqli_query($connect, "SELECT * FROM Table WHERE Event_ID = 120");
while ($row = mysqli_fetch_assoc($records)) {
    unset($row['id']);
    $row['Event_ID'] = 155;

    $query = copyQuery('Table', $row);
    mysqli_query($connect, $query);
}

Using a function is optional. I made it because I needed to do it a few times. I used this option because now I can forget about it if the database columns change in the future.

Whip
  • 1,891
  • 22
  • 43