86

I have two tables with identical structure except for one column... Table 2 has an additional column in which I would insert the CURRENT_DATE()

I would like to copy all the values from table1 to table2.

If I use

INSERT INTO dues_storage SELECT * FROM dues WHERE id=5;

it throws an error pointing to the difference in the number of columns.

I have two questions:

  1. How do I get around this?
  2. How do I add the value for the additional date column (CURRENT_DATE()) in table2 within this same statement?
Josh Correia
  • 3,807
  • 3
  • 33
  • 50
user165242
  • 1,379
  • 2
  • 12
  • 18
  • You could have a look at this. It worked for me in mysql. http://stackoverflow.com/questions/57168/how-to-copy-a-row-from-one-sql-server-table-to-another – Shreyo Mar 24 '14 at 11:33

7 Answers7

112

To refine the answer from Zed, and to answer your comment:

INSERT INTO dues_storage
SELECT d.*, CURRENT_DATE()
FROM dues d
WHERE id = 5;

See T.J. Crowder's comment

Nabin
  • 11,216
  • 8
  • 63
  • 98
crunchdog
  • 13,078
  • 3
  • 23
  • 19
  • 62
    Be **VERY CAREFUL** doing this. It does work, but it assumes the order of columns in the two tables is identical; it does **not** match by column name, and does try to coerce values to fit, which can cause unexpected results. Now, if your development structure assures the column orders are identical bar the last column, it's a convenient and straightforward way to do it, but the caveat is important. – T.J. Crowder Aug 30 '09 at 12:20
  • Luckily the order is the same. ill keep in mind to keep the structure identical even in the future. thanks all! – user165242 Aug 30 '09 at 14:01
  • @crunchdog how should query be organized if I need to set `where` like `A.id = B.id`? – Eugene Jun 25 '12 at 09:53
  • 5
    Do you even need CURRENT_DATE()? You can set the type of that field to TimeStamp and set the default to CURRENT_TIMESTAMP. It should populate the current DateTime to when the record was created. – Chiwda Apr 24 '17 at 14:17
60

The safest way to do it is to fully specify the columns both for insertion and extraction. There's no guarantee (to the application) that either of these will be the order you think they may be.

insert into dues_storage (f1, f2, f3, cd)
    select f1, f2, f3, current_date() from dues where id = 5;

If you're worried about having to change many multiple PHP pages that do this (as you seem to indicate in the comment to another answer), this is ripe for a stored procedure. That way, all your PHP pages simply call the stored procedure with (for example) just the ID to copy and it controls the actual copy process. That way, there's only one place where you need to maintain the code, and, in my opinion, the DBMS is the right place to do it.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
8
INSERT INTO dues_storage
SELECT field1, field2, ..., fieldN, CURRENT_DATE()
FROM dues
WHERE id = 5;
Zed
  • 57,028
  • 9
  • 76
  • 100
6

Hope this will help someone... Here's a little PHP script I wrote in case you need to copy some columns but not others, and/or the columns are not in the same order on both tables. As long as the columns are named the same, this will work. So if table A has [userid, handle, something] and tableB has [userID, handle, timestamp], then you'd "SELECT userID, handle, NOW() as timestamp FROM tableA", then get the result of that, and pass the result as the first parameter to this function ($z). $toTable is a string name for the table you're copying to, and $link_identifier is the db you're copying to. This is relatively fast for small sets of data. Not suggested that you try to move more than a few thousand rows at a time this way in a production setting. I use this primarily to back up data collected during a session when a user logs out, and then immediately clear the data from the live db to keep it slim.

 function mysql_multirow_copy($z,$toTable,$link_identifier) {
            $fields = "";
            for ($i=0;$i<mysql_num_fields($z);$i++) {
                if ($i>0) {
                    $fields .= ",";
                }
                $fields .= mysql_field_name($z,$i);
            }
            $q = "INSERT INTO $toTable ($fields) VALUES";
            $c = 0;
            mysql_data_seek($z,0); //critical reset in case $z has been parsed beforehand. !
            while ($a = mysql_fetch_assoc($z)) {
                foreach ($a as $key=>$as) {
                    $a[$key] = addslashes($as);
                    next ($a);
                }
                if ($c>0) {
                    $q .= ",";
                }
                $q .= "('".implode(array_values($a),"','")."')";
                $c++;
            }
            $q .= ";";
            $z = mysql_query($q,$link_identifier);
            return ($q);
        }
Joel
  • 2,654
  • 6
  • 31
  • 46
Josh Strike
  • 61
  • 1
  • 1
1

Alternatively, you can use Inner Queries to do so.

SQL> INSERT INTO <NEW_TABLE> SELECT * FROM CUSTOMERS WHERE ID IN (SELECT ID FROM <OLD_TABLE>);

Hope this helps!

Prasheel
  • 985
  • 5
  • 22
1
SET @sql = 
CONCAT( 'INSERT INTO <table_name> (', 
    (
        SELECT GROUP_CONCAT( CONCAT('`',COLUMN_NAME,'`') ) 
            FROM information_schema.columns 
            WHERE table_schema = <database_name>
                AND table_name = <table_name>
                AND column_name NOT IN ('id')
    ), ') SELECT ', 
    ( 
        SELECT GROUP_CONCAT(CONCAT('`',COLUMN_NAME,'`')) 
        FROM information_schema.columns 
        WHERE table_schema = <database_name>
            AND table_name = <table_source_name>
            AND column_name NOT IN ('id')  
    ),' from <table_source_name> WHERE <testcolumn> = <testvalue>' );  

PREPARE stmt1 FROM @sql; 
execute stmt1;

Of course replace <> values with real values, and watch your quotes.

-3

Just wanted to add this little snippet which works beautifully for me.

INSERT INTO your_target_table SELECT * FROM your_rescource_table WHERE id = 18;

And while I'm at it give a big shout out to Sequel Pro, if you're not using it I highly recommend downloading it...makes life so much easier

Kevin F
  • 1
  • 1