Rename column with quotation mark on start of its name - sql

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';

Related

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 execute store procedure for another DB?

I have a stored procedure that should be able to be executed on any table of any database on my MS Sql Server. Most of the combination of EXEC and USE statements didn't result in anything. Here is the stored procedure:
CREATE PROCEDURE [dbo].[usp_TrimAndLowerCaseVarcharFields]
(
#Database VARCHAR(200),
#TableSchema VARCHAR(200),
#TableName VARCHAR(200)
)
AS
BEGIN
DECLARE #sSql VARCHAR(MAX)
SET #Database = '[' + #Database + ']'
SET #sSql = ''
-- Create first part of a statement to update all columns that have type varchar
SELECT #sSql = #sSql + COLUMN_NAME + ' = LOWER(RTRIM(' + COLUMN_NAME + ')), '
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'varchar'
AND TABLE_CATALOG = #Database
AND TABLE_SCHEMA = #TableSchema
AND TABLE_NAME = #TableName
SET #sSql = 'UPDATE ' + #Database + '.' + #TableSchema + '.' + #TableName + ' SET ' + #sSql
-- Delete last two symbols (', ')
SET #sSql = LEFT(#sSql, LEN(#sSql) - 1)
EXEC(#sSql)
END
Please, advice what I have to do to execute it on [OtherDB].[TargetTable].
You can fully qualify both tables and stored procedures. In other words you can do this:
UPDATE [OtherDB].[Schema].[targetTable] SET ...
It appears you are doing this in your proc already.
You can also EXEC a stored procedure using the Fully Qualified name - e.g.
EXEC [OtherDB].[dbo].[usp_TrimAndLowerCaseVarcharFields]
Honestly, your proc looks fine, are you receiving any error messages? If so please post them. Also, make sure your user has access to the other DB.
The table name in the query you used is wrong, it is looking up into same database, but you do need to look up from different database. So the query will be as below:
SELECT #sSql = #sSql + COLUMN_NAME + ' = LOWER(RTRIM(' + COLUMN_NAME + ')), '
FROM [TargetDB].INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'varchar'
AND TABLE_CATALOG = #Database
AND TABLE_SCHEMA = #TableSchema
AND TABLE_NAME = #TableName
-- [TargetDB] = #Database
The TargetDB will be same as your passing database (#Database)
If you want to use [TargetDB] dynamically then you need to generate sql(#sSql) and the execute the sql string.
In this case I sugest to use the 2 sp's in SQL Server:
sp_MSforeachtable
sp_MSforeachdb
for more information, please read the article in here.
hope this help.
exec #RETURN_VALUE=sp_MSforeachtable #command1, #replacechar, #command2,
#command3, #whereand, #precommand, #postcommand
exec #RETURN_VALUE = sp_MSforeachdb #command1, #replacechar,
#command2, #command3, #precommand, #postcommand
Complete script:
declare #DatabaseName varchar(max), #DatabaseCharParam nchar(1)
declare #TableSchema varchar(max)
declare #TableName varchar(max), #TableCharParam nchar(1)
set #DatabaseName='DATABASENAME'; set #DatabaseCharParam='?'
set #TableSchema='dbo'
set #TableName='TABLENAME'; set #TableCharParam='$'
-- Exemple Script to execute in each table in each database
-- Create first part of a statement to update all columns that have type varchar
DECLARE #sSql VARCHAR(MAX)
set #sSql=''
SELECT #sSql = isnull(#sSql,'') + COLUMN_NAME + ' = LOWER(RTRIM(' + COLUMN_NAME + ')),'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'varchar'
AND TABLE_CATALOG = #DatabaseName
AND TABLE_SCHEMA = #TableSchema
AND TABLE_NAME = #TableName
declare #EachTablecmd1 varchar(2000)
--Prepare #EachTablecmd1 the script to execution in each table using sp_MSforeachtable (ATENTION: #Command1 are limited to varchar(2000) )
--in sp_MSforeachtable #TableCharParam will be subtituted with owner i.e:[dbo].[TABLENAME]
set #sSql='update '+#TableCharParam+' set '+ left(#sSql,LEN(#sSql)-1)
set #EachTablecmd1='if '''''+ #TableCharParam +'''''=''''['+#TableSchema+'].['+#TableName+']'''' '+#sSql
--i.e.: if 'table1'='table1' update table1 set column1=LOWER(RTRIM(column1)),....
-- the #sSql for each table in a database
set #sSql ='exec sp_MSforeachtable #command1='''+#EachTablecmd1+''' ,#replacechar='''+#TableCharParam+''''
declare #EachBDcmd1 varchar(2000)
--Prepare the execution to each database using sp_MSforeachdb (ATENTION: #Command1 are limited to varchar(2000) )
set #EachBDcmd1='if '''+#DatabaseCharParam+'''='''+#DatabaseName+''' '+ #sSql
--print #EachBDcmd1
exec sp_MSforeachdb #command1=#EachBDcmd1,#replacechar=#DatabaseCharParam

Referencing SQL Server columns dynamically in SP

SQL 2008
Hello,
I have a rather different task I have to do in SQL. It's a bit more involved than this, but I'm going to try to make it simple.
I need to somehow SELECT a column dynamically. Like this:
declare #ColName varchar(50)
select #ColName = 'Column1' --This is an actual column name in a real table called 'MyTable'
select #ColName from MyTable where Column2 = 123
Is there a way to do something like this? Any help or direction would be greatly appreciated!
Thanks,
Jason
you need dynamic SQL, but first read The Curse and Blessings of Dynamic SQL to make sure you don't open yourself up for SQL Injection
DECLARE #colNameIn AS varchar(50) = 'Column1'
DECLARE #template AS varchar(MAX) = 'select {#ColName} from MyTable where Column2 = 123' -- This template can be expanded
-- Protect yourself from injection or invalid columns:
DECLARE #ColName AS varchar(50)
SELECT #ColName = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'MyTable'
AND COLUMN_NAME = #ColNameIn
IF #ColName IS NOT NULL
BEGIN
DECLARE #sql AS varchar(MAX)
SET #sql = REPLACE(#template, '{#ColName}', QUOTENAME(#ColName))
EXEC (#sql)
END
Read the link in #SQLMenace answer!
declare #ColName varchar(50)
select #ColName = 'Column1'
declare #sql varchar(MAX)
select #sql = 'select ' + #ColName + ' MyTable where Column2 = 123'
exec (#sql)
You can do this as using a CASE statement if you have predefined all of the acceptable column names in the procedure.
DECLARE #ColName varchar(50)
SET #ColName = 'Column1'
SELECT CASE #ColName
WHEN 'Column1' THEN Column1
WHEN 'Column2' THEN Column2
END
FROM MyTable
WHERE Column2 = 123

How do I Change SQL Server column names in T-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

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.