MySQL - Copying partial data from one table to another - mysql

This may be a silly question, and I understand why I'm getting the result that I am, however, I thought mySQL acted differently and I can't finish the documentation to tell me otherwise.
I have 2 basic tables as follows:
CREATE TABLE test ( num INT, time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP );
CREATE TABLE test_to_copy ( num INT );
I then create a single entry into the test_to_copy table:
INSERT INTO test_to_copy VALUES ( 12 );
Now I try and copy the table test_to_copy to test like so:
INSERT INTO test SELECT * FROM test_to_copy;
The error that keeps getting thrown is
"Column count doesn't match value count at row 1".
I know that it is complaining that the number of columns in both tables does not match meaning it does not know what variable we are assigning our copy to, however, should it not be a case where the time is created automatically i.e. defaulted if nothing is inserted when we do the copy rather than throw the error?
Due to constraints, I can no longer have the time in both tables, and I must do a SELECT * on the test_to_copy table as there are over 50 columns, and i'm wondering is there an easy way around this?

This is another variation of a frequent question: "can I query *-except-for-one-column?"
No, there is no wildcard-with-exceptions syntax in SQL. The * wildcard means all columns. If you don't want all columns, you must name the columns explicitly.
If you have a variety of columns because this method may be used for more than one table, you can get the list of columns for any given table from INFORMATION_SCHEMA.COLUMNS and use that information to build a dynamic SQL query.
Here's a way you can produce the list of columns:
SELECT
GROUP_CONCAT(
CONCAT('`', column_name, '`')
) AS _cols
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA='mydatabase' AND TABLE_NAME='mytable'
AND COLUMN_NAME NOT IN ('time'); -- or other columns to exclude
See also:
Select all columns except one in MySQL?
SQL exclude a column using SELECT * [except columnA] FROM tableA?

INSERT INTO test (num)
SELECT num
FROM test_to_copy

Related

Create a table and specify data types according to an existing query

Let's say I have a table like this
this table is the result of a query from another larger table stored in my database
All I want is to create a table like this one above and specify for each column a custom format and store it into my database
I know that I could do create table mytab as select ... etc
however i don't know how to specify the column formats that I want in mysql
could you please help ?
If you have the query sql, you should be able to do a select into to store the results in a table. Add a LIMIT clause to just store one row. You could then do SHOW CREATE TABLE tablename (from this SO answer) to get the SQL for creating the table. It would be up to you to figure out what your primary key should be.
Assuming with column formats you mean data types: Use CAST to cast to the desired data type.
create new_table as
select
cast( a.metrique as varchar(100) ) as metrique,
cast( b.nombre_de_lignes as int ) as cote_de_lignes, ...
from ...
You may specify columns properties completely or partially. Like there is no SELECT part, and you simply create empty table.
I.e. like
CREATE TABLE table_name ({any definitions allowed in table creation query:
columns specifications, indices, constraints, FKs, etc.})
SELECT ...
In this form each output column in SELECT must have alias which matches according column name defined in CREATE TABLE part. If alias is absent in the structure then a column with the name==alias will be added to the table definition with dynamically formed properties.

extract data from sql, modify it and save the result to a table

This may seem like a dumb question. I am wanting to set up an SQL db with records containing numbers. I would like to run an enquiry to select a group of records, then take the values in that group, do some basic arithmetic on the numbers and then save the results to a different table but still have them linked with a foreign key to the original record. Is that possible to do in SQL without taking the data to another application and then importing it back? If so, what is the basic function/procedure to complete this action?
I'm coming from an excel/macro/basic python background and want to investigate if it's worth the switch to SQL.
PS. I'm wanting to stay open source.
A tiny example using postgresql (9.6)
-- Create tables
CREATE TABLE initialValues(
id serial PRIMARY KEY,
value int
);
CREATE TABLE addOne(
id serial,
id_init_val int REFERENCES initialValues(id),
value int
);
-- Init values
INSERT INTO initialValues(value)
SELECT a.n
FROM generate_series(1, 100) as a(n);
-- Insert values in the second table by selecting the ones from the
-- First one .
WITH init_val as (SELECT i.id,i.value FROM initialValues i)
INSERT INTO addOne(id_init_val,value)
(SELECT id,value+1 FROM init_val);
In MySQL you can use CREATE TABLE ... SELECT (https://dev.mysql.com/doc/refman/8.0/en/create-table-select.html)

Trying to use INTO...SELECT in MySQL. Having trouble with the WHERE clause.

I'm trying to make it so that it copies all the data from oa_tags into member_info, but the problem is that I have a unique auto_increment key in both oa_tags and member_info(it's the same in both, called ID). I need it to copy all the data from oa_tags into member_info, but obviously it has to ignore the entries with the same "ID" column.
This is what I have so far -
INSERT INTO member_info
SELECT *
FROM oa_tags, member_info WHERE oa_tags.ID > member_info.ID;
It's throwing this error at me - "#1136 - Column count doesn't match value count at row 1"
Any suggestions are welcome.
Thanks
This is the how mysql supports what you're wanting to do.
http://dev.mysql.com/doc/refman/5.0/en/ansi-diff-select-into-table.html
This explains why I wanted to know the field list/structure of both tables. (I don't like the not in . I think there has to be a way to do it with exists but I'm struggling; and I'm not sure you really care about performance as this seems to be a one time thing)
INSERT INTO member_info (FIELD LIST)
SELECT (FIELD LIST) from oa_tags where ID not in (Select ID from member_info)
This might work, but I doubt it and it's far from "Best practice" but if it's one time throw away, it might get the job done.
INSERT INTO member_info
SELECT * from oa_tags where ID not in (Select ID from member_info)
If you implemented a best practice where you identify all the columns it will fix many of the problems you are currently having. In general it is poor practice to use the * for columns other than testing. Naming/Qualifying your columns (even when there is a lot) will prevent a lot of future issues when tables change.
You can name both the columns in the insert and the select so that they match and only insert the ones you are interested in. Such as ignoring the 'ID' column
The problem is that your column count is off. Let's assume each table has five columns.
You are trying to insert into member_info which has five columns. Your select joins both tables which means you will get a total of ten columns in your select. Run just the select to verify but that is why you are getting the error.
To fix it you can try changing:
select *
to
select oa_tags.*
However, I don't believe your current statement will work. Say you have a row in oa_tags with id 10. The where clause will match that row to rows in member_info where the id is 1 through 9 and you will end up inserting duplicates. Also, both tables could have an id of 10 but if member info had an id of 9, that statement would still try to insert id 10.
I would let the auto increment do its job and try:
INSERT INTO member_info(column1, column2,... (every column but id)
SELECT column1, column2,... (every column but id to allow the table to auto increment)
FROM oa_tags
If you don't want to insert every record in oa_tags into member_info, you can still filter on the id by adding:
WHERE oa_tags.ID not in (select member_info.ID from member_info);

Get unique IDs for multiple INSERT

I need to get back all the inserted IDs (from an auto-incremented field) from a single query that inserts something like 20+ rows into a MySQL database. I've got something like this so far:
INSERT INTO [tablename] ( ... ) VALUES ( ... ), ( ... ), ( ... );
How would I need to modify the above query to get back all inserted IDs?
I've found a few topics where the use of DECLARE was suggested, but PhpMyAdmin always returned an error, when I tried to run the query.
Thanks!
MyISAM should be locking the table for your insert, so it feels like you'd be OK getting one value back and offsetting with the number of rows affected.
To be really safe, how about adding a 'batch' column and inserting a session-based variable? Then you could select out the IDs that had that value. Not great, but...

MySQL : multiple column values as 1 comma-separated string?

Suppose I have a select query like :
SELECT * FROM tablename
and in the table are columns : field1, field2 and field3
Does anyone know if it's possible to get a resultset with only 1 row with 1 field, with comma separated values of the columns, like this :
"fieldvalue1, fieldvalue2, fieldvalue3"
Problem is that I don't know the column names of the table in advance...
Another problem is that a prepared statement is not the way to go, since all this should be done from within a trigger, and MySQL doesn't allow dynamic cursors/selects inside a trigger.
I have done some research and only came as far as GROUP_CONCATenating the column names correctly. But the problem is, that
SELECT (SELECT GROUP_CONCAT( cols.column_name) FROM (SELECT column_name FROM information_schema.columns WHERE table_name='test_table') as cols) FROM test_table
will return one and the same concatenated string containing the column names, once for each table row, instead of evaluating it as the column names for the outer select statement and returning the actual values.
From what I have read in all of the forums discussing this kind of question (and there were many), there is really no way of getting this to work without prepared statements.
I can only think of one other way to do this, and that would be having a dedicated column on each table, where you concatenate the individual column values on INSERT or UPDATE, so you can simply select this one field instead of the full set of fields.
Seems like you have 3 questions here:
Getting a resultset with 1 row, 1 field: MYSQL has a CONCAT_WS function that works like this:
SELECT CONCAT_WS(',',Field1,Field2,Field3)
That will return "Field1Value, Field2Value, Field3Value"
I'm not sure how you are going to get these column names. Do you need to get them from a sql statement, a string, etc. ? You can get the table names `SHOW COLUMNS FROM tablename'. The Field column will have the column names.
Triggers are available in mysql (added in 5.0.2 I think): http://dev.mysql.com/doc/refman/5.0/en/triggers.html
First, to find out the columns' names in advance, assuming that you have the table's name, you can get them as any other query:
SHOW COLUMNS FROM your_table
Once you have the names you can do:
SELECT CONCAT(field1,',',field2,',',field3) AS newField FROM your_table