How to get sum of multiple rows in a table dynamically - sql

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)

Related

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.

Turn dynamic SELECT query into UPDATE stored procedure SQL

I am rather new to this and I am having a hard time into converting the below SQL query into an UPDATE statement for a stored procedure.
SELECT 'select'+
stuff((
SELECT ',' + 'dbo.' + Function_Name + '(' + Parameters_List + ')' FROM
[SPECIFIC_DATABASE]..Specific_table c WHERE c.Table_Name = t.Table_Name FOR
XML PATH('')),1,1,'')
+' from [' + Database_Name +'].[dbo].['+Table_Name+'] '
+ 'Where Audit_ID>' + CAST(#Audit_ID as nvarchar(100))
As 'Specific Queries'
FROM (SELECT Distinct Database_Name, Table_Name FROM [SPECIFIC_DATABASE]..Specific_table) t
The UPDATE query should be something like
UPDATE Table_name
SET Column_name = Function_Name(Parameters_List)
WHERE Audit_id >= #Audit_ID
FROM [SPECIFIC_DATABASE]..Specific_table
Any suggestions and guidelines on this would be much appreciated!
I think this should give you what you want, but I don't see any any reference to a Column_Name, so I'm assuming you will hardcode that.
select 'UPDATE tbl' + stuff((
select ' set Column_Name = ' + 'dbo.' + Function_Name + '(' + Parameters_List + ')'
from [SPECIFIC_DATABASE]..Specific_table c
where c.Table_Name = t.Table_Name
for xml PATH('')
), 1, 1, '')
+ ' from [' + Database_Name + '].[dbo].[' + Table_Name + '] tbl'
+ 'Where Audit_ID>'
+ CAST(#Audit_ID as nvarchar(100)) as 'Specific Queries'
from (
select distinct Database_Name, Table_Name
from [SPECIFIC_DATABASE]..Specific_table
) t
If the answer's not right then it might be helpful if you post what is the current output of your first query and maybe some more details as to what are the contents of the table called "Specific_table".

How to display the output and also save it in global temp table in ms-sql

Usually when we use select statement it displays the output, but when insert into is used,stores the result into temp table.i want to do both.Display result and store in temp table as well in dynamic sql.
IF #DisplayInSelect IS NOT NULL
SET #DisplayInSelect = ','+#DisplayInSelect
SET #SQL = 'IF EXISTS (SELECT DISTINCT a.'+#column_name+' FROM ['+#TableName+'] a where '+#FullCondition+' )'+
'SELECT DISTINCT ''Error at column: '+#Column_name+''' as [Error Records if found any are shown below],'''+ISNULL(#CustomErrorMessage,'ERROR')+''''+ISNULL(#DisplayInSELECT,'')+', a.'+#column_name+',* FROM ['+#TableName+'] a where '+#FullCondition+'
INSERT INTO ##error_check(SELECT DISTINCT ''Error at column: '+#Column_name+''' as [Error Records if found any are shown below],'''+ISNULL(#CustomErrorMessage,'ERROR')+''''+ISNULL(#DisplayInSELECT,'')+', a.'+#column_name+', *FROM ['+#TableName+'] a where '+#FullCondition+');
PRINT('IQR1 sql is'+#SQL)
EXEC(#SQL)
END
You have to use insert into table along with Exec. Try like this,
IF #DisplayInSelect IS NOT NULL
SET #DisplayInSelect = ',' + #DisplayInSelect
SET #SQL = 'IF EXISTS (SELECT DISTINCT a.' + #column_name + ' FROM [' + #TableName + '] a where ' + #FullCondition + ' )' + 'SELECT DISTINCT ''Error at column: ' + #Column_name + ''' as [Error Records if found any are shown below],''' + ISNULL(#CustomErrorMessage, 'ERROR') + '''' + ISNULL(#DisplayInSELECT, '') + ', a.' + #column_name + ',* FROM [' + #TableName + '] a where ' + #FullCondition + '
SELECT DISTINCT ''Error at column: ' + #Column_name + ''' as [Error Records if found any are shown below],''' + ISNULL(#CustomErrorMessage, 'ERROR') + '''' + ISNULL(#DisplayInSELECT, '') + ', a.' + #column_name + ', *FROM [' + #TableName + '] a where ' + #FullCondition + ';'
--To Save
INSERT INTO ##error_check
EXEC (#SQL)
PRINT (' IQR1 sql IS ' + #SQL)
--To Display
EXEC (#SQL)

sql dynamic variables are not executing? [duplicate]

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

Transpose rows to columns - SQL2005

I have the following result set
Status Wage --Columns Names (Table)
====== =====
Employed 10,000
What I need is:
Key Value DataType
=== ===== ========
Status Employed column data type e.g varchar
Wage 10,000 decimal(18,2)
How can this be achieved using TSQL in SQL 2005
What you are looking for is PIVOT.
http://msdn.microsoft.com/en-us/library/ms177410(v=SQL.90).aspx
It can be done using INFORMATION_SCHEMA, UNPIVOT, CAST and EXEC. Here's a working solution.
CREATE TABLE #Data ([Status] int, [Wage] varchar(100), [Tax] decimal(10,3), BigText nvarchar(max))
INSERT #Data VALUES (7, '$12m', 123123.22, 'small island')
SELECT ORDINAL_POSITION, COLUMN_NAME, DATA_TYPE
+ CASE WHEN CHARACTER_MAXIMUM_LENGTH > 0 THEN '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS nvarchar(10)) + ')' WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN '(max)' ELSE '' END
+ CASE WHEN DATA_TYPE IN ('numeric', 'decimal') AND NUMERIC_PRECISION > 0 THEN '(' + CAST(NUMERIC_PRECISION AS nvarchar(10))
+ CASE WHEN NUMERIC_SCALE > 0 THEN ',' + CAST(NUMERIC_SCALE AS NVARCHAR(10)) ELSE '' END
+ ')' ELSE '' END DATA_TYPE
INTO #Columns
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE C.TABLE_NAME LIKE '#Data%'
ORDER BY C.ORDINAL_POSITION
DECLARE #selectList nvarchar(max), #columnNames nvarchar(max)
SELECT #selectList = ISNULL(#selectList + ',', '') + 'CAST(' + QUOTENAME(COLUMN_NAME) + ' AS nvarchar(max)) ' + QUOTENAME(COLUMN_NAME),
#columnNames = ISNULL(#columnNames + ',', '') + QUOTENAME(COLUMN_NAME)
FROM #Columns
DECLARE #unpivot nvarchar(max)
SET #unpivot = '
SELECT b.Column_Name, b.DataValue, c.Data_Type
FROM
(
SELECT ' + #selectList + ' FROM #Data
) a
UNPIVOT (DataValue FOR Column_Name IN (' + #columnNames + ')) b
JOIN #Columns c ON c.Column_Name = b.Column_Name
'
EXEC (#unpivot)