Select query using the result (columns from the select from Info_schema) - mysql

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.

Related

Copy data into same table with different value for some columns

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.

Mysql How to only select from a column if the column exists

I need to be able to check if a column exists and if it does then I want to SELECT from it.
I am trying lots of different variations but I'm not even sure if this is possible.
Here's my latest attempt:
SELECT
IF (EXISTS (SELECT `Period` AS `Period` FROM myview), `PERIOD`,
IF (EXISTS (SELECT `Country` AS `COUNTRY` FROM myview),`COUNTRY` FROM myview ;
Any ideas?
EDIT
I had seen the other question on here: MySQL, Check if a column exists in a table with SQL
But I still struggle with the if statement. I can check to see if the column exists using the answer in the question above. But my question is - how to execute a select statement from that column if the result is found to be true.
EDIT 2
The answer below indicates that I should use the BEGIN and END statement and this makes sense. However, my query complains at the first line. It says 'unexpected IF' - can anybody confirm if this is the right syntax fro MYSQL?
if( exists (SELECT *
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'db_name'
AND TABLE_NAME = 'view_name'
AND COLUMN_NAME = 'column_name') )
begin
SELECT `column_name` FROM `view_name`
end
Thanks in advance.
This query will give you whether a column exists.
SELECT *
FROM information_schema.COLUMNS
WHERE
TABLE_SCHEMA = 'db_name'
AND TABLE_NAME = 'table_name'
AND COLUMN_NAME = 'column_name'
If you want to check if some columns exist then perform a select statement you need to first check your columns exist. Then perform the select:
if (exists (SELECT * FROM information_schema.COLUMNS WHERE TABLE_NAME = 'myview' AND COLUMN_NAME = 'Period') and exists (SELECT * FROM information_schema.COLUMNS WHERE TABLE_NAME = 'myview' AND COLUMN_NAME = 'Country'))
begin
select `Period`, `Country` from myview
end
If the IF condition is true, then you will execute anything inside the BEGIN and END.
I came across the same situation where I had some product tables created by sheets uploaded by users. Sometimes, the sheets did not have column named "obsolete", so I had to import all products from the sheet but not the obsolete ones.
I am not modifying my query based on the original question that was asked, but here is my solution:
SELECT
t2.model,
(
SELECT
COUNT(*) AS _count
FROM db.table t1
WHERE
`obsolete`=1
AND t1.model=t2.model
) AS `obsolete`
FROM (
SELECT
0 AS `obsolete`,
t3.model
FROM db.table t3
) t2
There are 2 most important parts in this query:
We are selecting 0 AS obsolete as dummy to fool MySql which will be used even if column does not exist when selecting COUNT(*).
We have named tables as t1 & t2 to match the column model as t1.model=t2.model.

How to get rows whose columns values are not null

I want to get rows of a table such that no column value is null. No hardcoding of column values. I have hundreds of column names so.
Output should be only row 2 since all that row has the values for all the columns. I do not want to specify all the column names for is not null. It should take it programmatically. Even if i add a new column it should work without changing the query. That is my vision.
I found something, but that means using CURSOR
DECLARE #ColumnName VARCHAR(200)
DECLARE #ColumnCount INT
DECLARE #sql VARCHAR(400)
CREATE TABLE #tempTable (Id INT)
DECLARE GetNonNullRows CURSOR
FOR
SELECT c.NAME, (SELECT COUNT(*) FROM sys.columns col WHERE col.object_id = c.OBJECT_ID) FROM sys.tables AS t
JOIN sys.columns AS c ON t.object_id = c.object_id
WHERE t.name = 'SomeTable' AND t.type = 'U'
OPEN GetNonNullRows
FETCH NEXT FROM GetNonNullRows INTO #ColumnName, #ColumnCount
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'SELECT st.UniqueId FROM SomeTable AS st WHERE ' + CONVERT(varchar, #ColumnName) + ' IS NOT NULL'
INSERT INTO #tempTable
EXEC (#sql)
FETCH NEXT FROM GetNonNullRows INTO #ColumnName, #ColumnCount
END
CLOSE GetNonNullRows
DEALLOCATE GetNonNullRows
SELECT * FROM SomeTable AS st1
WHERE st1.UniqueId IN (SELECT Id FROM #tempTable AS tt
GROUP BY Id
HAVING COUNT(Id) = #ColumnCount)
DROP TABLE #tempTable
Let me to explain this a little.
First i create cursor which iterate through all the columns of one table. For each column, I've create sql script to search in table for not null values for selected column. For those rows that satisfies criteria, I take its unique ID and put in temp table, and this job I am using for all columns.
At the end only ID's which count is like columns count are your result set, because only rows that have identical number of appearances like number of columns in table may be rows with all non null values in all columns.
Try this ::
SELECT * FROM mytable WHERE column IS NOT NULL
try this
SELECT *
FROM your_table_name
where coalesce(column_1, column_2, column_3, ...., column_n) is not null
SQL alone cannot express such a concept.
You have to dinamically build the SQL query according to the table definition using some procedural language.
In Oracle you can use the dictionay view USER_TAB_COLUMNS to build the column list.
try using IS NOT NULL
SELECT * FROM table WHERE field_name IS NOT NULL
For more information, check out the mysql manual on working with null values.

Is it possible to name column by index

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)

How to merge multiple tables with similar names in MySQL [duplicate]

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.