update special character columns dynamically for all columns of a table? - sql

I want to replace special characters by normal characters in all columns dynamically for all columns of a table.But it works only for a column which is hardcoded
alter proc dbo.specialcharacterreplacer
#tblname varchar(1000),
#column_name varchar(1000)
as
begin
declare #Sql VARCHAR(MAX)
set #Sql = '
UPDATE ' + #tblname + ' SET ' + #column_name+ ' = REPLACE('+#column_name + ', ' + '''ó'''+ ', '+'''o'''+')
UPDATE ' + #tblname + ' SET ' + #column_name+ ' = REPLACE('+#column_name + ', ' + '''ò'''+ ', '+'''o'''+')
UPDATE ' + #tblname + ' SET ' + #column_name+ ' = REPLACE('+#column_name + ', ' + '''ö'''+ ', '+'''o'''+')
UPDATE ' + #tblname + ' SET ' + #column_name+ ' = REPLACE('+#column_name + ', ' + '''ð'''+ ', '+'''o'''+')
exec (#sql)
end
go
EXEC dbo.specialcharacterreplacer #tblname = 'dirtyyyysource', #column_name ='select *from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '#tblname''
how to make columns dynamic?

This was the central code to get your update statement for all columns of a given table dynamically. Be aware of TABLE_SCHEMA and the column's type. You might use some additions in the WHERE part... (in my example you'd try to replace the INT column as well...)
And you might have a look here: https://stackoverflow.com/a/32048968/5089204
There you'll find one of my former answers to a similar question and shows an approach how to create a function which will replace several special characters in one go.
CREATE TABLE dbo.TestTable(ID INT,Test1 VARCHAR(100), Test2 VARCHAR(100));
GO
declare #tblname varchar(1000)='TestTable';
declare #tblschema varchar(1000)='dbo';
DECLARE #SqlCmd VARCHAR(MAX)= 'UPDATE ' + #tblname + ' SET ' +
(
STUFF(
(
SELECT ',' + COLUMN_NAME + ' = REPLACE(' + COLUMN_NAME + ', ' + '''ó'', ''o'''+')'+ CHAR(10) --might need to use CHAR(13)+CHAR(10)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA=#tblschema AND TABLE_NAME = #tblname
FOR XML PATH('')
),1,1,'') + ';'
);
SELECT #SqlCmd;
GO
DROP TABLE dbo.TestTable;
GO
The result:
UPDATE TestTable SET ID = REPLACE(ID, 'ó', 'o')
,Test1 = REPLACE(Test1, 'ó', 'o')
,Test2 = REPLACE(Test2, 'ó', 'o')
;

Related

Dynamic SQL - Insert a variables via INSERT INTO x SELECT statement

I would like to ask how can I insert a variables into a table using INSERT INTO x SELECT statement via dynamic SQL.
I have following table:
|-------------------|-----------------|--------------|-----------------|
| TableName | ColName | Value | SQL_Statement |
|-------------------|-----------------|--------------|-----------------|
I get a content for Value column by this query:
INSERT INTO #ReturnTable(Value) SELECT TreeHolder FROM prm.Schm_Root WHERE ParentTreeHolderId = 'DD040D31-4591-4658-A02E-A6ED00AB64F2';
But I need to fill whole table. Please consider that other values are variables, not SQL queries.
SELECT #TableSchema = TableSchema FROM #TableNames WHERE Id = #Counter;
SELECT #TableName = TableName FROM #TableNames WHERE Id = #Counter;
SELECT #ColName = ColName FROM #TableNames WHERE Id = #Counter;
SET #SQL_Statement = 'SELECT ' + #ColName + ' FROM ' + #TableSchema + '.' + #TableName + ' WHERE ' + #ColName + ' = ' + '''''' + CAST(#GuidArgument AS NVARCHAR(50)) + '''''' + ';';
Now I have this query that fills a table:
SET #SQL_String = N'INSERT INTO #ReturnTable SELECT
''' + #TableName + ''',
''' + #ColName + ''',
''' + #SQL_Statement + ''',
'' + Value + '',
(SELECT ' +
#ColName + '
FROM ' +
#TableSchema + '.' + #TableName + '
WHERE ' +
#ColName + ' = ''' + CAST(#GuidArgument AS NVARCHAR(50)) + '
'')';
EXECUTE sp_executesql #SQL_String
PRINT #SQL_String;
The thing I need is to rewrite this query from INSERT INTO ? VALUE to INSERT INTO ? SELECT format.
If I understand correctly, you want to insert SQL execute syntax string and it results in ReturnTable table.
I would let subquery SQL execute syntax save in a variable. because the will be more clear what you need to do.
Declare a new variable #SQL_excuteStatement variable to save your execute syntax.
the #SQL_Statement to carry the original SQL string.
set #SQL_Statement = 'SELECT ' + #ColName +
' FROM ' + #TableSchema + '.' + #TableName +
' WHERE ' + #ColName + ' = '+'''''' + CAST(#GuidArgument AS NVARCHAR(50)) + '''''';
and use select ... from table instead of subquery in select
There is a sample for you.
DECLARE #SQL_String NVARCHAR(MAX)
DECLARE #TableSchema NVARCHAR(MAX)
DECLARE #TableName NVARCHAR(MAX)
DECLARE #ColName NVARCHAR(MAX)
DECLARE #Counter int = 1
DECLARE #SQL_Statement NVARCHAR(MAX)
DECLARE #GuidArgument INT = 1
CREATE TABLE TableNames(
ID INT,
TableSchema NVARCHAR(100),
TableName NVARCHAR(100),
ColName NVARCHAR(100)
);
CREATE TABLE ReturnTable(
TableName NVARCHAR(100),
ColName NVARCHAR(100),
SQL_Statement NVARCHAR(max),
value nvarchar(max)
);
INSERT INTO TableNames VALUES (1,'dbo','T','val');
CREATE TABLE T(val INT);
INSERT INTO T VALUES (1)
SELECT #TableSchema = TableSchema FROM TableNames WHERE Id = #Counter;
SELECT #TableName = TableName FROM TableNames WHERE Id = #Counter;
SELECT #ColName = ColName FROM TableNames WHERE Id = #Counter;
set #SQL_Statement = 'SELECT ' + #ColName +
' FROM ' + #TableSchema + '.' + #TableName +
' WHERE ' + #ColName + ' = '+ '''''' + CAST(#GuidArgument AS NVARCHAR(50)) + '''''';
SET #SQL_String = N'INSERT INTO ReturnTable (TableName,ColName,SQL_Statement,value)
SELECT '''+ #TableName + ''','''+ #ColName + ''','''+ #SQL_Statement + '''' + ',' + QUOTENAME(#ColName) +
' FROM ' + QUOTENAME(#TableSchema) + '.' + QUOTENAME(#TableName) + '' +
' WHERE ' + #ColName + ' = ''' + CAST(#GuidArgument AS NVARCHAR(50)) + '''';
EXECUTE sp_executesql #SQL_String
sqlfiddle
Note
I would suggest you use clear column after insert into
INSERT INTO table2 (column1, column2, column3, ...)
SELECT column1, column2, column3, ...
FROM table1
WHERE condition;

Comparing string with an UNIQUEIDENTIFIER?

I have written the following procedure:
ALTER PROCEDURE [dbo].[GetLocationOfGuidPre]
#GuidArgument UNIQUEIDENTIFIER
.
.
.
SET #SQL_String = 'INSERT INTO #Guids(FoundGuid) SELECT ' + #ColName + ' FROM ' + #TableSchema + '.' + #TableName + ' WHERE ' + #ColName + ' = ' + #GuidArgument;
When I try to execute it, I get this error:
The data types nvarchar and uniqueidentifier are incompatible in the add operator.
How can I compare a string value with UNIQUEIDENTIFIER?
Have you tried passing it as a parameter?
SET #SQL_String = 'INSERT INTO #Guids(FoundGuid) SELECT ' + #ColName + ' FROM ' + #TableSchema + '.' + #TableName + ' WHERE ' + #ColName + ' = #GuidArgument';
EXEC sp_executesql #SQL_string,
N'#GuidArgument UNIQUEIDENTIFIER',
#GuidArgument = #GuidArgument;
I guess the reason for this error is pretty clear: it says + ' = ' + #GuidArgument; does not work, since you try to add an unique ID to a varchar... just try to cast your #GuidArgumentas varchar and it should work.

Adding an apostrophe into a dynamic SQL

I would like to ask how can I add an apostrophe into a dynamic SQL. I need to return an SQL statement in one of the columns which has to have apostrophes in itself.
I have the following statement:
SET #SQL_String = N'INSERT INTO #ReturnTable
(
TableName,
ColName,
SQL_Statement,
Value
)
VALUES
(
''' + #TableName + ''',
''' + #ColName + ''',
''' +
'SELECT ' +
#ColName +
' FROM ' +
#TableSchema + '.' + #TableName +
' WHERE ' +
#ColName + ' = ' + CAST(#GuidArgument AS NVARCHAR(50)) + ';' +''',
(
SELECT
' + #ColName + '
FROM
' + #TableSchema + '.' + #TableName +
' WHERE '
+ #ColName + ' = ''' + CAST(#GuidArgument AS NVARCHAR(50)) +
'''))';
Executing with:
EXECUTE #RC = [dbo].[GetLocationOfGuidPre] 'F2CAB996-F00F-43B8-A67A-0000721A829D'
I need to put a whole first CAST into a pair of '.
I've tried:
Putting whole CAST statement into a separeted variable like: DECLARE #Test NVARCHAR(50);
SET #Test = CAST(#GuidArgument AS NVARCHAR(50));
SET #Test = 'CAST(#GuidArgument AS NVARCHAR(50))';
SET #Test = '''CAST(#GuidArgument AS NVARCHAR(50))''';
Addidng two more apostrophes:
' WHERE ' + #ColName + ' = ''' + CAST(#GuidArgument AS NVARCHAR(50)) + ''';'
Please use CHAR(39) instead of typing ' in your dynamic code directly.
Example:
declare #my_dynamic_sql nvarchar(max) = 'print char(39);';
exec(#my_dynamic_sql);

Population of Visual Studio Database Project data-loading scripts from existing data

So, I've been hunting for a solution for this for awhile and have come up with what sort of works ... but I can't help feeling that there must be something more elegant.
What I'm looking for is to be able to extract existing data from a populated database & incorporate that data into loading scripts. The database schema & configuration data will be rolled out multiple times, and will change as development continues, so it's important to be able to rebuild the configuration data from existing data, rather than from static data kept in scripts.
Here's what I've cobbled together:
create procedure #dump (
#TableName varchar(128)
)
as
set nocount on
set rowcount 0
declare #template varchar(max)
set #template = 'SET IDENTITY_INSERT [dbo].[' + #TableName + '] ON
MERGE INTO [dbo].[' + #TableName + '] AS [Target]
USING
(
VALUES
{vals}
)
AS [Source] ({fields})
ON [Target].[{pk}] = [Source].[{pk}]
WHEN MATCHED THEN UPDATE SET
{upds}
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
{fields}
)
VALUES
(
{fields}
);
SET IDENTITY_INSERT [dbo].[' + #TableName + '] OFF
--------------------------------------------------
'
declare #pk varchar(max) = ''
declare #vals varchar(max) = '/*
set concat_null_yields_null off
select ''' + '(' + ''' + replace(replace({casts} + '') ,'', '',,'', '', null,''), ''' + ',)' + ''', ''' + ',null)' + ''') from [' + #TableName + ']
*/'
declare #casts varchar(max) = ''
declare #fields varchar(max) = ''
declare #upds varchar(max) = ''
declare #inserts varchar(max) = ''
set #pk = SUBSTRING(#TableName, 1, len(#TableName) - 1) + 'ID'
declare cur_flds
cursor for select c.name, c.type
from syscolumns c
where c.id = object_id(#TableName)
order by c.colid
declare #fn varchar(max)
declare #ft int
open cur_flds
fetch next from cur_flds into #fn, #ft
while ##FETCH_STATUS = 0
begin
if len(#fields) > 0
set #fields = #fields + ', '
set #fields = #fields + '[' + #fn + ']'
if len(#casts) > 0
set #casts = #casts + ' + ' + ''','' + '
if #ft in(56,55,50,38,48)
set #casts = #casts + 'cast([' + #fn + '] as varchar)'
else if #ft = 111
set #casts = #casts + ''''''''' + ' + 'cast([' + #fn + '] as varchar) + ' + ''''''''''
else
set #casts = #casts + ''''''''' + ' + 'replace([' + #fn + '], ''''''''' + ', ' + ''''''''''''') + '''''''''
if #fn != #pk
begin
if len(#upds) > 0
set #upds = #upds + ', '
set #upds = #upds + '[Target].[' + #fn + '] = [Source].[' + #fn + ']'
end
fetch next from cur_flds into #fn, #ft
end
close cur_flds
deallocate cur_flds
set #vals = REPLACE(#vals, '{casts}', #casts)
set #template = REPLACE(#template, '{pk}', #pk)
set #template = REPLACE(#template, '{vals}', #vals)
set #template = REPLACE(#template, '{fields}', #fields)
set #template = REPLACE(#template, '{upds}', #upds)
set #template = REPLACE(#template, '{inserts}', #inserts)
print #template
go
exec #dump 'ActionItemSystems'
drop proc #dump
That ends up giving me output of:
SET IDENTITY_INSERT [dbo].[ActionItemSystems] ON
MERGE INTO [dbo].[ActionItemSystems] AS [Target]
USING
(
VALUES
/*
set concat_null_yields_null off
select '(' + replace(replace(cast([ActionItemSystemID] as varchar) + ',' + '''' + replace([ActionItemSystemName], '''', '''''') + '''' + ') ,', ',,', ', null,'), ',)', ',null)') from [ActionItemSystems]
*/
)
AS [Source] ([ActionItemSystemID], [ActionItemSystemName])
ON [Target].[ActionItemSystemID] = [Source].[ActionItemSystemID]
WHEN MATCHED THEN UPDATE SET
[Target].[ActionItemSystemName] = [Source].[ActionItemSystemName]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
[ActionItemSystemID], [ActionItemSystemName]
)
VALUES
(
[ActionItemSystemID], [ActionItemSystemName]
);
SET IDENTITY_INSERT [dbo].[ActionItemSystems] OFF
From this point, I can take the commented-out bit
set concat_null_yields_null off
select '(' + replace(replace(cast([ActionItemSystemID] as varchar) + ',' + '''' + replace([ActionItemSystemName], '''', '''''') + '''' + ') ,', ',,', ', null,'), ',)', ',null)') from [ActionItemSystems]
execute that, and get output like:
(33,'7111-5 -Upstream/Seed Lab') ,
(32,'7301-Seed Lab') ,
(30,'7807 UFDF') ,
(14,'BAS Panel Upgrade') ,
(1,'Clean Steam') ,
(13,'DCS') ,
(2,'HWFI') ,
(3,'MCS') ,
(12,'MES') ,
(31,'Seed Lab') ,
(18,'UCS WRO') ,
(34,'Upstream Seed Lab') ,
(29,'Viral Filtration') ,
which can then be incorporated (sans the final comma) into the script.
Now, this solution functions, but it's fragile. It depends on various assumptions (e.g., that the Table Name will have a Primary Key of Table Name - trailing 's' and plus ID) that may not hold true for every solution. It also requires cutting & pasting, and rerunning from the start when the table structures change.
This is probably quite a lot of background ... which I'm partly sharing because I couldn't find anything similar out there & thought that somebody might benefit from this. However, I still come back to my real question, which is to say: where's the tool to generate this kind of script for VS Database Projects? There really should be something - something that would take into account whatever the primary key is, that would generate the thing entire, etc.
You can try with this procedure for generating MERGE statements:
https://github.com/readyroll/generate-sql-merge
It is more advanced version of what you already have.

How do I script my table to generate INSERT INTO commands?

I have a lookup table with about 10 records, I know I can script the structure to a text file, but how can I script the data to insert into commands?
Ten records, and it's urgent?
Just type it out manually. Should be pretty easy to cut-n-paste.
Assuming SQL Server...
SQL Management Studio will generate an insert script. Right-click your database and select Tasks-Export data
This depends pretty much on the tools you are using...
The quick and dirty way is to run a select into a string and tell sql enterprise manager to give you text (not grid) as the output
SELECT 'INSERT INTO TABLES (fields here) VALUES (' + field1 + ', '....
Do something like this:
select "insert into my_targ_table(my_field_1, my_field_2, ..., my_field_n) values(" || x.my_field_1_col || ", " || x.my_field_2_col || ");"
from my_source_table x
Then just run the script you've generated.
This code works with all tables
DECLARE #TblName varchar(128)
DECLARE #WhereClause varchar(255)
DECLARE #cmd1 varchar(7000)
DECLARE #cmd2 varchar(7000)
SET #TblName = '<tablename>' --Name of your table
SET #WhereClause = ' ' --where clause ex columnA = 1
SET #cmd1 = 'SELECT '' INSERT INTO ' + #TblName + ' ( '
SET #cmd2 = ' + '' VALUES ( '' + '
create table #tableDef (id int identity (1,1), ColType int, ColName varchar(128))
--Fetch column names and datatypes
insert #tableDef (ColType, ColName)
select case when DATA_TYPE like '%char%' then 1
when DATA_TYPE like '%datetime%' then 2
else 0 end ,
COLUMN_NAME
from information_schema.columns
where TABLE_NAME = #TblName
order by ORDINAL_POSITION
SELECT #cmd1 = #cmd1 + ColName + ',',
#cmd2 = #cmd2
+ ' CASE WHEN ' + ColName + ' IS NULL '
+ ' THEN ''NULL'' '
+ ' ELSE '
+ case ColType
when 1 then ''''''''' + ' + ColName + ' + '''''''''
when 2 then ''''''''' + ' + 'CONVERT(VARCHAR(20),' + ColName + ')' + ' + '''''''''
else 'CONVERT(VARCHAR(20),' + ColName + ')' end
+ ' END + '','' + '
from #tableDef
order by id
select #cmd1 = left(#cmd1,len(#cmd1)-1) + ' ) '' '
select #cmd2 = left(#cmd2,len(#cmd2)-8) + '+'')'' FROM ' + #tblName + #WhereClause
select '/*' + #cmd1 + #cmd2 + '*/'
exec (#cmd1 + #cmd2)
drop table #tableDef