Dynamic SQL Server query - sql

I am writing a dynamic insert query in a stored procedure. I am receiving the column names as parameter to my stored procedure.
For example, I have an Employee table with EmployeeId and EmployeeName columns. I need to append EMP_ before each employee name while inserting the data into Department table from Employee table.
Non-dynamic query looks like this.
INSERT INTO Department(EmployeeId, EmployeeName)
SELECT
EmployeeId, 'EMP_' + EmployeeName
FROM
Employee
If I write a dynamic insert
SET #SqlCommand =
'INSERT INTO ' + #DepartmentTable + '(' + #EmployeeIdColumn + ',' + #EmployeeNameColumn + ')' +
'SELECT ' + #EmployeeIdColumn + ',''EMP_''' + #EmployeeNameColumn + '''' +
'FROM ' +
#EmployeeTable + ' WTB '
EXEC sp_executesql
#stmt = #SqlCommand
The issue is, for the EmployeeName column, it is inserting "EMP_EmployeeName" instead of actual employee name. I tried putting quotes before and after EmployeeNameColumn, but it didn't work. How can I fix it?

You need just one + after EMP_'', and remove it after ' WTB '. Also i fixed some spaces:
SET #SqlCommand =
'INSERT INTO ' + #DepartmentTable + ' (' + #EmployeeIdColumn + ',' + #EmployeeNameColumn + ')' +
' SELECT ' + #EmployeeIdColumn + ',''EMP_''+' + #EmployeeNameColumn +
' FROM ' + #EmployeeTable + ' WTB '
If you PRINT #SqlCommand you will get something like this:
INSERT INTO Department (EmpId,EmpName) SELECT EmpId,'EMP_'+EmpName FROM Employee WTB
And one note: better use QUOTENAME with table/column names. It will help to avoid situations where column has spaces in the name like 'Employee Name':
SET #SqlCommand =
'INSERT INTO ' + QUOTENAME(#DepartmentTable) + '(' + QUOTENAME(#EmployeeIdColumn) + ',' + QUOTENAME(#EmployeeNameColumn) + ')'+
' SELECT ' + QUOTENAME(#EmployeeIdColumn) + ',''EMP_''+' + QUOTENAME(#EmployeeNameColumn) +
' FROM ' + QUOTENAME(#EmployeeTable) + ' WTB '
To get:
INSERT INTO [Department]([EmpId],[EmpName]) SELECT [EmpId],'EMP_'+[EmpName] FROM [Employee] WTB

Try using the CONCAT function.
-- Syntax for SQL Server, Azure SQL Database, Azure SQL Data Warehouse, Parallel Data Warehouse
CONCAT ( string_value1, string_value2 [, string_valueN ] )
Your query would then look like this :
INSERT INTO deptTable(empId,empName)
SELECT empId,concat('EMP_', empName) as empName FROM empTable
PS: Looks like I misunderstood your question.
INSERT INTO deptTable(empId,empName)
SELECT empId,'SUFFIX'+empName as empName FROM empTable
will also work. I guess you wanted it for the stored proc.
In any case the concat should still do it.

Here is the dynamic query to create stored procedure with insert statement with columns and parameters
> DECLARE #table_name varchar(255) = 'table_name'
> DECLARE #v_col varchar(MAX)
> DECLARE #v_param varchar(MAX)
> DECLARE #SP_param varchar(MAX)
> DECLARE #sp_type varchar(10) = 'Insert'
>
> SET #v_col = STUFF(
> (SELECT ',' + '['+c.name+']'
> FROM sys.tables t JOIN sys.columns c ON t.object_id = c.object_id
> WHERE t.name = #table_name
> AND c.is_identity = 0
> FOR XML PATH ('')), 1, 1, ''
> )
> SET #v_param = STUFF(
> (SELECT ',' + '#'+c.name
> FROM sys.tables t JOIN sys.columns c ON t.object_id = c.object_id
> WHERE t.name = #table_name
> AND c.is_identity = 0
> FOR XML PATH ('')), 1, 1, ''
> )
>
> SET #SP_param = STUFF(
> (SELECT ',' + '#'+c.name+' '+y.name+' '+(CASE WHEN y.name = 'varchar' THEN '('+CAST(c.max_length as varchar)+')'
> ELSE '' END)
> FROM sys.tables t JOIN sys.columns c ON t.object_id = c.object_id
> JOIN sys.types y ON y.user_type_id = c.user_type_id
> WHERE t.name = #table_name
> AND c.is_identity = 0
> FOR XML PATH ('')), 1, 1, ''
> )
> Declare #Query VARCHAR(MAX)
> DECLARE #SPQuery VARCHAR(MAX)
> SET #SPQuery = 'CREATE PROCEDURE '+#sp_type+''+#table_name+' ('+#SP_param+')
> AS BEGIN'
> SET #Query='Insert Into '+#table_name+' ('+#v_col+')
> Values (
> '+#v_param+')
> END'
>
>
> PRINT(#SPQuery);
> PRINT(#Query);

Related

Grabbing Null and blank Columns to a table

I'm trying to find a way to grab the count of nulls and blanks of every column in a table and put the results into a table. I found this but don't know how to push it to a table? Would also like to add in a Count(distinct fieldname) as well. Any help would be appreciated!
DECLARE #t nvarchar(max)
SET #t = N'SELECT '
SELECT #t = #t + 'sum(case when ' + c.name + ' is null or ' + c.name + ' = '''' then 1 else 0 end) "' + c.name + '",
sum(case when ' + c.name + ' is null then 0 else 1 end) "Non-Null Values for ' + c.name + '",'
FROM sys.columns c
WHERE c.object_id = object_id('TableName');
SET #t = SUBSTRING(#t, 1, LEN(#t) - 1) + ' FROM TableName;'
EXEC sp_executesql #t
**Edit
This provides the results in one row. Is there a way to do it so each field gets it's own row in a table?
FieldName CountofNullsBlanks
FieldA 0
FieldB 100
Here:
DECLARE #t nvarchar(max)
SET #t = N'SELECT '+convert(nvarchar(max),count(*))+' as [Distinct fieldnames],' -- added the distinct
SELECT #t = #t + 'sum(case when ' + c.name + ' is null or ' + c.name + ' = '''' then 1 else 0 end) "' + c.name + '",
sum(case when ' + c.name + ' is null then 0 else 1 end) "Non-Null Values for ' + c.name + '",'
FROM sys.columns c
WHERE c.object_id = object_id('YOURTABLE');
SET #t = SUBSTRING(#t, 1, LEN(#t) - 1) + 'into ##a FROM YOURTABLE;' --added the into ##a
EXEC sp_executesql #t
Notice the "into ##a" towards the end; This saves the result "table" to a global temp, which will be available until all sessions that accessed it finish. Careful with the name or it might cause conflicts in the database.

Put single quotes into single quotes in SQL Server string

I have the update query below.
update tableName
set columnName = null
where isnull(columnName, '') = ''
I want to put single quotes in a SQL Server string builder query so that the above query can be executed for every column in the table. See this query:
Declare #sql2 varchar(max) = ''
declare #tablename2 as varchar(255) = 'test2'
select #sql2 = #sql2 + 'update [' + #tablename2 + '] set [' + c.name +']' + ' = NULL ' +
' WHERE ISNULL([' + c.name + '], ' + '' + ') = ' + ''
from sys.columns c
inner join sys.tables t on c.object_id = t.object_id
where t.name = #tablename2
EXEC (#sql2)
go
Below is test data.
create table test2
(
test varchar(50)
)
insert into test2
values (' ewewwe'), ('sdsddsds '), ('')
I get this error while executing the SQL String builder query:
Incorrect syntax near ') = '
What am I doing wrong?
The error you receive is because the statement string is not valid. You end up with an unescaped string.
You need to add an escaped quote ('') for each quote you need, ('''''') like this:
Declare #sql2 varchar(max) =''
declare #tablename2 as varchar(255) ='test2'
select #sql2 = #sql2 + 'update [' + #tablename2 + '] set [' + c.name + ']' + ' = NULL ' +
' WHERE ISNULL([' + c.name + '], ' + '''''' + ') = ' + ''''''
from sys.columns c
inner join sys.tables t on c.object_id = t.object_id
where t.name = #tablename2
EXEC (#sql2)
go
when you use isnull, you have to provide 2 parameters
' WHERE ISNULL([' + c.name + '], ' + '???' + ') = ' + ''
You need to provide something for the ??? and currently its empty
Replace with
WHERE ISNULL([' + c.name + '], ' + '''''' + ')
Single quotes are self-escaped; that is, you put two together in a literal to get one in the final string.
Additionally, you want the QUOTENAME() function to handle enclosing these fields. It's smart enough to also account for names that might include braces or other weirdness, plus you can expect it to be updated if anything else is ever added to the language that might interfere:
DECLARE #sql2 varchar(max) = ''
DECLARE #tablename2 as varchar(255) = 'test2'
SELECT #sql2 = #sql2 +
'update ' + QUOTENAME(#tablename2) +
' set ' + QUOTENAME(c.name) + ' = NULL' +
' WHERE COALESCE(RTRIM(' + QUOTENAME(c.name) + '), '''') = '''' '
FROM sys.columns c
INNER JOIN sys.tables t on c.object_id = t.object_id
WHERE t.name = #tablename2
EXEC(#sql2)

How to check a condition against all the columns of a table?

I have a table which has more than 30 columns(all are varchar). I need to list out all the columns which contains blank i.e.' ' values.
I tried using 'coalesce' but it is only for NULL.
The following query will give you all the columns in a table that might have null or '' values.
It is written so that you can run it for all tables in your database but you can limit it to a single table, as I have done for this specific example, checking a table called testingNulls:
--two variables needed for table name and column name, when looping through all tables
declare #table varchar(255), #col varchar(255), #sql varchar(max)
--this will be used to store the result, to have one result set instead of one row per each cursor cycle
if object_id('tempdb..#nullcolumns') is not null drop table #nullcolumns
create table #nullcolumns (tablename varchar(255), columnname varchar(255))
declare getinfo cursor for
select t.name tablename, c.name
from sys.tables t join sys.columns c on t.object_id = c.object_id
where t.name = 'testingnulls' --here the condition for the table name
open getinfo
fetch next from getinfo into #table, #col
while ##fetch_status = 0
begin
select #sql = 'if exists (select top 1 * from [' + #table + '] where [' + #col + '] is null or [' + #col + '] like '''' ) begin insert into #nullcolumns select ''' + #table + ''' as tablename, ''' + #col + ''' as all_nulls end'
print(#sql)
exec(#sql)
fetch next from getinfo into #table, #col
end
close getinfo
deallocate getinfo
--this should be the result you need:
select * from #nullcolumns
You can see a working example here. I hope this is what you need.
List all columns that contain a blank in some record? You'd use a query per column and collect the results with UNION ALL:
select 'COL1' where exists (select * from mytable where col1 like '% %')
union all
select 'COL2' where exists (select * from mytable where col2 like '% %')
union all
...
union all
select 'COL30' where exists (select * from mytable where col30 like '% %');
If you want like select * from [your_table_name] where [col1] = '' and [col2] = ''....., then use dynamic sql query like below.
Query
declare #sql as varchar(max);
select #sql = 'select * from [your_table_name] where '
+ stuff((
select ' and [' + [column_name] + '] = ' + char(39) + char(39)
from information_schema.columns
where table_name = 'your_table_name'
for xml path('')
)
, 1, 5, ''
);
exec(#sql);
Update
Or else if you want to list the column names which have a blank value, then you can use the below dynamic sql query.
Query
declare #sql as varchar(max);
select #sql = stuff((
select ' union all select ' + [column_name] + ' as [col1], '
+ char(39) + [column_name] + char(39) + ' as [col2]'
+ ' from your_table_name'
from information_schema.columns
where table_name = 'your_table_name'
for xml path('')
)
, 1, 11, ''
);
set #sql = 'select distinct t.col2 as [blank_cols] from(' + #sql
+ ')t
where coalesce(ltrim(rtrim(t.col1)), ' + char(39) + char(39) + ') = '
+ char(39) + char(39) + ';';
exec(#sql);
Find a demo here
But still I'm not sure that this is what you are looking out for.
you have not many choices but to specify all the columns in your where clause
WHERE COL1 = '' AND COL2 = '' AND COL3 = '' AND . . .
or you can use Dynamic SQL to form your query, but that is not an easy path to go
If you want to count number of columns having '' value in a table (not for each row) then use the following
SELECT max(CASE WHEN col1 = '' THEN 1 ELSE 0 END) +
max(CASE WHEN col2 = '' THEN 1 ELSE 0 END) +
max(CASE WHEN col3 = '' THEN 1 ELSE 0 END) +
...
FROM t
demo
I created a dynamic SQL script that you can use by providing the table name only
Here it is
declare #sql nvarchar(max)
declare #table sysname = 'ProductAttributes'
select #sql =
'select * from ' + #table + ' where ' +
string_agg('[' + name + '] = '' '' ', ' and ')
from sys.columns
where object_id = OBJECT_ID(#table)
select #sql
exec sp_executesql #sql
Unfortunately, for SQL string concatenation String_Agg function is new with SQL Server 2017
But it is also possible to use SQL XML Path to concatenate WHERE clause fragments
SELECT #sql = 'select * from ' + #table + ' where ' +
STUFF(
(
SELECT
' and ' + '[' + [name] + '] = '' '' '
from sys.columns
where object_id = OBJECT_ID(#table)
FOR XML PATH(''),TYPE
).value('.','VARCHAR(MAX)'
), 1, 5, ''
)
select #sql as sqlscript
exec sp_executesql #sql

Append Quotes for all VARCHAR Columns when exporting to csv file

I have a stored procedure which when run gives a table output. I want to export this procedure to a csv file but want to append double/single quotes for all the columns with a datatype CHAR/VARCHAR.
For Example:
Stored Proc O/P:
ID Name Address SSN
1 abd 9301,LeeHwy, 22031 64279100
Output in CSV File:
1,"abd","9301,LeeHwy, 22031",64279100
Can anyone also help me on how I can use a BAT file to execute the procedure and generate this csv file.
One way to do this, is to loop through the table schema to extract the varchar columns. I have tested this for one of my tables, and it worked:
DECLARE #tableName VARCHAR(Max) = '[Put your table name here]';
DECLARE #currColumns VARCHAR(Max) = NULL;
SELECT #currColumns = COALESCE(#currColumns + ','
+ CASE WHEN t.Name = 'varchar' THEN '''"'' + ' ELSE '' END
+ '[', '[') + c.name + ']'
+ CASE WHEN t.Name = 'varchar' THEN '+ ''"''' ELSE '' END
+ ' as [' + c.name + ']'
FROM
sys.columns c
INNER JOIN
sys.types t ON c.user_type_id = t.user_type_id
WHERE
c.object_id = OBJECT_ID(#tableName)
EXEC('SELECT ' + #currColumns + ' FROM ' + #tableName);
It's a quick and dirty way.
UPDATE (comment):
Inserting into a table is really easy. Just do this:
INSERT INTO [TABLE]
EXEC('SELECT ' + #currColumns + ' FROM ' + #tableName);
I have found a solution for my problem.
Credits also go to #Rogala (The developer who gave initial answer to the question) for triggering the idea of using system tables.
The code is as below:
DECLARE #tableName VARCHAR(Max) = '[Put your table name here]';
DECLARE #currColumns VARCHAR(Max) = NULL;
Declare #Delim CHAR(5)='''"''+'
SELECT #currColumns = COALESCE(#currColumns + ','+ CASE WHEN DATA_TYPE= 'varchar' THEN '''"'' + ' ELSE '' END + '[', '[') + COLUMN_NAME + ']'
+ CASE WHEN DATA_TYPE = 'varchar' THEN '+ ''"''' ELSE '' END + ' as [' + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.Columns
WHERE table_name = #tableName
Set #currColumns= #Delim+#currColumns
EXEC('SELECT ' + #currColumns + ' FROM ' + #tableName);

Dynamically Count Null Values in SQL Server

I'm a little new at SQL so please bear with me. I am attempting to write some a query that will allow me to loop through an entire table and find the number of times null values appear in each column. This is easy to do the hard way by typing the following:
Select
SUM(CASE COL_1 WHEN IS NULL THEN 1 ELSE 0 END) AS COL_1_NULLS
,SUM(CASE COL_2 WHEN IS NULL THEN 1 ELSE 0 END) AS COL_2_NULLS
FROM TABLE1
This is easy but it can become arduous if you want to do this for multiple tables or if a single table has a lot of columns.
I'm looking for a way to write a query that passes a table name into it and then loops through each column in the defined table (possibly pulling the column name by ordinance via a join to a metadata view?) and then sums the number of nulls in the column. Before anyone jumps on the nitpick bandwagon please keep in mind that this basic idea could be used for more than just finding nulls. Any assistance with this issue is greatly appreciated.
You need to use dynamic sql:
declare #custom_sql varchar(max)
set #custom_sql = 'SELECT null as first_row'
select
#custom_sql = #custom_sql + ', ' + 'SUM(CASE WHEN ' + COLUMN_NAME + ' IS NULL THEN 1 ELSE 0 END) as ' + COLUMN_NAME + '_NULLS'
from
INFORMATION_SCHEMA.COLUMNS where table_name = 'MYTABLE'
set #custom_sql = #custom_sql + ' FROM MYTABLE'
exec(#custom_sql)
You can also use the COALESCE term (just for a slightly different approach):
declare #custom_sql varchar(max)
select
#custom_sql = COALESCE(#custom_sql + ', ', '') + 'SUM(CASE WHEN ' + COLUMN_NAME + ' IS NULL THEN 1 ELSE 0 END) as ' + COLUMN_NAME + '_NULLS'
from
INFORMATION_SCHEMA.COLUMNS where table_name = 'users'
set #custom_sql = 'SELECT ' + #custom_sql
set #custom_sql = #custom_sql + ' FROM Users'
print #custom_sql
exec(#custom_sql)
I don't know how to make a generic query, but you can always generate the script like this
declare #sql nvarchar(max) = 'select 1 as dummy'
select #sql = #sql + '
, sum(case when [' + c.name + '] is null then 1 else 0 end) as [' + c.name + '_NULLS]'
from sys.columns c
join sys.tables t on t.object_id = c.object_id
where t.name = 'TABLE1'
set #sql = #sql + ' from TABLE1'
select #sql
Then you can execute the result eg. with exec sp_executesql #sql
For a cooler approach, you can use ISNULL to skip the first comma.
declare #sql nvarchar(max)
declare #tablename nvarchar(255) = 'xxxx'
Select #sql = ISNULL(#SQL + ',','') + ' ' + COLUMN_NAME + '_count = Sum(case when ' + COLUMN_NAME + ' is null then 1 else 0 end)' + char(13)
From information_schema.columns
where table_name = #tablename
set #sql = 'Select' + #sql + ' From ' + #tablename
print #sql
exec sp_executesql #sql