T-SQL : Script to create view with columns from a select statement - sql-server

I have some bulk views to create for an entire database.
To create a view the general syntax is as follows:
CREATE VIEW [TABLE_NAME]
AS
SELECT [COLUMN1], [COLUMN2], [COLUMN3], [COLUMN4]
FROM [TABLE_NAME]
WITH CHECK OPTION;
I would like to set the column names in the script above by querying the column names ([COLULMN1], [COLUMN2], etc) from INFORMATION_SCHEMA.COLUMNS.
Is there a way to achieve this by table name?

COALESCE is your friend good programmer. What you want to do is get a csv list of COLUMNS. Then using dynamic sql you can auto generate the rest of the code.
declare #columns AS VARCHAR(MAX)
SELECT #COLUMNS = NULL
select #COLUMNS = coalesce(#columns+',','')+c.name from syscolumns as c
inner join sysobjects as o on c.id = o.id
WHERE O.NAME = 'change me to your table name'
SELECT #COLUMNS
SELECT ' CREATE VIEW ' + 'COOL VIEW NAME' + ' AS ' +
' SELECT ' + #COLUMNS +
' FROM '+ ' change me to your table name '+
' WITH CHECK OPTION;'
EDIT
I purposely didn't declare the view anywhere. If you want to declare the view just execute the scripts like so. BUT YOU SHOULD NEVER just execute code on your servers without reading it all I purposely excluded the execution part as I think it is bad judgement just to cut and paste code and execute it without understanding/testing.
DECLARE #sql varchar(max)
SELECT #sql = ' CREATE VIEW ' + 'COOL VIEW NAME' + ' AS ' +
' SELECT ' + #COLUMNS +
' FROM '+ ' change me to your table name '+
' WITH CHECK OPTION;'
EXEC(#sql);

Here's one option... replace "MyTableName" with the table name you want, or wrap it in a cursor that reads TABLE_NAME from INFORMATION_SCHEMA.VIEWS into #tableName:
DECLARE #tableName sysname;
DECLARE #sql nvarchar(max);
DECLARE #columnList nvarchar(max);
SELECT #tableName = 'MyTableName';
SELECT #columnList = '';
SELECT #columnList += CASE WHEN LEN(#columnList) = 0 THEN '' ELSE ', ' END + COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #tableName ORDER BY ORDINAL_POSITION;
SELECT #sql = 'CREATE VIEW [TABLE_NAME] AS
SELECT ' + #columnList + '
FROM [' + #tableName + ']
WITH CHECK OPTION;'
PRINT #sql
EXEC(#sql);

Related

Unpivot all other columns

Im new to Stack overflow and SQL and I'm trying to replicate a function in Microsoft Power Query to use in SQL instead.
I know how to Unpivot and keep 1 Column in SQL and then had to reference all the other columns by name to make the unpivot.
Now I need to Keep 3 ID columns and Unpivot the rest of the columns
(This table has 355 columns right now and will change)
Can anyone help me with this?
This is the furthest I got (Thanks to RAV DBLearning on Youtube), but I cant seem to find a way to Convert the columns types to 1 type.
DECLARE
#SQLSTRING NVARCHAR(MAX),
#COLUMNLIST NVARCHAR(1000) = ''
SELECT
#COLUMNLIST = #COLUMNLIST + QUOTENAME(NAME) + ','
FROM
sys.columns
WHERE
OBJECT_ID = OBJECT_ID('xp.XPROPERTYVALUES') AND
--COLUMN_ID NOT IN(1,2,3)
COLUMN_ID IN(452,453,454)
SELECT
#COLUMNLIST = LEFT(#COLUMNLIST,LEN(#COLUMNLIST)-1)
SET
#SQLSTRING =
'
SELECT
upv.id,
upv.item_id,
upv.itemtype_id,
upv.X_Category,
upv.X_Values
FROM
xp.XPROPERTYVALUES
UNPIVOT
(
X_Values FOR X_Category
IN
(' + #COLUMNLIST + ')
) AS upv
'
PRINT
(#SQLSTRING)
EXECUTE
sp_executesql #SQLSTRING
It just needs a source query.
And you can re-use the calculated column list for that.
DECLARE #SQLSTRING NVARCHAR(MAX),
#COLUMNLIST NVARCHAR(MAX);
DECLARE #TABLENAME VARCHAR(30) = 'xp.XPROPERTYVALUES';
SELECT #COLUMNLIST = CONCAT(#COLUMNLIST + ', ', QUOTENAME(NAME))
FROM sys.columns
WHERE OBJECT_ID = OBJECT_ID(#TABLENAME)
AND LOWER(NAME) NOT LIKE '%id';
SET #SQLSTRING = N'SELECT upv.id
, upv.item_id, upv.itemtype_id
, upv.X_Category, upv.X_Values
FROM
(
SELECT id, item_id, itemtype_id,
'+ #COLUMNLIST + N'
FROM '+ #TABLENAME +N'
) src
UNPIVOT
(
X_Values FOR X_Category IN (' + #COLUMNLIST + N')
) upv';
-- SELECT #SQLSTRING;
EXECUTE sp_executesql #SQLSTRING;
db<>fiddle here

Sequential Column names

Having a simple query such as:
select * from foo
Where the output has the columns
bar | abc | def
---------------
...............
It is possible to encapsulate this query into another one and give sequential names instead to the columns such as 1|2|3... (mantaining all the rows intact)?
I know this sounds weird and probably it isn't even possible.
Thanks for the help!
Try This
DECLARE #Sql NVARCHAR(max),
#TableName VARCHAR(100) = '<YourTableName>'
;WITH CTE
AS
(
SELECT DENSE_RANK()OVER (ORDER BY COLUMN_NAME) Rno,
TABLE_NAME,
COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_CATALOG='Database'
AND TABLE_NAME = #TableName
)
SELECT 'SELECT '+ STUFF((SELECT ', '+ COLUMN_NAME +' AS '+ QUOTENAME(CAST(Rno AS VARCHAR))
FROM CTE
FOR XML PATH ('')),1,1,'') + ' FROM '+#TableName
PRINT #Sql
EXEC (#Sql)
Try this:
DECLARE #TableName NVARCHAR(100) = 'YOUR TABLENAME HERE',
#Query NVARCHAR(MAX) = 'SELECT '
SELECT #Query = CONCAT(#Query, ' ', COLUMN_NAME, ' AS ', QUOTENAME(ROW_NUMBER() OVER(ORDER BY ORDINAL_POSITION)), ',
')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
SET #Query = SUBSTRING(#Query, 0, LEN(#Query) - 3) + '
FROM ' + QUOTENAME(#TableName)
You use INFORMATION_SCHEMA.COLUMNS to get all our table's columns,
ROW_NUMBER() window function to generate sequential number for column aliases and sp_ExecuteSQL to execute dynamic generated queries.

How to delete column from all tables in SQL Server

I want to delete the ABCDEF column from all tables of my database. I am trying this code:
declare #SQL nvarchar(max)
SELECT
#SQL = STUFF((SELECT ' DROP column ' + quotename(TABLE_SCHEMA) + '.' + quotename(table_NAME ) +'.ABCDEF;'
FROM
information_schema.columns
FOR XML PATH('')),1,2,'')
PRINT #SQL
EXECUTE (#SQL)
But I am getting an error
incorrect syntax near column
How to do this?
You can use an undocumented feature of SQL Server sys.sp_msforeachtable. The below script will basically iterate for all the tables in database and alter them if required.
select '[dbo].['+tab.name+']' name into #table from
sys.tables tab join sys.columns col on tab.object_id = col.object_id and col.name = 'ABCDEF'
exec sys.sp_msforeachtable 'if exists (select 1 from #table where name = ''?'')
alter table ? drop column [ABCDEF]'
That's not the right way to drop a column from a table. It should be
ALTER TABLE table_name DROP COLUMN column_name
Build your dynamic query something like this:
DECLARE #sql NVARCHAR(max)=''
SELECT #SQL += 'Alter table ' + Quotename(table_catalog)
+ '.' + Quotename(table_schema) + '.'
+ Quotename(TABLE_NAME) + ' DROP column '
+ Quotename(column_name) + ';'
FROM information_schema.columns where COLUMN_NAME = 'abcd' -- Here alone mention
--the Column to be removed
EXEC Sp_executesql #sql
While dropping the columns from multiple tables, I faced following default constraints error.
The object 'DF_TableName_ColumnName' is dependent on column 'ColumnName'.
To resolve this, I have to drop all those constraints first, by using following query
DECLARE #sql NVARCHAR(max)=''
SELECT #SQL += 'Alter table ' + Quotename(tbl.name) + ' DROP constraint ' + Quotename(cons.name) + ';'
FROM SYS.DEFAULT_CONSTRAINTS cons
JOIN SYS.COLUMNS col ON col.default_object_id = cons.object_id
JOIN SYS.TABLES tbl ON tbl.object_id = col.object_id
WHERE col.[name] IN ('Column1','Column2')
--PRINT #sql
EXEC Sp_executesql #sql
After that, I dropped all those columns by using the answer above.
DECLARE #sql NVARCHAR(max)=''
SELECT #SQL += 'Alter table ' + Quotename(table_catalog)+ '.' + Quotename(table_schema) + '.'+ Quotename(TABLE_NAME)
+ ' DROP column ' + Quotename(column_name) + ';'
FROM information_schema.columns where COLUMN_NAME IN ('Column1','Column2')
--PRINT #sql
EXEC Sp_executesql #sql
I posted here in case someone find the same issue.
Happy Coding!

SQL Server - find all tables in database with unique ID value

I want to find out all the tables in the database (in SQLServer) that has the column IDName with particular value 'SAM', like so IDName='SAM'. So my initial apporach was create a table with all the tables that have the column "IDName" (since not all the tables in the database has this column. Then i was thinking of going through each table to see which tables match the IDName='SAM' - This is where i'm stuck. I'm pretty sure there is a lot faster way of doing this too but im not too familiar with database query coding. Anything will help Thanks!
select * into tmp from
(
SELECT SO.NAME AS TableName, SC.NAME AS ColumnName
FROM dbo.sysobjects SO INNER JOIN dbo.syscolumns SC ON SO.id = SC.id
WHERE sc.name = 'IDName' and SO.type = 'U'
) tablelist
So if I go Select * from tmp, I get the list of tables that have the column "IDName". Now I have to go through each one of that list and see if they have "IDName = 'Sam'" if they do add it to the output table. In the end I want to see all the names of the tables from the database that has the IDName 'Sam'.
DECLARE #sql AS varchar(max) = '';
DECLARE #ColumnName AS varchar(100) = 'IDName'
DECLARE #ResultQuery AS varchar(max) = 'SELECT ''#TableName'' AS TableName ' +
' ,#ColumnName ' +
'FROM #TableName ' +
'WHERE #ColumnName = ''SAM''';
SET #ResultQuery = REPLACE(#ResultQuery, '#ColumnName', QUOTENAME(#ColumnName));
WITH AllTables AS (
SELECT SCHEMA_NAME(Tables.schema_id) AS SchemaName
,Tables.name AS TableName
,Columns.name AS ColumnName
FROM sys.tables AS Tables
INNER JOIN sys.columns AS Columns
ON Tables.object_id = Columns.object_id
WHERE Columns.name = #ColumnName
)
SELECT #sql = #sql + ' UNION ALL ' +
REPLACE(#ResultQuery, '#TableName', QUOTENAME(TableName)) + CHAR(13)
FROM AllTables
SET #sql = STUFF(#sql, 1, LEN(' UNION ALL'), '');
--PRINT #sql;
SET #sql =
'WITH AllTables AS ( ' +
#sql +
') ' +
'SELECT DISTINCT TableName ' +
'FROM AllTables ';
EXEC (#sql)

Does anybody know of a proc to turn a row into an INSERT statement?

Does anybody know of a proc or script which will generate any row into an insert statement into the same table?
Basically, I'd like to call something like
exec RowToInsertStatement 'dbo.user', 45;
And the following code would be output
insert into dbo.MyTable( FirstName, LastName, Position)
values( 'John', 'MacIntyre', 'Software Consultant');
I realize I could
insert into dbo.MyTable
select * from dbo.MyTable where id=45;
But this obviously won't work, because the ID column will complain (I hope it complains) and there's no way to just override that one column without listing all columns, and in some tables there could be hundreds.
So, does anybody know of a proc that will write this simple insert for me?
EDIT 3:04: The purpose of this is so I can make a copy of the row, so after the INSERT is generated, I can modify it into something like
insert into dbo.MyTable( FirstName, LastName, Position)
values( 'Dave', 'Smith', 'Software Consultant');
.. no obviously this contrived example is so simple it doesn't make sense, but if you have a table with 60 columns, and all you need is to change 3 or 4 values, then it starts to be a hassle.
Does that make sense?
Update
I believe the following dynamic query is what you want:
declare #tableName varchar(100), #id int, #columns varchar(max), #pk varchar(20)
set #tableName = 'MyTable'
set #pk = 'id'
set #id = 45
set #columns = stuff((select ',['+c.name+']' [text()] from sys.tables t
join sys.columns c on t.object_id = c.object_id
where t.name = #tableName and c.name <> #pk for xml path('')),1,1,'')
print 'insert into [' + #tableName + '] (' + #columns + ')
select ' + #columns + '
from [' + #tableName + ']
where ' + #pk + ' = ' + cast(#id as varchar)
Update 2
The actual thing that you wanted:
declare #tableName varchar(100), #id int, #columns nvarchar(max), #pk nvarchar(20), #columnValues nvarchar(max)
set #tableName = 'MyTable'
set #pk = 'id'
set #id = 45
set #columns = stuff((select ',['+c.name+']' [text()] from sys.tables t
join sys.columns c on t.object_id = c.object_id
where t.name = #tableName and c.name <> #pk for xml path('')),1,1,'')
set #columnValues = 'set #actualColumnValues = (select' +
stuff((select ','','''''' + cast(['+c.name+'] as varchar(max)) + '''''''' [text()]' [text()]
from sys.tables t
join sys.columns c on t.object_id = c.object_id
where t.name = #tableName and c.name <> #pk for xml path('')),1,1,'')
+ 'from [' + #tableName + ']
where ' + #pk + ' = ' + cast(#id as varchar)
+ 'for xml path(''''))'
--select #columnValues
declare #actualColumnValues nvarchar(max), #columnValuesParams nvarchar(500)
SET #columnValuesParams = N'#actualColumnValues nvarchar(max) OUTPUT';
EXECUTE sp_executesql #columnValues, #columnValuesParams, #actualColumnValues OUTPUT;
--SELECT stuff(#actualColumnValues, 1,1, '')
declare #statement nvarchar(max)
set #statement =
'insert into [' + #tableName + '] (' + #columns + ')
select ' + stuff(#actualColumnValues,1,1,'')
print #statement
What it does is this:
It generates the insert statement and then it queries the actual data from the table and generates the select statement with that data. May not work correctly for some really complex datatypes but for varchars, datetimes and ints should work like a charm.
This stored proc works great for me:
http://vyaskn.tripod.com/code.htm#inserts
Did you know that in Enterprise Manager and SQL Server Management Studio that you can, from the object browser, drag the list of columns into the text window and it will drop the names of all the columns into the text, separated by commas?

Resources