Update (find and replace) in all column in SQL Server - sql

I got this script for update data in table:
update [dbo].[temp_LABORATOR_copy]
set [PRA] = replace([PRA], '.', ',');
update [dbo].[temp_LABORATOR_copy]
set [PRV] = replace([PRV], '.', ',');
update [dbo].[temp_LABORATOR_copy]
set [TVK] = replace([TVK], '.', ',');
update [dbo].[temp_LABORATOR_copy]
set [eAl] = replace([eAl], '.', ',');
update [dbo].[temp_LABORATOR_copy]
set [efH] = replace([efH], '.', ',');
But there is 53 columns in the table and listing script for each column separately is inefficient. Is there a possibility to perform this script comprehensively for the whole table?
Like:
update [dbo].[temp_LABORATOR_copy]
set * = NULL
where * like '***'

To generate a script like that use dynamic sql.
DECLARE #tableName varchar(50) = '[dbo].[temp_LABORATOR_copy]'
DECLARE #sql VARCHAR(MAX)='';
-- columns
SELECT #sql = #sql
+ CASE len(#sql) WHEN 0 THEN '' ELSE ',' END
+ c.name + ' = CASE WHEN ' + c.name + ' LIKE ''***'' THEN NULL ELSE ' + c.name + ' END'
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(#tableName)
SET #sql = 'UPDATE ' + #tableName + ' SET ' +#sql ;
select #sql;
EXECUTE (#sql);

You can use dynamic SQL:
DECLARE #sql nvarchar(max)
SELECT #sql = (
SELECT 'update [dbo].[temp_LABORATOR_copy] set [' +COLUMN_NAME+'] = replace(['+COLUMN_NAME+'], ''.'', '','');'
FROM information_schema.columns
WHERE TABLE_NAME = 'temp_LABORATOR_copy'
AND COLUMN_NAME NOT IN ('Field2','Field3') -- Here put columns that must not be updated
AND DATA_TYPE IN ('nvarchar','varchar','nchar','char')
FOR XML PATH('')
)
--That will give you script like
--update [dbo].[temp_LABORATOR_copy] set [Field1] = replace([Field1], '.', ','); and etc
EXEC sp_executesql #sql

Related

Select table and column dynamically based on other table rows

I have following table and values,
Tb_name column_name1 column_name2
Citator_KTLO_CC Date_Created Date_Modified
Citator_KTLO_QA Date_Created Date_Modified
I want to select dynamically column from table, so the result is like this:
Select Date_Created,Date_Modified from Citator_KTLO_CC
and in next loop it will select for second row, like
Select Date_Created,Date_Modified from Citator_KTLO_QA
How can i do this by using dynamic sql ?
any example are appreciated.
here is an example of how to do this.
Since you dont post many info I just assume that the table containing all the tablenames is called 'tables'
Also this will only work if all tables have the same column types.
-- create a test table you dont need this
create table tables (tb_name varchar(100) primary key, field1 varchar(100), field2 varchar(100))
-- fill my test table you dont need this
insert into tables values ('table1', 'field1', 'field2')
insert into tables values ('table2', 'foo1', 'foo2')
insert into tables values ('table3', 'test1', 'test2')
-- this is the actual code you need, replace the names with your real names
declare #sql varchar(max) = ''
declare #tb_name varchar(100) = ''
declare #field1 varchar(100) = ''
declare #field2 varchar(100) = ''
declare myCursor cursor for
select tb_name, field1, field2 from tables -- dont know how your table is called
open myCursor
fetch next from myCursor into #tb_name, #field1, #field2
while ##FETCH_STATUS = 0
begin
set #sql = #sql + ' select ' + #field1 + ', ' + #field2 + ' from ' + #tb_name + ' union all '
fetch next from myCursor into #tb_name, #field1, #field2
end
close myCursor
deallocate myCursor
select #sql = left(#sql, len(#sql) - 10)
exec (#sql)
EDIT:
using a where clause is possible but things will get more complicated
declare #something date = getdate()
set #sql = #sql + ' select ' + #field1 + ', ' + #field2 + ' from ' + #tb_name + ' where ' + #field1 + ' = ' + #something + ' union all '
You can use the example above to build what you need just play with it.
EDIT:
using a where clause with a date format
declare #something date = getdate()
set #sql = #sql + ' select ' + #field1 + ', ' + #field2 + ' from ' + #tb_name + ' where ' + #field1 + ' = ''' + CONVERT(varchar(8), #something, 112) + ''' union all '
DECLARE #SQL VARCHAR(1000);
SET #SQL = '
SELECT *
FROM Citator_KTLO_CC
UNION ALL
SELECT *
FROM Citator_KTLO_QA;'
EXEC (#SQL);
How about something like this. If you've more than two cols, you can use dynamic sql to generate a list of cols to then generate more dynamic sql instead of hard coding.
DROP TABLE #Test
CREATE TABLE #Test
(Tb_name NVARCHAR(15),
column_name1 NVARCHAR(12),
column_name2 NVARCHAR(13));
INSERT INTO #Test VALUES
('Citator_KTLO_CC','Date_Created','Date_Modified'),
('Citator_KTLO_QA','Date_Created','Date_Modified');
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = (SELECT STUFF((SELECT ' UNION ALL SELECT ' + Cols + ' FROM '+TbL
FROM (SELECT QUOTENAME(Tb_name) TBL,
QUOTENAME(column_name1) + ', '+
QUOTENAME(column_name2) Cols
FROM #Test) Blah
FOR XML PATH('')),1,10,''))
PRINT #SQL
EXEC sys.sp_executesql #SQL
Try this..
For selecting one row if you are running in aloop
DECLARE #sql NVARCHAR(4000)
SELECT #sql = ' select ' + column_name_1 + ',' + column_name2 + ' from ' + Tb_name
FROM < yourtable >
EXEC (#sql)
OR
DECLARE #sql NVARCHAR(4000)
SELECT #sql = 'union all select ' + column_name_1 + ',' + column_name2 + ' from ' + Tb_name
FROM < yourtable >
SET #sql =stuff(#sql,1,10,'')
EXEC (#sql)
DECLARE #ColumnList1 VARCHAR(MAX) = '''''';
DECLARE #ColumnList2 VARCHAR(MAX) = '''''';
DECLARE #ColumnNameFromTable1 VARCHAR(50);
DECLARE #ColumnNameFromTable2 VARCHAR(50);
DECLARE MyCursor1 CURSOR
FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Citator_KTLO_CC'
ORDER BY ORDINAL_POSITION
DECLARE MyCursor2 CURSOR
FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Citator_KTLO_QA'
ORDER BY ORDINAL_POSITION
OPEN MyCursor1
OPEN MyCursor2
FETCH NEXT FROM MyCursor1 INTO #ColumnNameFromTable1;
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM MyCursor2 INTO #ColumnNameFromTable2;
SET #ColumnList1 = #ColumnList1 + ',' + #ColumnNameFromTable1
SET #ColumnList2 = #ColumnList2 + ',' + #ColumnNameFromTable2
FETCH NEXT FROM MyCursor1 INTO #ColumnNameFromTable1;
END
CLOSE MyCursor1;
DEALLOCATE MyCursor1;
CLOSE MyCursor2;
DEALLOCATE MyCursor2;
EXEC ('SELECT ' + #ColumnList1 + ' FROM Citator_KTLO_CC UNION ALL SELECT ' +
#ColumnList2 + ' FROM Citator_KTLO_QA ')

using information_schema_tables and concatenate

I want to know how can I use the information_schema_tables select query to look up #tablename, so that, that table's catalog and schema is shown, and then concatenate it together so that #tablename is displayed as table_catalog.table_schema.table name'?
At the moment I am just calling on the table name using select #tablename = Value
declare #tablename varchar(MAX)
declare #tableschema varchar(MAX)
declare #loop int = 1
select a.* into #tmp
from
(
select RID,
v.value('local-name(.)', 'VARCHAR(MAX)') 'Field',
v.value('./text()[1]', 'VARCHAR(MAX)') 'Value'
from #XMLTemp
cross apply Field.nodes ('/Record/*') x(v)
where v.value('local-name(.)', 'VARCHAR(MAX)') not in ('Update', 'Filter', 'Insert', 'Delete')
) as a
where RID = #loop
...
select Table_Catalog, Table_Schema
from Information_Schema.Tables
...
select #tablename = ''
select #tablename = Value
from #tmp
where Field='tableName'
and RID = #loop
...
print 'update ' + #tablename + '
...
select #tablename = Value from #tmp where Field = 'TableName'
...
set #loop = #loop+1
In SQL Server you can use "+" to concatenate strings.
declare #tablename varchar(MAX)
select #tablename = TABLE_CATALOG + '.' + TABLE_SCHEMA + '.' + TABLE_NAME
from INFORMATION_SCHEMA.TABLES
where TABLE_NAME = 'TableName'
Keep in mind that if your query returns multiple rows #tablename variable will contains the last value returned.
select quotename(db_name()) + '.' + quotename( schemas.name ) + '.' + quotename( tables.name )
from sys.tables
join sys.schemas on tables.schema_id = schemas.schema_id
A couple of notes: "Catalog" in ANSI speak is Database in SQL Server, so within a database it's pretty much a constant value - the name of the current database.
In SQL Server I find the system views are more consistent and reliable than INFORMATION_SCHEMA, which mostly works but has some quirky issues.
According to your last question I'd like to suggest the following UDF:
You pass in your XML and a catalog's name (or NULLor DEFAULT) and the same with the schema's name. The function will use COALESCE to use the right portion:
CREATE FUNCTION dbo.CreateUpdateStatement
(
#XmlData XML
,#CatalogName VARCHAR(100) = NULL
,#SchemaName VARCHAR(100) = NULL
)
RETURNS VARCHAR(MAX)
BEGIN
DECLARE #RetVal VARCHAR(MAX);
WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema-instance' AS xsi)
SELECT #RetVal=
'UPDATE '
+ COALESCE(#CatalogName + '.',TheTable.TABLE_CATALOG + '.', '')
+ COALESCE(#SchemaName + '.',TheTable.TABLE_SCHEMA + '.', 'dbo.')
+ One.Record.value('TableName[1]','varchar(max)')
+ ' SET ' + One.Record.value('(Update/FieldName)[1]','varchar(max)') + '=''' + One.Record.value('(Update/NewValue)[1]','varchar(max)') + ''' '
+ ' WHERE ' + One.Record.value('KeyField[1]','varchar(max)') + '=''' + One.Record.value('TableRef[1]','varchar(max)') + ''';'
FROM #XmlData.nodes('/Task/Record') AS One(Record)
OUTER APPLY
(
SELECT TOP 1 TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME=One.Record.value('TableName[1]','varchar(max)')
) AS TheTable;
RETURN #RetVal;
END
GO
This is how you call it (I used one existing table's name spz.dbo.AuditRow in one of my catalogs):
DECLARE #x xml=
'<Task xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Record>
<order>1</order>
<TableName>AuditRow</TableName>
<KeyField>ProductPersonID</KeyField>
<TableRef>32420</TableRef>
<Update>
<FieldName>StatusID</FieldName>
<OldValue>3</OldValue>
<NewValue>8</NewValue>
</Update>
</Record>
</Task>';
SELECT dbo.CreateUpdateStatement(#x,DEFAULT,DEFAULT);
--UPDATE spz.dbo.AuditRow SET StatusID='8' WHERE ProductPersonID='32420';
SELECT dbo.CreateUpdateStatement(#x,'MyCatalog',DEFAULT);
--UPDATE MyCatalog.dbo.AuditRow SET StatusID='8' WHERE ProductPersonID='32420';
SELECT dbo.CreateUpdateStatement(#x,DEFAULT,'MySchema');
--UPDATE spz.MySchema.AuditRow SET StatusID='8' WHERE ProductPersonID='32420';
SELECT dbo.CreateUpdateStatement(#x,'MyCatalog','MySchema');
--UPDATE MyCatalog.MySchema.AuditRow SET StatusID='8' WHERE ProductPersonID='32420';
You might execute this immediately with
EXEC (SELECT dbo.CreateUpdateStatement(#x,NULL,NULL));

select columns with value NA

How to select columns in a table that only contain a specific value for all the rows? I am trying to find these columns to do an update on those values with a NULL value. In my columns I have varied range of values including NA
I am using SQL Server 2012.
I've tried doing: thsi only gives me column names. Can i add to this condition for columns with value 'NA'?
SELECT COLUMN_NAME AS NAMES,COLUMN_DEFAULT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'ABC'
I am a beginner in SQL. Trying to figure out how to do this.
If min of column equals to max then that column contains same values:
Select
case when min(col1) = max(col1) then 1 else 0 end as Col1IsSame,
case when min(col2) = max(col2) then 1 else 0 end as Col2IsSame,
...
from Table
With dynamic query:
declare #s nvarchar(max) = 'select '
select #s = #s + 'case when min(' + COLUMN_NAME + ') = max(' +
COLUMN_NAME + ') then 1 else 0 end as ' + COLUMN_NAME + ','
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'Table'
Set #s = substring(#s, 1, len(#s) - 1) + ' from Table'
exec(#s)
TRY THIS QUERY
DECLARE #SQLQUERY NVARCHAR(MAX)
declare #tableName varchar(50)
DECLARE #NAME VARCHAR(50)
Declare #ParamDefinition AS NVarchar(2000)
Set #ParamDefinition = '#OIM VARCHAR(20)'
SELECT NAME
FROM sys.objects
WHERE [object_id]=#OIM
set #tableName= (SELECT NAME
FROM sys.objects
WHERE [object_id]=#OIM)
SET #NAME=(SELECT C.NAME
FROM sys.columns c
JOIN
sys.tables t ON c.object_id = t.object_id
WHERE c.name in (select distinct name
from sys.columns
where object_id=#OIM))
SET #SQLQUERY = ''
SELECT #SQLQUERY = #SQLQUERY + 'UPDATE ' + #tableName + ' SET ' + #NAME + ' = NULL WHERE ' + #NAME + ' = NA ; '
PRINT #SQLQUERY
Execute sp_Executesql #SQLQUERY , #ParamDefinition, #OIM
end

quickest way to update a table to set blank values to NULLs?

I have a table and there are blank values in several columns, scattered all over the place.
I want to replace '' with NULL.
What's the quickest way to do this? Is there a trick I'm not aware of?
update <table name> set
<column 1> = case when <column 1> = '' then null else <column 1> end,
<column 2> = case when <column 2> = '' then null else <column 2> end
you can add as many lines as you have columns. No need for a where clause (unless you have massive amounts of data - then you may want to add a where clause that limits it to rows that have empty values in each of the columns you are checking)
If you have a lot of columns and you don't want to write the SQL manually, you can use the Information_Schema.Columns view to generate the SQL for you...
DECLARE #Table AS Varchar(100)
SET #Table = 'Your Table'
SELECT 'UPDATE ' + #Table + ' SET ' + QUOTENAME(Column_Name)
+ ' = NULL WHERE ' + QUOTENAME(Column_Name) + ' = '''''
FROM Information_Schema.Columns
WHERE Table_Name = #Table
AND Data_Type IN ( 'varchar', 'nvarchar' )
Then just copy the result set and run it in a new query window...
I did it like this:
DECLARE #ColumnNumber INT
DECLARE #FullColumnName VARCHAR(50)
DECLARE #SQL NVARCHAR(500)
SET #ColumnNumber = 0
WHILE (#ColumnNumber <= 30)
BEGIN
SET #FullColumnName = 'Column' + CAST(#ColumnNumber AS VARCHAR(10))
SET #SQL = 'UPDATE [].[].[] SET ' + #FullColumnName + ' = NULL WHERE ' + #FullColumnName + ' = '''''
EXECUTE sp_executesql
#SQL;
SET #ColumnNumber = #ColumnNumber + 1
END
This expands on JJ.'s answer. I had a table where there were there were more columns than I cared to count and I wanted to make sure that every column that had blanks were converted to nulls.
DECLARE #tableName VARCHAR(50) = 'MyTable'
DECLARE #colIndex INT = 0
DECLARE #colName VARCHAR(50)
DECLARE #sql NVARCHAR(MAX)
DECLARE #maxColCount INT = (SELECT COUNT(COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tableName)
WHILE (#colIndex <= #maxColCount)
BEGIN
SELECT #colName = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tableName AND ORDINAL_POSITION = #colIndex
SET #sql = 'UPDATE [dbo].[' + #tableName + '] SET ' + #colName + ' = NULL WHERE ' + #colName + ' = '''''
EXEC sp_executesql #sql
PRINT('Updated column ' + #colName)
SET #colIndex = #colIndex + 1
END

SELECT REPLACE on every column

I have a table containing around 100 columns, is it to possible to do a Select Replace on every column at the same time rather than typing out each column individually, i'm trying to trim the '"' of each field in the table.
SELECT
REPLACE(*, '"', '')
DECLARE #tablename nvarchar(100)= 'Test'
DECLARE #col nvarchar(max)
SELECT #col = coalesce(#col + ',', 'select ' ) +
case when data_type in ('varchar', 'char','nvarchar', 'nchar') then
'replace('+column_name+' , ''"'', '''') '+' as [' + column_name + ']' else '[' + column_name + ']' end
FROM INFORMATION_SCHEMA.COLUMNS a
WHERE table_name = #tablename
SET #col += ' from ' + #tablename
EXEC (#col)
Since you're using SQL Server, you can retrieve the names of all columns on a table using the INFORMATION_SCHEMA, e.g.
select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'yourTable'
You can then use a cursor to iterate over each column name, build some dynamic SQL and execute this using 'exec sp_executesql'.
Here's my solution:
declare #isString bit
declare #tableName nvarchar(256) = N'MyTableName'
declare #columnName nvarchar(max)
declare #sql nvarchar(max) = ''
declare c cursor local forward_only read_only for
select column_name, case when CHARACTER_SET_NAME is null then 0 else 1 end as IsString
from information_schema.COLUMNS WHERE table_name = #tableName
open c
fetch next from c into #columnName, #isString
set #sql = N'select '
declare #first bit = 1
while ##FETCH_STATUS = 0
begin
select #columnName
if #isString <> 0
begin
if #first = 0
begin
set #sql = #sql + ', '
end
set #sql = #sql + N'REPLACE(' + #columnName + ', ''"'', '''')'
set #first = 0
end
fetch next from c into #columnName, #isString
end
close c
deallocate c
set #sql = #sql + ' from ' + #tableName
exec sp_executesql #sql
Here is a recursive version:
declare #TABLE_NAME sysname = 'MyTableName'
declare #Prefix nvarchar(128) = 'REPLACE('
declare #Suffix nvarchar(128) = ', ''"'', '''')'
declare #Sql nvarchar(max)
;with Cols (TABLE_NAME, SELECT_LIST, ITERATION) as
(
select TABLE_NAME
, cast('' as nvarchar(max)) as SELECT_LIST
, 0 as ITERATION
from INFORMATION_SCHEMA.TABLES
where TABLE_NAME = #TABLE_NAME
union all
select c.TABLE_NAME
, c.SELECT_LIST
+ case when len(c.SELECT_LIST) > 0 then ', ' else '' end
+ case when i.DATA_TYPE like '%char' then #Prefix else '' end
+ cast(i.COLUMN_NAME as nvarchar(128))
+ case when i.DATA_TYPE like '%char' then #Suffix + ' as ' + cast(i.COLUMN_NAME as nvarchar(128)) else '' end
, c.ITERATION + 1
from INFORMATION_SCHEMA.COLUMNS i
join Cols c on i.TABLE_NAME = c.TABLE_NAME
where i.ORDINAL_POSITION = c.ITERATION + 1
)
select #Sql = ('select ' + a.SELECT_LIST + ' from ' + a.TABLE_NAME)
from Cols a
join (
select TABLE_NAME, max(ITERATION) as ITERATION
from Cols
group by TABLE_NAME
) as b on a.TABLE_NAME = b.TABLE_NAME
and a.ITERATION = b.ITERATION
exec (#sql)