Alter table structure to match copy table - sql

I have 2 tables corporate and corporate_copy. Initially they were same in structure but people started added new columns into corporate and forgot do do so for corporate_copy.
Somewhere in the application there is less used functionality that copies data from corporate to corporate_copy and that kept failing without anyone noticing. Now I have to add 28 columns (ofcourse with same type and length and constraints etc....).
I know it can be done in one ALTER TABLE statement but I still feel it is lengthy task.
Do we have any luxury that will make copy table same as main table by keeping data and adding default values in newly added columns?
I am asking much but is there anything like that?

--Generate a dynamic query which contain all the missing column list and Execute it
--for eg I tried Something
BEGIN TRAN
DECLARE #SqlSelect NVARCHAR(MAX),#ColumnDeclaration VARCHAR(2000)
SELECT DISTINCT ' '+COLUMN_NAME+' '+ DATA_TYPE +' '+ISNULL(CONVERT(NVARCHAR(10), CHARACTER_MAXIMUM_LENGTH ),'')+' 'Missing_Column INTO #T FROM INFORMATION_SCHEMA.COLUMNS a
WHERE a.column_name not in (SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS b
WHERE b.table_name in ('Corporate_Copy'))
and a.table_name in ('Corporate')
SELECT #ColumnDeclaration=STUFF((
SELECT ', ' + Missing_Column
FROM #T
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(max)'), 1, 1, '')
SET #SqlSelect=' ALTER TABLE Corporate_Copy Add'+ #ColumnDeclaration + ');'
PRINT #SqlSelect
ROLLBACK TRAN

You could use schema compare, found in SQL Server data tools (free) to generate a change script automatically.
But if this is just a copy, you could just run this:
DROP TABLE Corporate_Copy;
SELECT *
INTO Corporate_Copy
FROM Corporate;
It's not clear whether you really need to preserve the data in the copy. If so, it's not really a copy is it?

From SQL-Server 2015, you can use the following query to extract all different columns between 2 tables:
select distinct a.* from INFORMATION_SCHEMA.COLUMNS a
where a.column_name not in (select column_name from INFORMATION_SCHEMA.COLUMNS b
where b.table_name in ('tbl_A'))
and a.table_name in ('tbl_B')
order by a.column_name
The output gives you enough information to create a simple script to add the columns which are missing:
For exmaple:
Alter table tbl_A ADD res.Column_Name res.Data_Type ....

generate CREATE script in SSMS (right-click on table, then "script table as...")
Delete all things that already exists. Usually they are in the begining and it's a simple
change CREATE to ALTER ... ADD

That should be possible using SELECT INTO, for example the following SQL statement creates a backup copy of corporate:
SELECT * INTO corporate_copy
FROM corporate ;

Related

Delete columns from multiple tables

I have 4 columns that are repeated in all the tables in the database and I have to delete them
How can I do this deletion without having to enter table by table?
This code will output the necessary SQL to make the changes.
STRING_AGG is used twice to group up the columns and tables. QUOTENAME is used to place brackets around names correctly.
SELECT STRING_AGG(
N'ALTER TABLE ' + QUOTENAME(SCHEMA_NAME(t.schema_id)) + N'.' + QUOTENAME(t.object_id) + N'
' + c.ColumnSql, N'
')
FROM sys.tables t
CROSS APPLY (
SELECT ColumnSql = STRING_AGG(CAST(N'DROP COLUMN ' + QUOTENAME(c.name) AS nvarchar(max), N'
')
FROM sys.columns c
WHERE c.object_id = t.object_id
AND c.name IN (
'ID_Integracion_CodBodega',
'ID_Integracion_FechaUltRep',
'ID_Integracion_ControlTrigger',
'ID_Integracion_CodBodega_Origen'
)
) c
You can execute it all together by using
DECLARE #sql nvarchar(max) = (
SELECT STRING_AGG.....
);
EXEC(#sql);
I caution you against using INFORMATION_SCHEMA because it is only there for compatibility.
SQL Server provides system information schema views that can be queried to retrieve information about the database.
In your case, the COLUMNS view can be used to fetch the names of all tables containing a specific column name.
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME IN (
'ID_Integracion_CodBodega',
'ID_Integracion_FechaUltRep',
'ID_Integracion_ControlTrigger',
'ID_Integracion_CodBodega_Origen'
);
From there, you can use the normal process to delete a column from an existing table.
ALTER TABLE [table_name] DROP COLUMN [column_name];
You should be very careful with this approach. It is easy to drop a column you didn't mean to.
Be aware of any constraints/dependencies in your database schema that you might be affecting with this action.
Are there constraints on your tables that will be affected by the removal of these columns? (Especially ON DELETE CASCADE constraints that may impact other tables).
Are there views/stored procedures/triggers that depend on these columns?
Do you have queries/dynamic SQL that will be impacted by the removal of these columns?

How to check if a value exists in any of the columns in a table in sql

Say, I have 100 columns in a table. I do not know in which columns a particular value could exist. So, I would like to check across all columns, if it exists in any of the 100 columns, I would like to select it.
I searched around a bit, and in most places the solution seems to be something like the following
select *
from tablename
where col1='myval'
or col2='myval'
or col3='myval'
or .. or col100='myval'
I also read a few forums where having to do this is said to be a bad case of database design, I agree, but I'm working on an already existing table in a database.
Is there a more intelligent way to do this?
One way is by reversing the In operator
select *
from yourtable
where 'Myval' in (col1,col2,col3,...)
If you don't want to manually type the columns use dynamic sql to generate the query
declare #sql varchar(max)='select *
from yourtable
where ''Myval'' in ('
select #sql+=quotename(column_name)+',' from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME='yourtable'
select #sql =left(#sql,len(#sql)-1)+')'
--print #sql
exec sp_executesql #sql

Querying the same table for a list of databases in MS SQL Server

This is my first time posting on SO, so please go easy!
I'm attempting to write a SQL script that queries the same table for a list of databases in a single SQL Server instance.
I have successfully queried the list of databases that I required using the following, and inserting this data into a temp table.
Select name Into #Versions
From sys.databases
Where name Like 'Master%'
Master is suffixed with numerical values to identify different environments.
Select * From #Versions
Drop Table #Versions
The table name I am trying to query, is the same in each of the databases, and I want to extract the newest value from this table and insert it into the temp table for each of the database names returned.
I have tried researching this but to no avail. I am fairly comfy with SQL but I fear I could be out of my depth here.
You can do the following. Once you have the list of your databases, you can build up the query (you need to edit it for your purpose).
Select name Into #Versions
From sys.databases
Where name Like 'test%'
declare #sql as varchar(max) = ''
select #sql = #sql + 'INSERT INTO sometable SELECT TOP 1 * FROM ' + name + '..sourcetable ORDER BY somedate DESC; '
FROM #Versions
exec (#sql)
Drop Table #Versions
Look at The undocumented sp_MSforeachdb procedure and here

SQL - INFORMATION_SCHEMA for All Databases On Server

INFORMATION_SCHEMA.TABLES or INFORMATION_SCHEMA.COLUMNS work for only specified databases.
Is it possible to query table metadata for ALL databases on server by using INFORMATION_SCHEMA?
You can do this only by using dynamic query for database iteration. One way is using ms_ForEachDB stored procedure, second is querying sys.databases dynamic view.
Expanding Dalex's answer into code.
--Make sure you have a global temporary table to use. Double dots are shorthand for .dbo.
IF OBJECT_ID('tempdb..##test') IS NOT NULL DROP TABLE ##test
--Create the table definition the easy way.
SELECT * INTO ##test
FROM ???.INFORMATION_SCHEMA.TABLES --The ??? will be whatever the name of your first database is.
DELETE FROM ##test
--Add all the data.
EXEC sp_MSforeachdb 'USE ? INSERT INTO ##test SELECT * FROM INFORMATION_SCHEMA.TABLES'
--View all the data.
SELECT * FROM ##test
--Clean up.
DROP TABLE ##test
Modified Dustin's code (from Dalex's suggestion) to accommodate database names with spaces and eliminate common system tables from results.
--Make sure you have a global temporary table to use. Double dots are shorthand for .dbo.
IF OBJECT_ID('tempdb..##test') IS NOT NULL DROP TABLE ##test
--Create the table definition the easy way.
SELECT top 1 * INTO ##test
FROM INFORMATION_SCHEMA.TABLES
DELETE FROM ##test
--Add all the data.
EXEC sp_MSforeachdb 'USE [?] INSERT INTO ##test SELECT * FROM INFORMATION_SCHEMA.TABLES'
--View all the data.
SELECT * FROM ##test
WHERE TABLE_CATALOG NOT IN ('master','tempdb', 'msdb')
ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME
--Clean up.
DROP TABLE ##test
You can use this:
SELECT TABLE_SCHEMA
FROM information_schema.tables
group by tables.TABLE_SCHEMA
This isn't the answer to the question but this text adds context ... and text is likely to be useful to someone to gain understanding.
It is possible and often required to add a use clause to select which database is being referenced above the select clause ..
e.g.
use CaseData
SELECT *
FROM information_schema.columns
--WHERE
--TABLE_CATALOG = 'CaseData'
--and TABLE_SCHEMA ='Clinical'
--and
--TABLE_NAME = 'SAASCaseData_NewFieldsOct2018'
SELECT DISTINCT `TABLE_SCHEMA` FROM `information_schema`.`TABLES`;

Select all columns from all tables in SQL Server 2008

How can I Select all columns from all tables from the DB, like:
Select * From *
in SQL Server 2008???
The table list it´s very very big, and have so many columns, is it possible to do it without writing the column names?
Or maybe make a select that returns the name of the tables.
This SQL will do this...
DECLARE #SQL AS VarChar(MAX)
SET #SQL = ''
SELECT #SQL = #SQL + 'SELECT * FROM ' + TABLE_SCHEMA + '.[' + TABLE_NAME + ']' + CHAR(13)
FROM INFORMATION_SCHEMA.TABLES
EXEC (#SQL)
Try this, works fine
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
then you could add
WHERE TABLE_NAME LIKE '' AND COLUMN_NAME LIKE ''
SELECT t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID where t.name = 'ProductItem' AND C.name like '%retail%'
ORDER BY schema_name, table_name
It is possible to retrieve the name of all columns from sys.columns
It is possible to retrieve the name of all table from sys.tables
But is impossible to retrieve all the data from all the tables. As soon as more than one table is involved in a query, a JOIN is necessary. Unless join conditions are provided, tables are joined as full Cartesian product, meaning each row from each table is matched with each row from ll other tables. Such a query as you request would produce for 10 tables with 10 records each no less than 10e10 records, ie. 100 billion records. I'm sure you don't want this.
Perhaps if you explain what you what to achieve, not how, we can help better.
To select * from each table, one after another, you can use the undocumented but well known sp_msforeachtable:
sp_msforeachtable 'select * from ?'
If you are going to send to Excel, I would suggest you use the export wizard and simply select all the tables there. In the object browser, put your cursor on the database name and right click. Chose Tasks - Export Data and follow the wizard. WHy anyone would want an entire database in Excel is beyond me, but that's the best way. If you need to do it more than once you can save the export in an SSIS package.
In SQL Server 2016 Management Studio ( Version: 13.0.15900.1), to get all column names in a specified table, below is the syntax:
**Select name from [YourDatabaseName].[sys].[all_columns]
where object_id=(Select object_id from [YourDatabaseName].[sys].[tables]
where name='YourTableName')**