i'm creating history table associated with each master table based on following query
SELECT TOP 0 * INTO HISTORY_TABLE FROM MASTER_TABLE
this query creates an empty table named HISTORY_TABLE consisting of columns similar to columns in MASTER_TABLE but with constraint's that are applied to the MASTER_TABLE.
so is their any way to get columns without constraints?
This may not be good idea, but this does what you want..
//This creates the table with constraints
SELECT TOP 0 * INTO HISTORY_TABLE FROM MASTER_TABLE
//This will drop all the constraints
DECLARE #database NVARCHAR(50)
DECLARE #table NVARCHAR(50)
DECLARE #sql NVARCHAR(255)
SET #database = 'databasename'
SET #table = 'HISTORY_TABLE'
WHILE EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE constraint_catalog=#database AND table_name=#table)
BEGIN
SELECT #sql = 'ALTER TABLE ' + #table + ' DROP CONSTRAINT ' + CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE constraint_catalog=#database AND table_name=#table
EXEC sp_executesql #sql
END
I hope this helps.
This gets you a table with a clean set of columns.
select top 0 * into #bounce from MASTER_TABLE
select * into HISTORY_TABLE from #bounce
But they are so clean you'll need to define the PK, indexes, etc. (but you may need those to be different on a history table anyway...)
Related
I am trying to do something a little weird and cannot figure out the right method for getting it done. Essentially I am trying to pull all tables/views and columns where the column name is like some string. In addition to that I would like to pull 1 row of data from that table/view and column combination. The second part is where I am lost. I know I can pull the necessary tables/views and columns with the below select statement.
SELECT COLUMN_NAME AS 'ColumnName'
,TABLE_NAME AS 'TableName'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%email%'
ORDER BY TableName,ColumnName;
So that I get something like the below
|ColumnName |TableName |
|emailAddress |all_emails |
....
But I want to get something like this:
|ColumnName |TableName |Example |
|emailAddress |all_emails |first.last#gmail.com|
....
Can anyone offer any insight?
I can't think of a simple way to do this within a query, but here's one option...
Put the list of the columns and tables into a temp table and run them through a loop, using dynamic SQL to select the max row for each.
I've added plenty of comments below to explain it.
DECLARE #SQL NVARCHAR(1000)
DECLARE #TABLE NVARCHAR(1000)
DECLARE #COLUMN NVARCHAR(1000)
DECLARE #SAMPLE NVARCHAR(1000)
DROP TABLE IF EXISTS ##TABLELIST
SELECT COLUMN_NAME AS 'ColumnName'
,TABLE_NAME AS 'TableName'
,ROW_NUMBER() OVER (ORDER BY COLUMN_NAME,TABLE_NAME)[RN]
INTO ##TABLELIST
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%email%';
ALTER TABLE ##TABLELIST
ADD [Sample] NVARCHAR(1000) -- Add a column for your sample row.
DECLARE #ROWCOUNTER INT = 1 -- Add a counter for the loop to use.
WHILE #ROWCOUNTER <= (SELECT MAX([RN]) FROM ##TABLELIST) -- Keep the loop running until the end of the list.
BEGIN
UPDATE ##TABLELIST
SET #TABLE = TableName WHERE [RN] = #ROWCOUNTER -- Get the table name into a variable.
UPDATE ##TABLELIST
SET #COLUMN = ColumnName WHERE [RN] = #ROWCOUNTER -- Get the column name into a variable.
SET #SQL = 'SELECT #SAMPLE = MAX([' + #COLUMN + ']) FROM [' + #TABLE + ']' -- Create SQL statement to pull max column from table specified in variables.
EXEC SP_EXECUTESQL #SQL, N'#SAMPLE NVARCHAR(1000) OUTPUT', #SAMPLE OUTPUT -- Execute SQL and put the output into the #SAMPLE variable.
UPDATE ##TABLELIST
SET [Sample] = CAST(#SAMPLE AS NVARCHAR(1000)) WHERE [RN] = #ROWCOUNTER -- Insert the SQL output into the sample column.
SET #ROWCOUNTER = #ROWCOUNTER+1 -- Add one to the row counter to move to the next column and table.
END
SELECT * FROM ##TABLELIST -- Select final output.
I have 1900 tables like table_1, table_2 and ........... which structure are same.
I want to insert all data to a new table table_all.
I know using UNION ALL I can do that but that's no useful as number of tables are large.
I made a procedure and it's working fine.
DROP PROCEDURE IF EXISTS insert_from_multiple_table;
CREATE PROCEDURE insert_from_multiple_table()
Begin
DECLARE tableCount INT DEFAULT 0;
SELECT COUNT(*)
INTO tableCount
FROM information_schema.TABLES where table_name like 'table_%' and table_Schema='your_db';
WHILE tableCount>0 DO
SET #dt_ncv = CONCAT("table_",tableCount);
SET #cntstmt = CONCAT( "insert into alltable select * FROM ",#dt_ncv);
#select #cntstmt;
PREPARE ncv_count_stmt FROM #cntstmt;
EXECUTE ncv_count_stmt;
SET tableCount = tableCount-1;
END WHILE ;
END
Is there any SQL lingo to return JUST the first two columns of a table WITHOUT knowing the field names?
Something like
SELECT Column(1), Column(2) FROM Table_Name
Or do I have to go the long way around and find out the column names first? How would I do that?
You have to get the column names first. Most platforms support this:
select column_name,ordinal_position
from information_schema.columns
where table_schema = ...
and table_name = ...
and ordinal_position <= 2
There it´s
declare #select varchar(max)
set #select = 'select '
select #select=#select+COLUMN_NAME+','
from information_schema.columns
where table_name = 'TABLE' and ordinal_position <= 2
set #select=LEFT(#select,LEN(#select)-1)+' from TABLE'
exec(#select)
A dynamic query using for xml path will also do the job:
declare #sql varchar(max)
set #sql = (SELECT top 2 COLUMN_NAME + ',' from information_schema.columns where table_name = 'YOUR_TABLE_NAME_HERE' order by ordinal_position for xml path(''))
set #sql = (SELECT replace(#sql +' ',', ',''))
exec('SELECT ' + #sql + ' from YOUR_TABLE_NAME_HERE')
I wrote a stored procedure a while back to do this exact job. Even though in relational theory there is no technical column order SSMS is not completely relational. The system stores the order in which the columns were inserted and assigns an ID to them. This order is followed using the typical SELECT * statement which is why your SELECT statements appear to return the same order each time. In practice its never a good idea to SELECT * with anything as it doesn't lock the result order in terms of columns or rows. That said I think people get so stuck on 'you shouldn't do this' that they don't write scripts that actually can do it. Fact is there is predictable system behavior so why not use it if the task isn't super important.
This SPROC of course has caveats and is written in T-SQL but if your looking to just return all of the values with the same behavior of SELECT * then this should do the job pretty easy for you. Put in your table name, the amount of columns, and hit F5. It returns them in order from left to right the same as you'd be expecting. I limited it to only 5 columns but you can edit the logic if you need any more. Takes both temp and permanent tables.
EXEC OnlySomeColumns 'MyTable', 3
/*------------------------------------------------------------------------------------------------------------------
Document Title: The Unknown SELECT SPROC.sql
Created By: CR
Date: 4.28.2013
Purpose: Returns all results from temp or permanent table when not knowing the column names
SPROC Input Example: EXEC OnlySomeColumns 'MyTable', 3
--------------------------------------------------------------------------------------------------------------------*/
IF OBJECT_ID ('OnlySomeColumns', 'P') IS NOT NULL
DROP PROCEDURE OnlySomeColumns;
GO
CREATE PROCEDURE OnlySomeColumns
#TableName VARCHAR (1000),
#TotalColumns INT
AS
DECLARE #Column1 VARCHAR (1000),
#Column2 VARCHAR (1000),
#Column3 VARCHAR (1000),
#Column4 VARCHAR (1000),
#Column5 VARCHAR (1000),
#SQL VARCHAR (1000),
#TempTable VARCHAR (1000),
#PermanentTable VARCHAR (1000),
#ColumnNamesAll VARCHAR (1000)
--First determine if this is a temp table or permanent table
IF #TableName LIKE '%#%' BEGIN SET #TempTable = #TableName END --If a temporary table
IF #TableName NOT LIKE '%#%' BEGIN SET #PermanentTable = #TableName END --If a permanent column name
SET NOCOUNT ON
--Start with a few simple error checks
IF ( #TempTable = 'NULL' AND #PermanentTable = 'NULL' )
BEGIN
RAISERROR ( 'ERROR: Please select a TempTable or Permanent Table.',16,1 )
END
IF ( #TempTable <> 'NULL' AND #PermanentTable <> 'NULL' )
BEGIN
RAISERROR ( 'ERROR: Only one table can be selected at a time. Please adjust your table selection.',16,1 )
END
IF ( #TotalColumns IS NULL )
BEGIN
RAISERROR ( 'ERROR: Please select a value for #TotalColumns.',16,1 )
END
--Temp table to gather the names of the columns
IF Object_id('tempdb..#TempName') IS NOT NULL DROP TABLE #TempName
CREATE TABLE #TempName ( ID INT, Name VARCHAR (1000) )
--Select the column order from a temp table
IF #TempTable <> 'NULL'
BEGIN
--Verify the temp table exists
IF NOT EXISTS ( SELECT 1
FROM tempdb.sys.columns
WHERE object_id = object_id ('tempdb..' + #TempTable +'') )
BEGIN
RAISERROR ( 'ERROR: Your TempTable does not exist - Please select a valid TempTable.',16,1 )
RETURN
END
SET #SQL = 'INSERT INTO #TempName
SELECT column_id AS ID, Name
FROM tempdb.sys.columns
WHERE object_id = object_id (''tempdb..' + #TempTable +''')
ORDER BY column_id'
EXEC (#SQL)
END
--From a permanent table
IF #PermanentTable <> 'NULL'
BEGIN
--Verify the temp table exists
IF NOT EXISTS ( SELECT 1
FROM syscolumns
WHERE id = ( SELECT id
FROM sysobjects
WHERE Name = '' + #PermanentTable + '' ) )
BEGIN
RAISERROR ( 'ERROR: Your Table does not exist - Please select a valid Table.',16,1 )
RETURN
END
SET #SQL = 'INSERT INTO #TempName
SELECT colorder AS ID, Name
FROM syscolumns
WHERE id = ( SELECT id
FROM sysobjects
WHERE Name = ''' + #PermanentTable + ''' )
ORDER BY colorder'
EXEC (#SQL)
END
--Set the names of the columns
IF #TotalColumns >= 1 BEGIN SET #Column1 = (SELECT Name FROM #TempName WHERE ID = 1) END
IF #TotalColumns >= 2 BEGIN SET #Column2 = (SELECT Name FROM #TempName WHERE ID = 2) END
IF #TotalColumns >= 3 BEGIN SET #Column3 = (SELECT Name FROM #TempName WHERE ID = 3) END
IF #TotalColumns >= 4 BEGIN SET #Column4 = (SELECT Name FROM #TempName WHERE ID = 4) END
IF #TotalColumns >= 5 BEGIN SET #Column5 = (SELECT Name FROM #TempName WHERE ID = 5) END
--Create a select list of only the column names you want
IF Object_id('tempdb..#FinalNames') IS NOT NULL DROP TABLE #FinalNames
CREATE TABLE #FinalNames ( ID INT, Name VARCHAR (1000) )
INSERT #FinalNames
SELECT '1' AS ID, #Column1 AS Name UNION ALL
SELECT '2' AS ID, #Column2 AS Name UNION ALL
SELECT '3' AS ID, #Column3 AS Name UNION ALL
SELECT '4' AS ID, #Column4 AS Name UNION ALL
SELECT '5' AS ID, #Column5 AS Name
--Comma Delimite the names to insert into a select statement. Bracket the names in case there are spaces
SELECT #ColumnNamesAll = COALESCE(#ColumnNamesAll + '], [' ,'[') + Name
FROM #FinalNames
WHERE Name IS NOT NULL
ORDER BY ID
--Add an extra bracket at the end to complete the string
SELECT #ColumnNamesAll = #ColumnNamesAll + ']'
--Tell the user if they selected to many columns
IF ( #TotalColumns > 5 AND EXISTS (SELECT 1 FROM #FinalNames WHERE Name IS NOT NULL) )
BEGIN
SELECT 'This script has been designed for up to 5 columns' AS ERROR
UNION ALL
SELECT 'Only the first 5 columns have been selected' AS ERROR
END
IF Object_id('tempdb..#FinalNames') IS NOT NULL DROP TABLE ##OutputTable
--Select results using only the Columns you wanted
IF #TempTable <> 'NULL'
BEGIN
SET #SQL = 'SELECT ' + #ColumnNamesAll + '
INTO ##OutputTable
FROM ' + #TempTable + '
ORDER BY 1'
EXEC (#SQL)
END
IF #PermanentTable <> 'NULL'
BEGIN
SET #SQL = 'SELECT ' + #ColumnNamesAll + '
INTO ##OutputTable
FROM ' + #PermanentTable + '
ORDER BY 1'
EXEC (#SQL)
END
SELECT *
FROM ##OutputTable
SET NOCOUNT OFF
SQL doesn't understand the order of columns. You need to know the column names to get them.
You can look into querying the information_schema to get the column names. For example:
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'tbl_name'
ORDER BY ordinal_position
LIMIT 2;
You can query the sysobject of the table to find out the first two column then dynamically generate the SQL statement you need.
If you want a permant object that you can query over and over again make a view for each table that only returns the first 2 columns. You can name the columns Column1 and Column2 or use the existing names.
If you want to return the first two columns from any table without any preprocessing steps create a stored procedure that queries the system information and executes a dynamic query that return the first two columns from the table.
Or do I have to go the long way around and find out the column names first? How would I do that?
It's pretty easy to do manually.
Just run this first
select * from tbl where 1=0
This statement works on all major DBMS without needing any system catalogs.
That gives you all the column names, then all you need to do is type the first two
select colname1, colnum2 from tbl
How to INSERT into another table except specific field
e.g
TABLE A
ID(auto_inc) CODE NAME
1 001 TEST1
2 002 TEST2
I want to insert CODE and NAME to another table, in this case TABLE B but except ID because it is auto increment
Note: I don't want to use "INSERT INTO TABLE B SELECT CODE, NAME FROM TABLE A", because I have an existing table with around 50 fields and I don't want to write it one by one
Thanks for any suggests and replies
This can't be done without specifying the columns (excludes the primary key).
This question might help you. Copy data into another table
You can get all the columns using information_schema.columns:
select group_concat(column_name separator ', ')
from information_schema.columns c
where table_name = 'tableA' and
column_name <> 'id';
This gives you the list. Then past the list into your code. You can also use a prepared statement for this, but a prepared statement might be overkill.
If this is a one time thing?
If yes, do the insert into tableA (select * from table B)
then Alter the table to drop the column that your dont need.
I tried to copy from a table to another one with one extra field.
source table is TERRITORY_t
* the principle is to create a temp table identical to the source table, adjust column fields of the temp table and copy the content of the temp table to the destination table.
This is what I did:
create a temp table called TERRITORY_temp
generate SQL by running export
CREATE TABLE IF NOT EXISTS TERRITORY_temp (
Territory_Id int(11) NOT NULL,
Territory_Name varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (Territory_Id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
copy over with
INSERT INTO TERRITORY_temp (Territory_Id, Territory_Name) VALUES
(1, 'SouthEast'),
(2, 'SouthWest'),
(3, 'NorthEast'),
(4, 'NorthWest'),
(5, 'Central');
or
INSERT INTO TERRITORY_temp
SELECT * from TERRITORY_t
add the extra field(s) to match with the new table
copy from the temp table to the destination table
INSERT INTO TERRITORY_new
SELECT * from TERRITORY_temp
Please provide feedback.
Step 1. Create stored procedure
CREATE PROCEDURE CopyDataTable
#SourceTable varchar(255),
#TargetTable varchar(255),
#SourceFilter nvarchar(max) = ''
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SourceColumns VARCHAR(MAX)=''
DECLARE #TargetColumns VARCHAR(MAX)=''
DECLARE #Query VARCHAR(MAX)=''
SELECT
#SourceColumns = ISNULL(#SourceColumns +',', '') + T.COLUMN_NAME
FROM
(
select name as COLUMN_NAME from sys.all_columns
where object_id = (select object_id from sys.tables where name = #SourceTable)
and is_identity = 0
)T
SELECT
#TargetColumns = ISNULL(#TargetColumns +',', '') + T.COLUMN_NAME
FROM
(
select name as COLUMN_NAME from sys.all_columns
where object_id = (select object_id from sys.tables where name = #TargetTable)
and is_identity = 0
)T
set #Query = 'INSERT INTO ' + #TargetTable + ' (' + SUBSTRING(#TargetColumns,2 , 9999) + ') SELECT ' + SUBSTRING(#SourceColumns,2 , 9999) + ' FROM ' + #SourceTable + ' ' + #SourceFilter;
PRINT #Query
--EXEC(#Query)
END
GO
Step 2. Run stored procedure
use YourDatabaseName
exec dbo.CopyDataTable 'SourceTable','TargetTable'
Explanations
a) dbo.CopyDataTable will transfer all data from SourceTable to TargetTable, except field with Identity
b) You can apply filter when call stored procedure, in order to transfer only row based on criteria
exec dbo.CopyDataTable 'SourceTable','TargetTable', 'WHERE FieldName=3'
exec dbo.CopyDataTable 'SourceTable','TargetTable', 'WHERE FieldName=''TextValue'''
c) Remove -- from --EXEC(#Query) WHEN finish
I am copying the data to temporary table using select statement which produces the result of pivoting.
My procedure is:
alter procedure proc11 AS
create Table #Temp (Software varchar(max), Ver varchar(max))
declare #cols varchar(max)
declare #colTabl varchar(max)
declare #alter varchar(max)
set #cols=STUFF((select distinct ',[' + Ltrim(rtrim(YEAR(Dt))) +']' from temp FOR XML PATH('')),1,1,'');
set #colTabl=STUFF((select distinct '[' + Ltrim(rtrim(YEAR(Dt))) +'] int,' from temp FOR XML PATH('')),1,0,'');
set #colTabl= LEFT(#colTabl,len(#colTabl)-1);
set #alter = 'alter table #Temp add '+ #colTabl;
exec(#alter)
EXEC('select * into #Temp from
(select YEAR(Dt)[year],Software,Ver from temp)T
Pivot(count([year]) for [year] in ('+#cols+'))PVT')
But the statement select * from #Temp returns no record.
How do I copy these records.
Please help. Thanks in advance.
It's because '#' temporary tables are kept just for the duration of current connection, and visible only in it's scope. Even if you create a temp table, open another tab in SSMS and try to use it, you you'll see "table does not exist" error.
What happens is, that your EXEC statement create the #Temp table, and when it finieshes, the table is immediately dropped. Not only that - #Temp table from CREATE statement, and #Temp from EXEC statement are in fact different tables! Try creating two #temp tables in different SSMS tabs and you'll see they're in fact not the same.
You could use global temp tables. Just change the name to ##Temp and it should work.
Run these two examples.
This won't work:
EXEC('select * into #Temp from (select ''something'' as x) x');
select * from #Temp
And this one will (when you run it second time you'll notice "table already exists" error:
EXEC('select * into ##Temp from (select ''something'' as x) x');
select * from ##Temp
EXEC('insert #Temp select * from
(select YEAR(Dt)[year],Software,Ver from temp)T
Pivot(count([year]) for [year] in ('+#cols+'))PVT order by Software')
Or simply remove the INSERT from the dynamic portion:
INSERT INTO #temp
EXEC(select * from
(select YEAR(Dt)[year],Software,Ver from temp)T
Pivot(count([year]) for [year] in ('+#cols+'))PVT order by Software')