Put single quotes into single quotes in SQL Server string - sql

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)

Related

A SELECT INTO statement cannot contain a SELECT statement that assigns values to a variable

I am trying to create a stored procedure or function to find the number of null values in each column in a table.
I am having problems determining the syntax for converting the code to a stored procedure/function.
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = (
SELECT '
' +
STUFF((
SELECT ', [' + c.name + '] = ' + CASE WHEN c.is_nullable = 0 THEN '0' ELSE 'COUNT(*) - COUNT([' + c.name + '])' END
FROM sys.columns c
WHERE c.[object_id] = o.[object_id]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, 'SELECT ''' + SCHEMA_NAME(o.[schema_id]) + '.' + o.name + ''', COUNT(*), ') + '
FROM [' + SCHEMA_NAME(o.[schema_id]) + '].[' + o.name + ']'
FROM sys.objects o
WHERE o.[type] = 'U'
AND o.is_ms_shipped = 0
AND [name] = 'BSEG'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
INTO xzy
PRINT #SQL
EXEC sys.sp_executesql #SQL
I want to stored the results in a table. But I am getting the following error message:
Msg 194, Level 15, State 1, Line 2
A SELECT INTO statement cannot contain a SELECT statement that assigns values to a variable.
So my ultimate aim is to have a stored procedure/function which upon execution will give number of null values in each column in a table and the results will be stored in another result table.
Can you please check with this following changes-
Remove assigning part from your query and just use the simple select statement as-
SELECT '' +
STUFF((
...
--Note: Write the SQL in such way so that only SQL
--text from STUFF functions is returned. There is no
--requirement of assigning the text first to variable #SQL
Add INSERT before INTO key as below-
...
INSERT INTO xzy
...
If still no luck, please provide output of PRINT #SQL command with above 2 changes.
The "INTO xyz" should go above "FROM sys.objects o"?
EDIT
Try this
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = (
SELECT '
' +
STUFF((
SELECT ', ' + CASE WHEN c.is_nullable = 0 THEN '0' ELSE 'COUNT(*) - COUNT([' + c.name + '])' END + ' AS [' + c.name + ']'
FROM sys.columns c
WHERE c.[object_id] = o.[object_id]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, 'SELECT ''' + SCHEMA_NAME(o.[schema_id]) + '.' + o.name + ''' as TableName, COUNT(*) as Cnt, ') + '
INTO xzy
FROM [' + SCHEMA_NAME(o.[schema_id]) + '].[' + o.name + ']'
FROM sys.objects o
WHERE o.[type] = 'U'
AND o.is_ms_shipped = 0
AND [name] = 'BSEG'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
PRINT #SQL
EXEC sys.sp_executesql #SQL

Dynamic SQL Server query

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

A query to get the MAX LEN of every field in a SQL table

I've been trying to come up with a query that will list the name of every column in a table with it's max length.
This is in SQL Server 2012.
Any help is greatly appreciated.
You can use below query to get the the Actual and used length of the columns in a table
DECLARE #TSQL VARCHAR(MAX) = ''
DECLARE #TableName sysname = 't1'
SELECT #TSQL = #TSQL + 'SELECT ' + QUOTENAME(sc.name, '''') + ' AS ColumnName, ' + QUOTENAME(t.name, '''') + ' AS DataType, ' +
QUOTENAME(sc.max_length, '''') + ' AS ActualLength, MAX(DATALENGTH(' + QUOTENAME(sc.name) + ')) AS UsedLength FROM '+#TableName+ char(10) +' UNION '
FROM sys.columns sc
JOIN sys.types t on t.system_type_id = sc.system_type_id and t.name != 'sysname'
WHERE sc.OBJECT_ID = OBJECT_ID(#TableName)
SET #TSQL = LEFT(#TSQL, LEN(#TSQL)-6)
EXEC(#TSQL)
If you want know your table detail use information_schema.columns
select *
from information_schema.columns
where table_name = 'YourTableName'
If you want the lenght of a string field use LEN
select len(field1)
from YourTableName

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