I know that I can copy the rows into the same table while specifying different values for columns that need to contain different values by actually writing ALL the column names in the query like so:
INSERT INTO
my_table (col1, col2, col3, col4)
SELECT
col1,
col2,
[value_for_col_3],
col4
FROM
my_table;
WHERE [value_for_col_3] is the raw value that I want for the column col3. This works fine, but in cases where my table contains a lot of columns, it would be cumbersome to write all the column names. Is there a way to perform the same operation without typing all the column names of my table (while still being able to specify different values for certain columns)?
Thanks in advance for any help.
In this answer, I'm giving a basic outline instead of writing out all of the code since you're looking to see if what you want can be done. This is a possbile method of doing so.
The method is to get the list of all of the names of the columns except for the ones you don't want, then use the output of those column names in a query.
This shows how to select all but certain columns in SQL Server, but I'm sure syntax could be modified to work in MySQL.
(Copy and pasting the below code from one of the answers here: SQL exclude a column using SELECT * [except columnA] FROM tableA?)
declare #cols varchar(max), #query varchar(max);
SELECT #cols = STUFF
(
(
SELECT DISTINCT '], [' + name
FROM sys.columns
where object_id = (
select top 1 object_id from sys.objects
where name = 'MyTable'
)
and name not in ('ColumnIDontWant1', 'ColumnIDontWant2')
FOR XML PATH('')
), 1, 2, ''
) + ']';
SELECT #query = 'select ' + #cols + ' from MyTable where';
EXEC (#query);
Just the SELECT statement,
SELECT #query = 'select ' + #cols + ' from MyTable where';
would be modified to your insert into statement.
Related
I have a large database (~50,000 rows) with 20 columns, and I want to "split" the data based upon the values in the third column (called FEATURE_CLASS). The values of FEATURE_CLASS are all of type VARCHAR(), and I want to create however many tables I'd need to replace the single, large table with many smaller tables each entitled with whatever the original table's FEATURE_CLASS value was.
Not sure of the best way to go about this, I was thinking something along the lines of creating a temporary table which would serve as an index, each row carrying a unique value of FEATURE_CLASS, then to iterate over the temp table and perform copying operations for each row of the temp table. I'm not sure really where to go from here, any help/ideas would be appreciated. Thanks!
The basic idea is to create a result set of statements that will create the tables for you and populate with the correct data. Run the below to generate the statements. You can then execute these statements manually (copy/paste) or from within a script.
SQL Server Example
SELECT DISTINCT
'SELECT * INTO [' + TableName.FEATURE_CLASS + '] FROM TableName WHERE FEATURE_CLASS = ''' + TableName.FEATURE_CLASS + ''';'
FROM
TableName
If you have any special characters in the FEATURE_CLASS column, you might want to consider removing them in the script above to prevent table names that are either invalid or tough to work with.
For example:
...
'SELECT * INTO [' + REPLACE(TableName.FEATURE_CLASS, '.', '') + '] FROM TableName WHERE FEATURE_CLASS = ''' + TableName.FEATURE_CLASS + ''';'
...
MySQL Example
SELECT DISTINCT
CONCAT('CREATE TABLE `', DB1.FEATURE_CLASS,
'` AS SELECT * FROM DB1 WHERE FEATURE_CLASS = ''',
DB1.FEATURE_CLASS, ''';') AS statements
FROM DB1;
This will give you a MySQL command something like this:
CREATE TABLE `feature_class_value` AS
SELECT * FROM DB1
WHERE FEATURE_CLASS = 'feature_class_value';
Check out the MySQL docs for more info on CREATE TABLE SELECT options https://dev.mysql.com/doc/refman/5.7/en/create-table-select.html.
I need to copy/ insert all values with a certain where clause from table A to table B (basically from Main tables to respective history tables).
I don't want to specify the column names as I want to create a generic approach which will be able to use for all the tables that will need the ingestion.
Unfortunately, the attributes in table A are not always in the same order as it is in tableB, so I can't use select * into #temp from TableA and then insert into tableB from #temp. Plus TableB has generic 3 sys columns which we are generated for audit purposes.
My idea was to use the Info schema to get the column names. Then somehow use the result to get all the values from the asking table and add on top the generic sys columns. Is it possible to do?
I got the column names by using Info schema.
Select
COLUMN_NAME
FROM INFORMATION_SCHEMA.columns
where TABLE_NAME = 'TableA'
The SYS columns are:
sys_date=Getdate ()
,sys_flag='1'
,sys_name=SYSTEM_USER
Use Dynamic Query SQL Server
Please change table Name accordingly.
Declare #Table_Name varchar(50)
SET #Table_Name ='LoginMst'
Declare #Query varchar(8000)
Declare #ColumnNames varchar (8000)
set #ColumnNames = ''
select #ColumnNames =
case when #ColumnNames = ''
then column_name
else #ColumnNames + coalesce(',' + column_name, '')
end
from information_schema.columns where Table_Name=#Table_Name
SET #Query='insert into '+#Table_Name+'_Log ('+#ColumnNames+',sys_date,sys_flag,sys_name'+')
select '+#ColumnNames+',Getdate(),''1'',SYSTEM_USER from '+ 'LoginMst'
--print #Query
Exec(#Query)
You will require iterating all the tables you wish to take backup of. You will require adding the where clause too.
Suppose that I am copying one table data values into another table.
INSERT INTO T1(field_list) VALUES( SELECT field_list FROM T2 )
And instead of inserting one column of second table I provide a variable. It would be like
INSERT INTO T1(field_list) VALUES ( SELECT field_list, #variable FROM T2 )
Taking into consideration that there is no error with column count and instead of providing some static text I provide a variable name.
If I change #variable to some static text it works but not #variable.
How to provide #variable in that case ?
You have to first declare the #variable
DECLARE #variable varchar(255)
SET #variable = 'myColumn'
EXECUTE (' SELECT *, ' + #variable + ' FROM myTable' )
INSERT INTO T1(field_list)
SELECT field_list, #variable FROM T2
It should work without any issue unless you table doesn't allow null and you have same number of values to be inserted as many columns defined in insert into statement.
As you said variable is declared, it shouldn't be a problem.
EDIT:
#Variable could be dynamic text that you pass from front end or static text assigned to variable in your SP. It should work in all the cases.
INSERT INTO T1(field1,field2)
SELECT field2, #variable FROM T2
I am wondering if it is possible to use SQL to create a table that name columns by index(number). Say, I would like to create a table with 10 million or so columns, I definitely don't want to name every column...
I know that I can write a script to generate a long string as SQL command. However, I would like to know if there is a more elegant way to so
Like something I make up here:
CREATE TABLE table_name
(
number_columns 10000000,
data_type INT
)
I guess saying 10 million columns caused a lot of confusion. Sorry about that. I looked up the manual of several major commercial DBMS and seems it is not possible. Thank you for pointing this out.
But another question, which is most important, does SQL support numerical naming of columns, say all the columns have the same type and there is 50 columns. And when referring it, just like
SELECT COL.INDEX(3), COL.INDEX(2) FROM MYTABLE
Does the language support that?
Couldn't resist looking into this, and found that the MySQL Docs say "no" to this, that
There is a hard limit of 4096 columns per table, but the effective
maximum may be less for a given table
You can easily do that in Postgres with dynamic SQL. Consider the demo:
DO LANGUAGE plpgsql
$$
BEGIN
EXECUTE '
CREATE TEMP TABLE t ('
|| (
SELECT string_agg('col' || g || ' int', ', ')
FROM generate_series(1, 10) g -- or 1600?
)
|| ')';
END;
$$;
But why would you even want to give life to such a monstrosity?
As #A.H. commented, there is a hard limit on the number of columns in PostgreSQL:
There is a limit on how many columns a table can contain. Depending on
the column types, it is between 250 and 1600. However, defining a
table with anywhere near this many columns is highly unusual and often
a questionable design.
Emphasis mine.
More about table limitations in the Postgres Wiki.
Access columns by index number
As to your additional question: with a schema like the above you can simply write:
SELECT col3, col2 FROM t;
I don't know of a built-in way to reference columns by index. You can use dynamic SQL again. Or, for a table that consists of integer columns exclusively, this will work, too:
SELECT c[3] AS col3, c[2] AS col2
FROM (
SELECT translate(t::text, '()', '{}')::int[] AS c -- transform row to ARRAY
FROM t
) x
Generally when working with databases your schema should be more or less "defined" so dynamic column adding isn't a built in functionality.
You can, however, run a loop and continually ALTER TABLE to add columns like so:
BEGIN
SET #col_index = 0;
start_loop: LOOP
SET #col_index = #col_index + 1;
IF #col_index <= num_columns THEN
SET #alter_query = (SELECT CONCAT('ALTER TABLE table_name ADD COLUMN added_column_',#col_index,' VARCHAR(50)'));
PREPARE stmt FROM #alter_query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
ITERATE start_loop;
END IF;
LEAVE start_loop;
END LOOP start_loop;
END;
But again, like most of the advice you have been given, if you think you need that many columns, you probably need to take a look at your database design, I have personally never heard of a case that would need that.
Note: As mentioned by #GDP you can have only 4096 cols and definitely the idea is not appreciated and as again #GDP said that database design ideas need to be explored to consider if something else could be a better way to handle this requirement.
However, I was just wondering apart from the absurd requirement if ever I need to do this how can I do it? I thought why not create a custom / user defined MySQL function e.g. create_table() tht will receive the parameters you intend to send and which will in turn generate the required CREATE TABLE command.
This is an option for finding columns using ordinal values. It might not be the most elegant or efficient but it works. I am using it to create a new table for faster mappings between data that I need to parse through all the columns / rows.
DECLARE #sqlCommand varchar(1000)
DECLARE #columnNames TABLE (colName varchar(64), colIndex int)
DECLARE #TableName varchar(64) = 'YOURTABLE' --Table Name
DECLARE #rowNumber int = 2 -- y axis
DECLARE #colNumber int = 24 -- x axis
DECLARE #myColumnToOrderBy varchar(64) = 'ID' --use primary key
--Store column names in a temp table
INSERT INTO #columnNames (colName, colIndex)
SELECT COL.name AS ColumnName, ROW_NUMBER() OVER (ORDER BY (SELECT 1))
FROM sys.tables AS TAB
INNER JOIN sys.columns AS COL ON COL.object_id = TAB.object_id
WHERE TAB.name = #TableName
ORDER BY COL.column_id;
DECLARE #colName varchar(64)
SELECT #colName = colName FROM #columnNames WHERE colIndex = #colNumber
--Create Dynamic Query to retrieve the x,y coordinates from table
SET #sqlCommand = 'SELECT ' + #colName + ' FROM (SELECT ' + #colName + ', ROW_NUMBER() OVER (ORDER BY ' + #myColumnToOrderBy+ ') AS RowNum FROM ' + #tableName + ') t2 WHERE RowNum = ' + CAST(#rowNumber AS varchar(5))
EXEC(#sqlCommand)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I merge two MySql tables?
I want to merge multiple tables that have the same structure and make one large table. The tables have similar names, so I want to use the LIKE statement. Can anyone tell me how I can do this?
The tables are very simple, each having an ID column and a few other columns, but there are a large amount of tables, all of which have names like 'TX-xxx', where 'TX' means Texas, and 'xxx' are the counties in Texas; you know there are more than 200 counties in Texas. (In fact, I have to do this for all the states.) So I want to use the statement "LIKE 'TX-___'".
Thanks!
You would have to give more information so we know exactly what you want but you could create a view
CREATE VIEW myViewName AS
select *
from table1
union all
select * from
table2
This way it would show the information from all your tables (and can be limited so in the selects to not show everything) and when table1, table2, etc are changed the view will reflect this. You can change it at anytime and fetch from it as you would a table:
select * from myViewName
Now for grabbing from specific tables I am not sure how you can do this in mysql though I have done it in tsql. This previous question would help you so you might have something like:
-- Create temporary table of varchar(200) to store the name of the tables. Depending on how you want to go through the array maybe an id number (int).
insert into tempTableName (name)
SELECT table_name FROM information_schema.tables WHERE table_schema = 'database_name' and table_name like 'TX_%';
declare #sqlQuery varchar(max)
--Then you will want to loop through the array and build up an sql statement
-- For each loop through:
if len(#sqlQuery) = 0 begin -- first time through
set #sqlQuery = 'select col1, col2, col3 from ' + currentTableName
end else begin -- second+ time through
set #sqlQuery = 'union all select col1, col2, col3 from ' + currentTableName
end
-- after the loop add the create view. Could double check it worked by checking length = 0 again
set #sqlQuery = 'CREATE VIEW myViewName AS ' + #sqlQuery
Once the query string is built up you will execute it with
PREPARE stmt FROM #sqlQuery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
If I understand your question correctly UNION is what you need. Something like
SELECT field1, field2
FROM (
SELECT field1, field2 from table1
UNION
SELECT field1, field2 from table2
) all_tables
WHERE all_tables.field1 like "%whatever%
Assuming they have the same columns or similar:
insert into #table
Select * from (Select * from tbl1
Union
select * from tbl2
Union
select * from tbl3)
If they don't have the same number/type of columns then you should provide us with that information.