How do I Change SQL Server column names in T-SQL? - sql

I have a table with 600+ columns imported from a CSV file with special chars % _ - in the column names.
Is there a way to change the column names to remove these special chars?
The code can be in T-SQL.

sp_rename?
EXEC sp_rename 'table.[Oh%Dear]', 'OhDear', 'COLUMN';
Worked example (was not sure about [ ] in sp_rename)
CREATE TABLE foo ([Oh%Dear] int)
EXEC sp_rename 'foo.[Oh%Dear]', 'OhDear', 'COLUMN'
EXEC sys.sp_help 'foo'

You can query INFORMATION_SCHEMA.COLUMNS and generate sp_rename scripts to rename the columns.
SELECT 'EXEC sp_rename ''' + TABLE_NAME + '.' + QUOTENAME(COLUMN_NAME) + ''', ''' + REPLACE(COLUMN_NAME, '%', '') + ''', ''COLUMN''; '
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%[%]%'
Here's a permalink to an actual runnable example

Can you use this?
sp_RENAME 'Table.ColumnName%', 'NewColumnName' , 'COLUMN'

here is an example that will loop over a table and change underscores and percent signs
create table Test ([col%1] varchar(50),[col_2] varchar(40))
go
select identity(int,1,1) as id ,column_name,table_name into #loop
from information_schema.columns
where table_name = 'Test'
and column_name like '%[%]%'
or column_name like '%[_]%'
declare #maxID int, #loopid int
select #loopid =1
select #maxID = max(id) from #loop
declare #columnName varchar(100), #tableName varchar(100)
declare #TableColumnNAme varchar(100)
while #loopid <= #maxID
begin
select #tableName = table_name , #columnName = column_name
from #loop where id = #loopid
select #TableColumnNAme = #tableName + '.' + #columnName
select #columnName = replace(replace(#columnName,'%',''),'_','')
EXEC sp_rename #TableColumnNAme, #columnName, 'COLUMN';
set #loopid = #loopid + 1
end
drop table #loop
select * from Test

Related

Rename column with quotation mark on start of its name

I have table with unknown column's names from import and I'm trying to rename its. For example:
DECLARE #Col1 nvarchar(128);
SELECT #Col1 = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = mytable and ordinal_position = 1;
DECLARE #ColName nvarchar(255);
SET #ColName = '[mytable.' + #Col1 + ']';
sp_RENAME #ColName, '[MyColumn]', 'COLUMN';
It doesn't work when #Col1 starts from quotation mark like "RudeColumName and returns: Incorrect syntax near 'sp_RENAME'. Also rename by using ALTER TABLE doesn't work and returns syntax error.
How could I rename this column?
QUOTENAME() is the right function to use. This is how you would use it:
DECLARE #Col1 nvarchar(128);
SELECT #Col1 = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = mytable and ordinal_position = 1;
DECLARE #ColName nvarchar(255);
SET #ColName = QUOTENAME('mytable') + '.' + QUOTENAME(#Col1);
sp_RENAME #ColName, '[MyColumn]', 'COLUMN';
Note: it is used separately for the table name and the column name.
Of course, you might also need QUOTENAME() around the new name as well. On the other hand, simply don't use new column names that require quoting.
Try this
DECLARE #Col1 nvarchar(128);
SELECT #Col1 = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = mytable and ordinal_position = 1;
DECLARE #ColName nvarchar(255);
SET #ColName = '[mytable.''' + #Col1 + ']';
sp_RENAME #ColName, '[MyColumn]', 'COLUMN';
How about to use QUOTENAME instead of brackets []?
DECLARE #Col1 nvarchar(128);
SELECT #Col1 = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = mytable and ordinal_position = 1;
DECLARE #ColName nvarchar(255);
SET #ColName = QUOTENAME('mytable.' + #Col1);
sp_RENAME #ColName, '[MyColumn]', 'COLUMN';

SQL query to dynamically COUNT(FIELD) for all fields of table X

This should be such an easy thing, but it has me totally stumped.
You can easily return the count of each field of a table manually, with oneliners such as:
select count(FIELD1) from TABLE1 --42,706
select count(FIELD5) from TABLE1 --42,686
select count(FIELD9) from TABLE1 --2,918
This is slow and painful if you want to review several dozen tables the same way, and requires you to know the names of the fields in advance.
How handy would it be to have a script you can connect to any database, simply feed it a table name, and it will automatically return the counts for each field of that table?
Seems you can get half the work done with:
select COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'TABLE1'
Something is flawed even with my barebones approach (explicitly hitting one field instead of them all):
declare #TABLENAME varchar(30), #FIELDNAME varchar(30)
set #TABLENAME = 'TABLE1'
set #FIELDNAME = (select top 1 COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #TABLENAME
and COLUMN_NAME = 'FIELD9')
select #FIELDNAME, count(#FIELDNAME) from TABLE1
The result is 42,706. Recall from my example above that FIELD9 only contains 2,918 values.
Even if that wasn't a problem, the more dynamic query would replace the last line with:
select #FIELDNAME, count(#FIELDNAME) from #TABLENAME
But SQL Server returns:
Must declare the table variable "#TABLENAME".
So I can avoid that by restructuring the query with a temp table:
declare #FIELDNAME varchar(30)
set #FIELDNAME = (select top 1 COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'TABLE1'
and COLUMN_NAME = 'FIELD9')
if OBJECT_ID('TEMPDB..#TEMP1') is not null
drop table #TEMP1
select *
into #TEMP1
from TABLE1 --still not exactly dynamic!
select #FIELDNAME, count(#FIELDNAME) from #TEMP1
But that still brings us back to the original problem of returning 42,706 instead of 2,918.
I am running SQL Server 2008 R2, if it makes any difference.
Your query:
SELECT #FIELDNAME, COUNT(#FIELDNAME) FROM TABLE1
does not count FIELD9, #FIELDNAME is treated as a constant. It's like doing a COUNT(*).
You should use dynamic sql:
DECLARE #sql VARCHAR(MAX)
SET #sql = 'SELECT ''' + #fieldName + ''', COUNT([' + #fieldName + ']) FROM [' + #tableName + ']'
EXEC(#sql)
To get all columns and return it in a single result set without using a Temporary Table and CURSOR:
DECLARE #sql NVARCHAR(MAX) = ''
SELECT #sql = #sql +
'SELECT ''' + COLUMN_NAME + ''' AS ColName, COUNT([' + COLUMN_NAME + ']) FROM [' + #tableName + ']' + CHAR(10) +
'UNION ALL' + CHAR(10)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tableName
SELECT #sql = LEFT(#sql, LEN(#sql) - 10)
EXEC(#sql)
Just set the #TargetTableName will do the job
DECLARE #TargetTableName sysname = '*'
SET NOCOUNT ON
DECLARE #TableName sysname, #ColumnName sysname, #Sql nvarchar(max)
DECLARE #TableAndColumn table
(
TableName sysname,
ColumnName sysname
)
DECLARE #Result table
(
TableName sysname,
ColumnName sysname,
NonNullRecords int
)
INSERT #TableAndColumn
SELECT o.name, c.name FROM sys.objects o INNER JOIN sys.columns c ON o.object_id = c.object_id
WHERE (o.name = #TargetTableName OR #TargetTableName = '*') AND o.type = 'U' AND c.system_type_id NOT IN (34, 35, 99) -- 34:image 35:text 99:ntext
ORDER BY c.column_id
DECLARE column_cursor CURSOR FOR SELECT TableName, ColumnName FROM #TableAndColumn
OPEN column_cursor
FETCH NEXT FROM column_cursor
INTO #TableName, #ColumnName
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Sql = 'SELECT ''' + #TableName + ''' AS TableName, ''' + #ColumnName + ''' AS ColumnName, COUNT([' + #ColumnName + ']) AS NonNullRecords FROM [' + #TableName + ']'
print #Sql
INSERT #Result
EXEC (#Sql)
FETCH NEXT FROM column_cursor
INTO #TableName, #ColumnName
END
CLOSE column_cursor;
DEALLOCATE column_cursor;
SET NOCOUNT OFF
SELECT * FROM #Result

How to use EXEC or sp_executeSQL without looping in this case?

Environment: SQL Server 2005/2008,
pubs database
I have inserted into a table variable a set of data as shown below using information_schema tables.
Now I would like to update the flag column based on the result of executing the query in the column dSQL. I was able to update using loops/cursor and then used sp_executeSQL to
update the column and then update flag column later. But is there an alternate set-based way to do this without looping through all individual rows?
use pubs
go
declare #dsql Nvarchar(max)='', #tablename varchar(100), #colname varchar(100)
declare #t table (
TABLE_NAME varchar(100),
COLUMN_NAME varchar(100)
)
insert into #t
select distinct t.TABLE_NAME, c.COLUMN_NAME
from information_Schema.tables t
inner join
information_Schema.columns c
on t.TABLE_CATALOG = c.TABLE_CATALOG
where t.TABLE_SCHEMA = c.TABLE_SCHEMA
and t.TABLE_TYPE = 'BASE TABLE'
and c.DATA_TYPE = 'varchar'
select *, Dsql = 'select ' + COLUMN_NAME + ' from ' + TABLE_NAME + ' WHERE '
+ COLUMN_NAME + ' = ''Menlo Park''', '' as Flag
FROM #t
GO
I had an idea to create a function and call the function for each row to execute individual query statement but calling the function for each record might be a performance hit.
It's a loop or a function as you suggested (which is really a loop anyway).
Not possible, I made a script like it earlier.
declare #searchvalue varchar(100)
set nocount off
set #searchvalue = 'Hello world'
create table #tt (table_name varchar(64), column_name varchar(64), count int)
select * into #t from
(
select 'select ''' + a.table_name + ''' ''table_name'',''' + a.column_name + ''' ''column_name'', count(*) count from [' + a.table_name +'] where [' +a.column_name+']='''+#searchvalue +'''' + ' group by ['+ a.column_name+']' sqlstring
from INFORMATION_SCHEMA.COLUMNS a
join
INFORMATION_SCHEMA.TABLES b
on a.table_name = b.table_name
and b.table_type = 'base table'
where data_type = 'varchar'
) a
--loop cursor
Declare #sqlstring as nvarchar(500)
Declare SqlCursor CURSOR FAST_FORWARD FOR
SELECT sqlstring FROM #t
OPEN SqlCursor
FETCH NEXT FROM SqlCursor
INTO #sqlstring
WHILE ##FETCH_STATUS = 0
BEGIN
insert #tt
exec(#sqlstring)
FETCH NEXT FROM SqlCursor
INTO #sqlstring
END
CLOSE SqlCursor
DEALLOCATE SqlCursor
select * from #tt
drop table #tt
drop table #t
Use what you want
This is an old question, but I'd like to add a different answer all the same.
Try the following script (no cursor, no loop (according to execution plan)): (tested in MS SQL 2012)
-- Setting up test data/code
SELECT N'SELECT * FROM INFORMATION_SCHEMA.COLUMNS AS C' T
INTO #Code
UNION ALL
SELECT N'SELECT * FROM INFORMATION_SCHEMA.TABLES AS T'
-- Variable to hold the selected queries, seperated by CrLf. You can also add a "GO" or ";"
DECLARE #SQL NVARCHAR(MAX) = CHAR(13) + CHAR(10)
-- Concatenate the selected queries together into the variable
SELECT #SQL = #SQL + CHAR(13) + CHAR(10) + C.T
FROM #Code AS C
-- Execute
EXEC sys.sp_executesql #SQL
-- Clean up
DROP TABLE #Code

SQL Server: How to perform Rtrim on all varchar columns of a table

I have over 30 columns in my table (sql server 2008). Columns type are varchar(x). I know that in every column there is two extra spaces at the end of column value. How to use rtrim function for all columns and save this modification into this existing table?
Edit: is there a way to do it using stored procedure or cursor where I don't have to manually declare all columns?
For a generic approach, you can use a script like this to generate the statement for you, for a given table (useful if you have many columns!):
DECLARE #SQL VARCHAR(MAX)
DECLARE #TableName NVARCHAR(128)
SET #TableName = 'YourTableName'
SELECT #SQL = COALESCE(#SQL + ',[', '[') +
COLUMN_NAME + ']=RTRIM([' + COLUMN_NAME + '])'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
AND DATA_TYPE = 'varchar'
SET #SQL = 'UPDATE [' + #TableName + '] SET ' + #SQL
PRINT #SQL
That will just print the SQL statement out. You can either then copy + run the statement, or just EXECUTE(#SQL). This is untested, so just try it out on a test table first :)
UPDATE xxx
SET col1 = RTRIM(col1),
col2 = RTRIM(col2),
col3 = RTRIM(col3),
...
We can have stored procedure to trim specific table under specific schema. If we have different schema names other than default dbo schema, it is better to use this SP by passing schema name and table name. This performs both LTRIM and RTRIM. This SP would check char, nchar, varchar, nvarchar columns.
CREATE PROCEDURE [dbo].[TrimAllColumnsOfTable] #SchemaName Varchar(100),#TableName Varchar(100)
AS
BEGIN
DECLARE #SQL VARCHAR(MAX)
SELECT #SQL = COALESCE(#SQL + ',[', '[') +
COLUMN_NAME + ']=LTRIM(RTRIM([' + COLUMN_NAME + ']))'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = #SchemaName AND TABLE_NAME = #TableName AND DATA_TYPE Like '%char%'
SET #SQL = 'UPDATE [' + #SchemaName + '].[' + #TableName + '] SET ' + #SQL
EXEC (#SQL)
END
USAGE: [TrimAllColumnsOfTable] 'SchemaName','TableName'
It is perfect... But remember to put also the where clause:
COLUMNPROPERTY(OBJECT_ID(TABLE_SCHEMA+'.'+TABLE_NAME),COLUMN_NAME,'IsComputed') = 0
Ohterwise you will get an error if the table has a computed column of "%char%" type!
The accepted answer works well. I ran into an issue with a temp table being named the same name. You can add
and TABLE_SCHEMA = 'dbo'
And that will get rid of collision on table names.

SQL To search the entire MS SQL 2000 database for a value

I would like to search an entire MS SQL 2000 database for one value. This would be to aid development only. Keep that in mind when considering this question.
This will get all the table names and the column of the data type I'm looking for:
SELECT Columns.COLUMN_NAME, tables.TABLE_NAME
FROM INFORMATION_SCHEMA.Columns as Columns
JOIN INFORMATION_SCHEMA.TABLES as tables
On Columns.TABLE_NAME = tables.TABLE_NAME
WHERE Columns.DATA_TYPE = 'INT'
I was thinking something like this:
-- Vars
DECLARE #COUNTER INT
DECLARE #TOTAL INT
DECLARE #TABLE CHAR(128)
DECLARE #COLUMN CHAR(128)
DECLARE #COLUMNTYPE CHAR(128)
DECLARE #COLUMNVALUE INT
-- What we are looking for
SET #COLUMNTYPE = 'INT'
SET #COLUMNVALUE = 3
SET #COUNTER = 0
-- Find out how many possible columns exist
SELECT #TOTAL = COUNT(*)
FROM INFORMATION_SCHEMA.Columns as Columns
JOIN INFORMATION_SCHEMA.TABLES as tables
On Columns.TABLE_NAME = tables.TABLE_NAME
WHERE Columns.DATA_TYPE = #COLUMNTYPE
PRINT CAST(#TOTAL AS CHAR) + 'possible columns'
WHILE #COUNTER < #TOTAL
BEGIN
SET #COUNTER = #COUNTER +1
-- ADD MAGIC HERE
END
Any ideas?
UPDATE I recently found this tool that works quite well.
Since it is dev only (and probably doesn't have to be very elegant), how about using TSQL to generate a pile of TSQL that you then copy back into the query window and execute?
SELECT 'SELECT * FROM [' + tables.TABLE_NAME + '] WHERE ['
+ Columns.Column_Name + '] = ' + CONVERT(varchar(50),#COLUMNVALUE)
FROM INFORMATION_SCHEMA.Columns as Columns
INNER JOIN INFORMATION_SCHEMA.TABLES as tables
On Columns.TABLE_NAME = tables.TABLE_NAME
WHERE Columns.DATA_TYPE = #COLUMNTYPE
It won't be pretty, but it should work... an alternative might be to insert something like the above into a table-variable, then loop over the table-variable using EXEC (#Sql). But for dev purposes it probably isn't worth it...
I've found this script to be helpful... but as Marc noted, it wasn't really worth it. I've only used it a handful of times since I wrote it six months ago.
It only really comes in handy because there are a couple of tables in our dev environment which cause binding errors when you query them, and I always forget which ones.
BEGIN TRAN
declare #search nvarchar(100)
set #search = 'string to search for'
-- search whole database for text
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
IF nullif(object_id('tempdb..#tmpSearch'), 0) IS NOT NULL DROP TABLE #tmpSearch
CREATE TABLE #tmpSearch (
ListIndex int identity(1,1),
CustomSQL nvarchar(2000)
)
Print 'Getting tables...'
INSERT #tmpSearch (CustomSQL)
select 'IF EXISTS (select * FROM [' + TABLE_NAME + '] WHERE [' + COLUMN_NAME + '] LIKE ''%' + #search + '%'') BEGIN PRINT ''Table ' + TABLE_NAME + ', Column ' + COLUMN_NAME + ''';select * FROM [' + TABLE_NAME + '] WHERE [' + COLUMN_NAME + '] LIKE ''%' + #search + '%'' END' FROM information_schema.columns
where DATA_TYPE IN ('ntext', 'nvarchar', 'uniqueidentifier', 'char', 'varchar', 'text')
and TABLE_NAME NOT IN ('table_you_dont_want_to_look_in', 'and_another_one')
Print 'Searching...
'
declare #index int
declare #customsql nvarchar(2000)
WHILE EXISTS (SELECT * FROM #tmpSearch)
BEGIN
SELECT #index = min(ListIndex) FROM #tmpSearch
SELECT #customSQL = CustomSQL FROM #tmpSearch WHERE ListIndex = #index
IF #customSql IS NOT NULL
EXECUTE (#customSql)
SET NOCOUNT ON
DELETE #tmpSearch WHERE ListIndex = #index
SET NOCOUNT OFF
END
print 'the end.'
ROLLBACK