I would like to rename all column names of a table given a string with new names separated by comma. Here be the string:
declare #str varchar(max)='A,B,C'
The number of columns in a table may vary, and appropriately the number of names in a string. So in a 5-column table the string would be 'A,B,C,D,E'.
I have a table with column names as:
col1 | col2 | col3
and in expected results I would like to have:
A | B | C
Update
I have tried to follow that path:
SELECT
ORDINAL_POSITION
,COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'my_temp'
order by ORDINAL_POSITION asc
but I do not know how to split #sql string so that it can be applied to results in the following way:
ORDINAL_POSITION COLUMN_NAME sql_string
1 Col1 A
2 Col2 B
3 Col3 C
Then I could easily create a string like:
dynamic_sql='EXEC sp_rename my_table.' + COLUMN_NAME +',' + sql_string +', ''COLUMN'''
Using the splitter from Jeff Moden I have referenced in the comments here and the answer on your question you can do this easily. http://www.sqlservercentral.com/articles/Tally+Table/72993/
Here is a full working example. It would be really helpful if you could post sample tables in your questions so we don't have to do that to work on the questions.
if object_id('SomeTable') is not null
drop table SomeTable
create table SomeTable
(
Col1 int
, Col2 int
, Col3 int
)
--to demonstrate the column names before we change them
select * from SomeTable
declare #NewNames varchar(100) = 'A,B,C'
, #SQL nvarchar(max) = ''
select #SQL = #SQL + 'EXEC sp_rename ''SomeTable.' + c.name + ''', ''' + s.Item +''', ''COLUMN'';'
from sys.columns c
join dbo.DelimitedSplit8K(#NewNames, ',') s on s.ItemNumber = c.column_id
where object_id = object_id('SomeTable')
select #SQL
--exec sp_executesql #SQL
--demonstrates the column names have been changed.
select * from SomeTable
I have said this previously and I can't in good conscience not mention it again. The fact that you need to do this is a huge red flag that there is something very very wrong with the way you managing your data. Changing column names should not happen very often at all and only when absolutely required. Doing this routinely is a sign that there are really big issues with the process or the design.
This would give you the names of all the columns of an existing table in the correct order
select c.name
from sys.columns c
inner join sys.objects o on c.object_id = o.object_id
where o.name = 'name_of_table'
order by c.column_id
Related
I'm working with a SQL Server database which is very light on constraints and want to apply some not null constraints. Is there any way to scan all nullable columns in the database and select which ones do not contain any nulls or even better count the number of null values?
Perhaps with a little dynamic SQL
Example
Declare #SQL varchar(max) = '>>>'
Select #SQL = #SQL
+ 'Union All Select TableName='''+quotename(Table_Schema)+'.'+quotename(Table_Name)+''''
+',ColumnName='''+quotename(Column_Name)+''''
+',NullValues=count(*)'
+' From '+quotename(Table_Schema)+'.'+quotename(Table_Name)
+' Where '+quotename(Column_Name)+' is null '
From INFORMATION_SCHEMA.COLUMNS
Where Is_Nullable='YES'
Select #SQL='Select * from (' + replace(#SQL,'>>>Union All ','') + ') A Where NullValues>0'
Exec(#SQL)
Returns (for example)
TableName ColumnName NullValues
[dbo].[OD-Map] [Map-Val2] 185
[dbo].[OD-Map] [Map-Val3] 225
[dbo].[OD-Map] [Map-Val4] 225
For all table/columns with counts >= 0
...
Select #SQL=replace(#SQL,'>>>Union All ','')
Exec(#SQL)
Check this query. This was originally written by Linda Lawton
Original Article: https://www.daimto.com/sql-server-finding-columns-with-null-values
Finding columns with null values in your Database - Find Nulls Script
set nocount on
declare #columnName nvarchar(500)
declare #tableName nvarchar(500)
declare #select nvarchar(500)
declare #sql nvarchar(500)
-- check if the Temp table already exists
if OBJECT_ID('tempdb..#LocalTempTable') is null
Begin
CREATE TABLE #LocalTempTable(
TableName varchar(150),
ColumnName varchar(150))
end
else
begin
truncate table #LocalTempTable;
end
-- Build a select for each of the columns in the database. That checks for nulls
DECLARE check_cursor CURSOR FOR
select column_name, table_name, concat(' Select ''',column_name,''',''',table_name,''' from ',table_name,' where [',COLUMN_NAME,'] is null')
from INFORMATION_SCHEMA.COLUMNS
OPEN check_cursor
FETCH NEXT FROM check_cursor
INTO #columnName, #tableName,#select
WHILE ##FETCH_STATUS = 0
BEGIN
-- Insert it if there if it exists.
set #sql = 'insert into #LocalTempTable (ColumnName, TableName)' + #select
print #sql
-- Run the statment
exec( #sql)
FETCH NEXT FROM check_cursor
INTO #columnName, #tableName,#select
end
CLOSE check_cursor;
DEALLOCATE check_cursor;
SELECT TableName, ColumnName, COUNT(TableName) 'Count'
FROM #LocalTempTable
GROUP BY TableName, ColumnName
ORDER BY TableName
The query result would be something like this.
This will tell you which columns in your database are currently NULLABLE.
USE <Your_DB_Name>
GO
SELECT o.name AS Table_Name
, c.name AS Column_Name
FROM sys.objects o
INNER JOIN sys.columns c ON o.object_id = c.object_id
AND c.is_nullable = 1 /* 1 = NULL, 0 = NOT NULL */
WHERE o.type_desc = 'USER_TABLE'
AND o.type NOT IN ('PK','F','D') /* NOT Primary, Foreign of Default Key */
Yes, it is fairly straight forward. Note: if the table contains a lot of records, I suggest using SELECT TOP 1000 *, instead of SELECT *.
-- Identify records where a specific column is NOT NULL
SELECT *
FROM TableName
WHERE ColumNName IS NOT NULL
-- Identify the count of records where a specific column contains NULL
SELECT COUNT(1)
FROM TableName
WHERE ColumNName IS NULL
-- Identify all NULLable columns in a database
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE IS_NULLABLE = 'YES'
For more information on the INFORMATION_SCHEMA views, see this: https://learn.microsoft.com/en-us/sql/relational-databases/system-information-schema-views/system-information-schema-views-transact-sql
If you want to scan all tables and columns in a given database for NULLs, then it is a two step process.
1.) Get the list of tables and columns that are NULLABLE.
-- Identify all NULLable columns in a database
SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE IS_NULLABLE = 'YES'
2.) Use Excel to create a SELECT statement to get the NULL counts for each table/column. To do this, copy and paste the query results from step 1 into EXCEL. Assuming you have copied the header row, then your data starts on row 2. In cell E2, enter the following formula.
="SELECT COUNT(1) FROM "&A2&"."&B2&"."&C2&" WHERE "&D2&" IS NULL"
Copy and paste that down the entire sheet. This will generate the SQL SELECT statement that you require. Copy the results in column E and paste into SQL Server and run it. This may take a while depending on the number of tables/columns to scan.
I have a table with 30+ fields and I want to quickly narrow my selection down to all fields where column name start with 'Flag'.
select * Like Flag% from Table1
You will want to build a dynamic query as explained here: https://stackoverflow.com/a/4797728/9553919
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Foods'
AND table_schema = 'YourDB'
AND column_name LIKE 'Vegetable%'
This SQL Statement should be useful. You may be able to simplify it but it does work.
Edit2: I just now saw your pervasive-sql tag. Unfortunately I've never worked with that and don't know if the syntax is compatible with MS SQL Server. I'll let my answer here in case it helps others, but wanted to share that I tested this using SQL Server.
Edit: SCHEMA_NAME function isn't necessary. You can replace SCHEMA_NAME(schema_id) with the name of your schema in single quotes if you want, but either will work.
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 = 'Table1' AND
c.name Like 'Flag%'
ORDER BY
c.name
or
SELECT t.name AS table_name,
'MySchema' 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 = 'Table1' AND
c.name Like 'Flag%'
ORDER BY
c.name
To do this, you will need to query the system tables for the columns associated to the table and filter them to what you want. From there, place them into a variable table and create a CSV of columns. From there, you can dynamically construct your query as needed. The below example should help you get started.
DECLARE #tableName VARCHAR(100) = 'dbo.SomeTable'
DECLARE #columnNames TABLE
(
Id INT IDENTITY PRIMARY KEY,
ColumnName VARCHAR(100)
)
--Grabs all of the columns into a variable table
INSERT INTO #columnNames (ColumnName)
SELECT
[name]
FROM sys.columns
WHERE
[object_id] = OBJECT_ID(#tableName)
AND
[name] LIKE '%Flag'
DECLARE #columns VARCHAR(1000)
--Creates a CSV of columns
SET #columns =
STUFF(
(
SELECT
',' + ColumnName
FROM #columnNames
FOR XML PATH(''))
,1,1,'')
DECLARE #selectStatement NVARCHAR(4000) = CONCAT('SELECT ', #columns, ' FROM ', #tableName)
PRINT #selectStatement
EXEC #selectStatement
Is there a way to only select the columns whose names are not present on another table? For example
Table A Column B
ID | Name | Address Address
-----------------------
1 | Daniel | dummy
In this example my select statement should be like this:
select ID, Name from Column A
I've seen people talking about dynamic SQL but I can't find a decent example to solve my issue, any help is much appreciated.
Here is a version of the way you would do this using dynamic SQL:
declare #cols varchar(max);
set #cols = NULL;
select #cols = coalesce(#cols + ', ' + column_name, column_name)
from information_schema.columns ca
where ca.table_name = 'A' and
ca.column_name not in (select cb.column_name
from information_schema.columns cb
where cb.table_name = 'B'
);
declare #sql varchar(max);
set #sql = 'select [cols] from A';
set #sql = replace(#sql, '[cols]', #cols);
exec sp_executesql #sql;
This is a bit simplified to show how the information_schema tables can be sued. It will work in many circumstances, but is not maximally general:
It doesn't take schema name into account.
It assumes all names are simple ASCII.
It does not escape the column names (assuming the names do not need to be escaped).
Select the other table in the WHERE clause.
SELECT ID, NAME
FROM ColumnA
WHERE NAME NOT IN (SELECT NAME FROM COLUMNB)
If I have these tables below:
PLAYERS
ID Name
== ===========
1 Mick
2 Matt
COACHES
ID Name
== ===========
1 Bill
2 Don
And I have a script below to find all tables that has a column called "Name":
SELECT t.name AS table_name FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE c.name LIKE 'Name'
Which returns the following:
table_name
===========
PLAYERS
COACHES
How can I select all the rows from both tables returned by the query above?
You will have to use dynamic sql, try something like this:
declare #t table( tablename varchar(50))
declare #sql varchar(max)
set #sql = ''
insert into #t
SELECT t.name AS table_name FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE c.name LIKE 'Name'
select #sql = #sql + 'Select * From ' + tablename + ' union ' from #t
--remove the trailing 'union'
Select #sql = substring(#sql, 1, len(#sql) - 6)
exec (#sql)
The above script creates and executes the following sql
select * from coaches
union
select * from players
Since we are using union here, it is important that all your tables that have name as column is of same structure.
See more about dynamic sql from http://msdn.microsoft.com/en-us/library/ms188001.aspx
SELECT p.Id,p.Name,c.Id,c.Name
FROM Players p JOIN Coaches c
ON p.Id=c.Id
May be this can help you.
Is there a way to apply an alter statement to ALL the columns in a table without having to specify the column names? This would only be used in a temp table I need to clean up the duplicate data in a report.
Here's a sample of what I'm wondering if its possible:
select T1.Column1, T1.Column2, T1.Column3, T2.Column1, T2.Column2
into #templateTable
from Table1 T1
join Table2 T2 on T1.Column1 = T2.Column2
alter table #templateTable
alter column * null
All I really need is my #tempTable to allow null values in the columns that it originally gets data from which don't previously allow null values.
Lastly, there are 2 reasons I don't want to go through and edit each column:
There are many columns (~50) being pulled from at least 10 tables.
I don't know which ones allow null and researching which ones do would take me the next two days.
Any help will be appreciated.
Ugly way, but it works in a SqlServer Management Studio, at least (can probably be used as "strings")
select 'alter table ' + table_name + ' alter column '+ column_name +' ' + data_type +
(case
when character_maximum_length is not null and CHARACTER_MAXIMUM_LENGTH <> -1 then ' (' + CAST(CHARACTER_MAXIMUM_LENGTH as varchar) +')'
when CHARACTER_MAXIMUM_LENGTH = -1 then '(MAX)'
else '' end) + ' null;' from tempdb.information_schema.COLUMNS
where TABLE_NAME = '<YOUR TABLE NAME>'
and IS_NULLABLE='NO';
copy result, paste and execute...
I'm not entirely gathering what you are trying to accomplish with your temp tables, but as far as your first question you can query the sysobjects tables for your table's name and then alter each column in that table by looping through the syscolumns table
So lets say I want to loop through each column in the table master:
declare #i int
declare #colcount int
declare #column varchar(max)
declare #sql nvarchar(max)
set #i = 1
set #colcount = (select MAX(colID) from syscolumns where ID = (select id from sysobjects
where name = 'master'))
WHILE #i < #colcount
BEGIN
set #column = (select name from syscolumns where ID = (select id from sysobjects where name = 'master') and colid = #i)
set #sql = 'select top 1000 [' + #column + '] from master'
EXECUTE(#sql)
set #i = #i + 1
End
you can change #sql to whatever you need it to be and that should get it
Check out this question Create a nullable column using SQL Server SELECT INTO?
I'm guessing this is a one time run...
select 'alter table xxx alter column ' + columnname + ...
from information_schema.columns
where ...
Copy and paste the result in a separate window and run.