sql dynamic variables are not executing? [duplicate] - sql

This question already has answers here:
Incorrect syntax near ']'.?
(3 answers)
Closed 8 years ago.
After trying to find out the problem myself doing some debugging
I have found that #cols and #cols2 variables are not bringing a result , I have PRINT
PRINT('INSERT INTO [' + #Destination_Database_Name + '].[dbo].[' + #tablename + '] (' + #cols2 + ']' + ') SELECT [' + #cols2 + ']' + ' FROM [' + #Source_Database_Name + '].[dbo].[' + #tablename + ']');
And the statement will not show the output all I get is
(1 row(s) affected)
(1 row(s) affected)
I am here2
c365online_script1
I am here3
tCompany
This is the section of the code which I think is the problem
Print 'I am here2'
SET IDENTITY_INSERT c365online_script1.dbo.tCompany ON
declare #cols2 varchar(max)
PRINT #cols2
select #cols2 = (Select Stuff((Select '],[' + C.COLUMN_NAME From INFORMATION_SCHEMA.COLUMNS As C Where C.TABLE_SCHEMA = T.TABLE_SCHEMA And C.TABLE_NAME = T.TABLE_NAME Order By C.ORDINAL_POSITION For Xml Path('')), 1, 2, '') As Columns From INFORMATION_SCHEMA.TABLES As T WHERE T.TABLE_NAME = #tablename)
PRINT('INSERT INTO [' + #Destination_Database_Name + '].[dbo].[' + #tablename + '] (' + #cols2 + ']' + ') SELECT [' + #cols2 + ']' + ' FROM [' + #Source_Database_Name + '].[dbo].[' + #tablename + ']');
PRINT #Destination_Database_Name
Print 'I am here3'
Print #tablename
END
I can post full code on request

Try
SET #cols2 = (Select....)
instead of
SELECT #cols2 = (Select....)

This is a NULL concatenation problem. Try initializing your variables as empty strings, like this, and see what you learn about the results of your query:
declare #tablename varchar(128) = '',
#Destination_Database_Name varchar(128) = '',
#Source_Database_Name varchar(128) = '';

Related

How to get sum of multiple rows in a table dynamically

I am trying to get the total sum from columns of a specific data type(money) for multiple tables in a database. Currently I am able to get the list of columns from specific tables but I am unable to get the sums from those columns.
This is what I have now
use database 1
Select + Column_Name
From information_schema.columns
Where TABLE_NAME = 'claimant'
and data_type = 'money'
The result looks something like below
table_name
column_name
table_1
column_a
table_1
column_b
table_1
column_c
what I would like
table_name
column_name
total_sum
table_1
column_a
66.20
table_1
column_b
300.50
table_1
column_c
5389.42
update for #Squirrel Here is the code I have but it's still giving me issues with truncation.
{
declare #sql nvarchar(max);
select #sql = 'with cte as (' + char(13)
+ 'select' + char(13)
+ string_agg(char(9) + quotename(column_name) + ' = sum(' + quotename(COLUMN_NAME) + ')', ',' + char(13)) + char(13)
+ 'from ' + max(quotename(table_name)) + char(13)
+ ')' + char(13)
+ 'select a.table_name, a.column_name, a.total_sum ' + char(13)
+ 'from cte ' + char(13)
+ 'cross apply (' + char(13)
+ char(9) + 'values' + char(13)
+ string_agg(char(9) + '(''' + table_name + ''',''' + column_name + ''',' + quotename(COLUMN_NAME) + ')', ',' + char(13)) + char(13)
+ ') a (table_name, column_name, total_sum)'
from information_schema.columns AS A
INNER JOIN EDL01.STAGING.TABLE_DETAILS B
ON A.TABLE_NAME = B.DEST_TABLE_NAME
where A.table_name = B.DEST_TABLE_NAME
and data_type = 'money'
print #sql
exec sp_executesql #sql
}
below is the create table
CREATE TABLE [staging].[TABLE_DETAILS](
[SOURCE_TABLE_NAME] [varchar](100) NULL,
[DEST_TABLE_NAME] [varchar](100) NULL,
[TYPE] [varchar](10) NULL,
[PRIORITY] [int] NULL,
[SOURCE_TABLE_DATABASE] [varchar](50) NULL,
[SOURCE_TABLE_SCHEMA] [varchar](50) NULL,
[DEST_TABLE_DATABASE] [varchar](50) NULL,
[DEST_TABLE_SCHEMA] [varchar](50) NULL
) ON [PRIMARY]
GO
Below is part of the results
select a.table_name, a.column_name, a.total_sum
from cte
cross apply (
values
('PAYMENT','BILLEDAMOUNT',[BILLEDAMOUNT]),
('PAYMENT','AMOUNT',[AMOUNT]),
('SIMS_PAYMENT','CHECKAMOUNT',[CHECKAMOUNT]),
('BILLREVIEWHEADER','JURISDICTIONAMOUNT1',[JURISDICTIONAMOUNT1]),
('BILLREVIEWHEADER','JURISDICTIONAMOUNT2',[JURISDICTIONAMOUNT2]),
('BILLREVIE
You need to form the query dynamically and then execute it using sp_executesql or exec()
Note : char(9) is tab, char(13) is carriage return. These are added to format the query so that it is readable when you print it out for verification.
declare #sql nvarchar(max);
select #sql = 'with cte as (' + char(13)
+ 'select' + char(13)
+ string_agg(char(9) + quotename(column_name) + ' = sum(' + quotename(column_name) + ')', ',' + char(13)) + char(13)
+ 'from ' + max(quotename(table_name)) + char(13)
+ ')' + char(13)
+ 'select a.table_name, a.column_name, a.total_sum ' + char(13)
+ 'from cte ' + char(13)
+ 'cross apply (' + char(13)
+ char(9) + 'values' + char(13)
+ string_agg(char(9) + '(''' + table_name + ''', ''' + column_name + ''',' + quotename(column_name) + ')', ',' + char(13)) + char(13)
+ ') a (table_name, column_name, total_sum)'
from information_schema.columns
where table_name = 'table_1'
and data_type = 'money'
print #sql
exec sp_executesql #sql
For your sample table, the generated dynamic query is
with cte as (
select
[column_a] = sum([column_a]),
[column_b] = sum([column_b]),
[column_c] = sum([column_c])
from [table_1]
)
select a.table_name, a.column_name, a.total_sum
from cte
cross apply (
values
('table_1', 'column_a',[column_a]),
('table_1', 'column_b',[column_b]),
('table_1', 'column_c',[column_c])
) a (table_name, column_name, total_sum)
EDIT
using a loop to iterate each table. Basically it execute above query for each of the table and insert the result into a temp table
see db<>fiddle demo
for earlier SQL Server version without string_agg(), use for xml path
select #sql = 'with cte as (' + char(13)
+ 'select' + char(13)
+ stuff
(
(
select ',' + quotename(COLUMN_NAME) + ' = sum(' + quotename(COLUMN_NAME) + ')'
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #table
and DATA_TYPE = 'money'
for xml path('')
),
1, 1, ''
) + char(13)
+ 'from ' + max(quotename(#table)) + char(13)
+ ')' + char(13)
+ 'select a.table_name, a.column_name, a.total_sum ' + char(13)
+ 'from cte ' + char(13)
+ 'cross apply (' + char(13)
+ char(9) + 'values' + char(13)
+ stuff
(
(
select ',' + '(''' + TABLE_NAME + ''', ''' + COLUMN_NAME + ''',' + quotename(COLUMN_NAME) + ')'
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #table
and DATA_TYPE = 'money'
for xml path('')
),
1, 1, ''
)
+ ') a (table_name, column_name, total_sum)' + char(13)

How to calculate data length in each column (in a single table) in SQL Server?

This code provide a possibility to sum a datalength in a single column:
select sum(datalength(column_1))
from my_table
This part provide me an information about columns in my_table
SELECT COLUMN_NAME,TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'my_table' AND TABLE_SCHEMA='my_schema'
and now i would like to add a column to second select result with sum of data length for each column, so i nedd a column like this:
sum(datalength(col_1))
sum(datalength(col_2))
.
.
.
sum(datalength(col_n))
Could you help me to prepare a proper select to achieve explained result?
EDIT: I need to count how many megabytes have elements in each column (in all rows):
1) if its int type column it is easy:
(size of int * number of rows)
2) when column is a varchar i would like to add size of each varchar in this column
If I understand you correctly and you want to " ... add a column to second select result (SELECT ... FROM INFORMATION_SCHEMA.COLUMNS ...) with sum of data length for each column ... ", a dynamic statement should be an option:
DECLARE #stm nvarchar(max) = N''
SELECT #stm = CONCAT(
#stm,
N'UNION ALL ',
N'SELECT ''',
COLUMN_NAME,
N''' AS [COLUMN_NAME], ''',
TABLE_SCHEMA,
N''' AS [TABLE_SCHEMA], ''',
TABLE_NAME,
N''' AS [TABLE_NAME], ',
CONVERT(nvarchar(max), ORDINAL_POSITION),
N' AS [ORDINAL_POSITION], ''',
DATA_TYPE,
N''' AS [DATA_TYPE], ',
N'(SELECT SUM(DATALENGTH(',
COLUMN_NAME,
N')) FROM ',
QUOTENAME(TABLE_SCHEMA),
N'.',
QUOTENAME(TABLE_NAME),
N') AS [DATA_LENGTH] '
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'YourTable' AND TABLE_SCHEMA = 'YourSchema'
SELECT #stm = STUFF(#stm, 1, 10, N'')
PRINT #stm
EXEC sp_executesql #stm
Is this what you're after?
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
DECLARE #Schema sysname = N'dbo', --Replace with appropriate Schema
#Table sysname = N'PerformanceTest'; --Replace with appropriate Table
SET #SQL = N'SELECT ' +
STUFF((SELECT N' +' + #CRLF +
N' ISNULL(SUM(DATALENGTH(' + QUOTENAME(COLUMN_NAME) + N')),0)'
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE C.TABLE_SCHEMA = #Schema
AND C.TABLE_NAME = #Table
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,11,N'') +N' AS DataLengthTotal' + #CRLF +
N'FROM ' + QUOTENAME(#Schema) + N'.' + QUOTENAME(#Table) + N';';
PRINT #SQL;
EXEC sp_executesql #SQL;
Seems the OP is not after a grant total, but total by column. This is can be easily be changed by changing the below
SELECT N' +' + #CRLF +
N' ISNULL(SUM(DATALENGTH(' + QUOTENAME(COLUMN_NAME) + N')),0)'
To the below:
SELECT N', ' + #CRLF +
N' ISNULL(SUM(DATALENGTH(' + QUOTENAME(COLUMN_NAME) + N')),0) AS ' + QUOTENAME(CONCAT(C.COLUMN_NAME,N'DataLength'))
And removing the alias after the STUFF expression.

How to pass column name as variable in dynamic query in SQL Server?

I have the below query, which gives the count of distinct values for each column. But I need to add a where clause condition in the query such as column1 = 'abc'. I am using this generic query so that I can use the same query with other tables also by passing the table name.
DECLARE #query VARCHAR(MAX)
SELECT #query =
'SELECT ' + SUBSTRING((SELECT ',' +'COUNT(DISTINCT(' + column_name + ')) AS ' + column_name + ' '
FROM information_schema.columns
WHERE table_name = 'table_name'
FOR XML PAT('')), 2, 100000) + 'FROM table_name'
--PRINT(#query)
EXECUTE(#query)
I tried passing it as below.
WHERE
table_name = 'table_name'
AND column1 = 'abc' -- compilation error, obviously
WHERE
table_name = 'table_name'
AND 'column1' = 'abc' -- not working, because it will compare the string values column1 and abc. and both are not equal
Then I just gave a try with the below query, but this is also not working, it's generating the wrong query when I try to print.
DECLARE #SQL NVARCHAR(MAX), #tname NVARCHAR(100),
#cname NVARCHAR(100), #acc_num NVARCHAR(50), #dp_code NVARCHAR(100)
SET #cname = 'column_name';
SET #acc_num = 'xyz';
SET #tname = 'table_name';
DECLARE #query VARCHAR(MAX);
SET #SQL = ''
;with cols as (
select Table_Schema, Table_Name, Column_Name, Row_Number() over(partition by Table_Schema, Table_Name
order by ORDINAL_POSITION) as RowNum
from INFORMATION_SCHEMA.COLUMNS
)
SELECT #query =
'SELECT ' + SUBSTRING((SELECT ',' +'COUNT(DISTINCT(' + QUOTENAME(column_name, '') + ')) As ' + QUOTENAME(column_name, '')+ ' '
+ ' WHERE ' + 'column_name' + ' = ''' + #acc_num + ''''
FROM cols
WHERE
table_name = #tname
for xml path('')),2,200000) + 'FROM' #tname
--for xml path('');
PRINT #query
--execute (#query)
This should be what you are after. There's a few comments in the SQL you need to pay attention to:
DECLARE #SQL nvarchar(max),
#tname sysname, --note the datatype change
#cname sysname, --note the datatype change
#acc_num nvarchar(50),
#dp_code nvarchar(100); --This is never used in your sample query
SET #cname = 'column_name';
SET #acc_num = 'xyz';
SET #tname = 'table_name';
SET #SQL = N'SELECT ' + NCHAR(13) + NCHAR(10) +
STUFF((SELECT N',' + NCHAR(13) + NCHAR(10) +
N' ' + N'COUNT DISTINCT(' + QUOTENAME(C.Column_Name) + N') AS ' + QUOTENAME(C.Column_Name)
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE C.Table_Name = #tname
ORDER BY C.ORDINAL_POSITION
FOR XML PATH(N'')),1,10,N'') + NCHAR(13) + NCHAR(10) +
N'FROM ' + QUOTENAME(#tname) + NCHAR(13) + NCHAR(10) +
N'WHERE ' + QUOTENAME(#cname) + N' = #Acc_Num;'
PRINT #SQL; --YOur debugging best friend
EXEC sp_executesql #SQL, N'#Acc_Num varchar(100)',#Acc_Num = #acc_num;
This parametrised the query instead, using sp_executesql, and nicely formats it for your PRINT statement.
If you don't understand then please do ask.
If you want a WHERE clause in the dynamic query, then you have to put it after the FROM clause in the dynamic query.
...
for xml path('')),2,200000) + ' FROM '+ #tname
+ ' WHERE ' + 'column_name' + ' = ''' + #acc_num + ''''

Modify columns using stored procedure in SQL Server

I wish to modify strings in several columns (for example all columns containing the 'sound' string), for example replacing ',' by '.'. Further to this post, I understand I have to use dynamic SQL. I created the following procedure:
USE [myDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[RemoveStringInColumn] (#colName varchar(50), #tableName varchar(50), #to_remove varchar(50), #to_add varchar(50))
AS
DECLARE #sql nvarchar(4000)
SET #sql = 'UPDATE ' + #tableName + ' SET ' + #colName + ' = REPLACE(' + #colName + ',' + #to_remove + ','+ #to_add + ');'
PRINT #sql
EXEC sp_executesql #sql
Which is called by:
EXEC dbo.RemoveStringInColumn 'COL_1', 'TABLE_1', ',', '.'
1) The problem is the #sql command does not contain the little hyphen arond the comma and the dot. How can I solve this?
2) In this post they use a SELECT command to fetch all column names. So far, I managed to fetch column names containing 'sound'.
select COLUMN_NAME AS my_cols
from INFORMATION_SCHEMA.COLUMNS
where table_name = 'TABLE_1' AND COLUMN_NAME LIKE '%sound%'
How can I put column names into a list and use a for loop to go through them calling the RemoveStringInColumn procedure?
Thanks
Just double the single quotes around #to_remove and #to_add
DECLARE #sql NVARCHAR(4000)
SET #sql = 'UPDATE ' + Quotename(#tableName) + ' SET ' + Quotename(#colName)
+ ' = REPLACE(' + Quotename(#colName) + ',''' + #to_remove + ''','''
+ #to_add + ''');'
PRINT #sql
EXEC Sp_executesql
#sql
Update : To do the replace for more than one column
DECLARE #sql NVARCHAR(4000),
#col_list VARCHAR(8000)= ''
SET #col_list = (SELECT ',' + Quotename(COLUMN_NAME) + ' = REPLACE('
+ Quotename(COLUMN_NAME) + ',''' + #to_remove
+ ''',''' + #to_add + ''')'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'TABLE_1'
AND COLUMN_NAME LIKE '%sound%'
FOR xml path(''))
SET #col_list = Stuff(#col_list, 1, 1, '')
SELECT #col_list
SET #sql = 'UPDATE ' + Quotename(#tableName) + ' SET '
+ #col_list
PRINT #sql
EXEC Sp_executesql
#sql

Dynamic SQL, Empty Variable, Formatting Issue?

I am using dynamic SQL to build out some statements. Here is a truncated example of a stored proc UpdateFOO. When I debug this stored procedure, the problem is the #SQL variable I am declaring always stay empty! It is supposed to fill with the query. I suspect it has something to do with how I am formatting this, but I cant spot if its a bad formatting error.
CREATE PROC [dbo].[UpdateFOO]
#TEST1 uniqueidentifier,
#TEST2 nvarchar(40),
#TEST3 nvarchar(50),
#TEST4 char(1),
#TEST5 nvarchar(20),
#TEST6 nvarchar(40),
#LINKED_SERVER_NAME nvarchar(max),
#DATABASE_NAME nvarchar(max)
AS
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRAN
DECLARE #SQL nvarchar(max)
SELECT #SQL = 'UPDATE [' + #LINKED_SERVER_NAME + '].[' + #DATABASE_NAME + '].[dbo].[SOME_TABLE]
SET [TEST1]=' + '''' + convert(nvarchar(36), #TEST1) + '''' +',
[TEST2]=' + '''' +#TEST2 + '''' +',
[TEST3]=' + '''' + #TEST3 + '''' +',
[TEST4]='+ '''' + #TEST4 + '''' +',
[TEST5]=' + '''' + #TEST5 + '''' +',
[TEST6]=' + '''' + #TEST6 + '''' +
' WHERE [TEST1] =' + '''' + convert(nvarchar(36), TEST1 )+ '''' +
+ 'SELECT [TEST1] FROM
[' + #LINKED_SERVER_NAME + '].[' + #DATABASE_NAME + '].[Rev].[SOME_TABLE]
WHERE [TEST1] =' + '''' + convert(nvarchar(36), TEST1 )+ '''' +''
PRINT LEN(#SQL)
EXEC (#SQL)
COMMIT
TIA Experts!
Here's how you use ISNULL. If the first value is null, it will return the 2nd value.
SELECT #SQL = 'UPDATE [' + #LINKED_SERVER_NAME + '].[' + #DATABASE_NAME + '].[dbo].[SOME_TABLE]
SET [TEST1]=' + '''' + convert(nvarchar(36), ISNULL(#TEST1, '')) + '''' +',
[TEST2]=' + '''' +ISNULL(#TEST2, '') + '''' +',
[TEST3]=' + '''' + ISNULL(#TEST3, '') + '''' +',
...
etc...
You should use parametrized query. Here's an example:
DECLARE #sql nvarchar(max), #paramlist nvarchar(max)
SELECT #sql= 'UPDATE Table
SET Col1 = #Value1,
Col2 = #Value2
WHERE (1 = 1)'
SELECT #paramlist = '#Value1 nvarchar (256), #Value2 nvarchar (256)'
EXEC sp_executesql #sql, #paramlist, #Value1, #Value2