How to sum dynamic columns in SQL Server? - sql

Assume I have a table with 3 columns. Is there possible sum of each column without specifying name of the column?
And is there possible create a table with dynamic name of the column, and then sum of each column?
UPDATE: Here is my sample.
First, I do a query and get the result like this:
---------
| Col |
---------
| DLX |
| SUI |
| PRE |
| TWQ |
---------
The number of row maybe different each time, and then I create a table with columns from rows above like this:
---------------------------------
| DLX | SUI | PRE | TWQ |
---------------------------------
And then I fill data the table from another table. After all, I sum each column. Because I will not know exactly name of the column, so I need sum of each column without specifying name of the column.

If your table is small (i.e. 10 columns) I would just do it manually. But if it's like 20+ columns, I would employ some dynamic sql.
To answer your question directly, yes, you can dynamically create a table with dynamic column names using dynamic sql.
Here's one way to do it:
You can use INFORMATION_SCHEMA.COLUMNS View to get all the column names and put them in a temp table.
SELECT NAME INTO #COLUMNS
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = YourTable
Next, create a temp table to store your sums.
CREATE TABLE #SUMS (
COLUMN_NAME NVARCHAR(MAX),
SUM_COLUMN INT
)
You can then use dynamic sql and a loop to sum each column.
WHILE EXISTS(SELECT TOP 1 * FROM #COLUMNS)
BEGIN
DECLARE #COLUMN NVARCHAR(MAX) = (SELECT TOP 1 * FROM #COLUMNS)
DECLARE #DYNAMICSQL NVARCHAR(MAX) = N'SELECT ' + #COLUMN + ' AS COLUMN_NAME, SUM(' + #COLUMN + ') FROM YourTable'
INSERT INTO #SUMS
EXEC SP_EXECUTESQL #DYNAMICSQL
DELETE FROM #COLUMNS
WHERE NAME = #COLUMN
END
Then you would need another dynamic sql and loop to loop through the new table and create a temp table with the column names you want using the sum values and the table name you want.
You should be able to do that using the code already supplied above.

At first I thought about pivoting but then came up with this:
DECLARE #Table TABLE ( --Table to generate input you need
[Col] nvarchar(3)
)
DECLARE #query nvarchar(max) -- a variable that will store dynamic SQL query
DECLARE #table_name nvarchar(max) = 'Temp' --A name of table to create
INSERT INTO #Table VALUES
('DLX'),
('SUI'),
('PRE'),
('TWQ')
SELECT #query = ISNULL(#query,'CREATE '+#table_name+' TABLE (') + QUOTENAME([Col]) + ' nvarchar(max),'
FROM #Table
SELECT #query = SUBSTRING(#query,1,LEN(#query)-1) +')'
EXEC sp_executesql #query
That will execute a query (PRINT #query to see the result below):
CREATE Temp TABLE ([DLX] nvarchar(max),[SUI] nvarchar(max),[PRE] nvarchar(max),[TWQ] nvarchar(max))
Which will create a temp table for you.
Then you can insert in that table in the pretty same way.

Related

Select columns whose name is not present in another table

Is there a way to only select the columns whose names are not present on another table? For example
Table A Column B
ID | Name | Address Address
-----------------------
1 | Daniel | dummy
In this example my select statement should be like this:
select ID, Name from Column A
I've seen people talking about dynamic SQL but I can't find a decent example to solve my issue, any help is much appreciated.
Here is a version of the way you would do this using dynamic SQL:
declare #cols varchar(max);
set #cols = NULL;
select #cols = coalesce(#cols + ', ' + column_name, column_name)
from information_schema.columns ca
where ca.table_name = 'A' and
ca.column_name not in (select cb.column_name
from information_schema.columns cb
where cb.table_name = 'B'
);
declare #sql varchar(max);
set #sql = 'select [cols] from A';
set #sql = replace(#sql, '[cols]', #cols);
exec sp_executesql #sql;
This is a bit simplified to show how the information_schema tables can be sued. It will work in many circumstances, but is not maximally general:
It doesn't take schema name into account.
It assumes all names are simple ASCII.
It does not escape the column names (assuming the names do not need to be escaped).
Select the other table in the WHERE clause.
SELECT ID, NAME
FROM ColumnA
WHERE NAME NOT IN (SELECT NAME FROM COLUMNB)

isnull for dynamically Generated column

I am getting temp table with dynamically generated columns let say it is columns A,B,C,D etc from other source.
Now in my hand I have temp table with column generated. I had to write stored procedure with the use of temp table.
So my stored procedure is like
create proc someproc()
as
begin
Insert into #searchtable
select isnull(#temp.*,0.00)
End
Now #searchresult is table created by me to store temp table columns. The problem arises when I want to check isnull for #tempdb columns. Because from source it comes it may be 3 columns, again next time it may be 4 columns. It changes.
Since it is dynamically generated I cannot use each column name and use like below:
isnull(column1,0.00)
isnull(column2,0.00)
I had to use all column generated and check if value is empty use 0.00
I tried this below but not working:
isnull(##temp.*,0.00),
Try with Dynamic code by fetching the column name for your dynamic table from [database].NFORMATION_SCHEMA.COLUMNS
--Get the Column Names for the your dynamic table and add the ISNULL Check:
DECLARE #COLS VARCHAR(MAX) = ''
SELECT #COLS = #COLS + ', ISNULL(' + COLUMN_NAME + ', 0.00) AS ' + COLUMN_NAME
FROM tempdb.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME LIKE '#temp[_]%' -- Dynamic Table (here, Temporary table)
DECLARE #COLNAMES VARCHAR(MAX) = STUFF(#COLS, 1, 1, '')
--Build your Insert Command:
DECLARE #cmd VARCHAR(MAX) = '
INSERT INTO #temp1
SELECT ' + #COLNAMES + ' FROM #temp'
--Execute:
EXEC (#cmd)
Hope, I understood your comment right:
CREATE PROCEDURE someproc
AS
IF OBJECT_ID(N'#searchtable') IS NOT NULL DROP TABLE #searchtable
IF OBJECT_ID(N'#temp') IS NOT NULL
BEGIN
DECLARE #sql nvarchar(max),
#cols nvarchar(max)
SELECT #cols = (
SELECT ',COALESCE('+QUOTENAME([name])+',0.00) as '+QUOTENAME([name])
FROM sys.columns
WHERE [object_id] = OBJECT_ID(N'#temp')
FOR XML PATH('')
)
SELECT #sql = N'SELECT '+STUFF(#cols,1,1,'')+' INTO #searchtable FROM #temp'
EXEC sp_executesql #sql
END
This SP checks if #temp table exists. If exists then it takes all column names from sys.columns table and we make a string like ,COALESCE([Column1],0.00) as [Column1], etc. Then we make a dynamic SQL query like:
SELECT COALESCE([Column1],0.00) as [Column1] INTO #searchtable FROM #temp
And execute it. This query result will be stored in #searchtable.
Notes: Use COALESCE instead of ISNULL, and sp_executesql instead of direct exec. It is a good practice.

Execute a query returned from a scalar function

I have a scalar function that returns a query. The scalar function must return the query itself and not its' results, since it uses dynamic SQL and the variables are used as column names and table names.
So, I have something like this:
SELECT t.id,
dbo.queryToExecute(t.id, t.ColumnToFetch, t.TableToFetchFrom) QueryToExecute
FROM Table t
Which returns
| ID | QueryToExecute
| 1 | SELECT ColumnName1 FROM Table1 WHERE id = 1
| 2 | SELECT ColumnName2 FROM Table2 WHERE id = 2
While "QueryToExecute" returns a single value.
I want to do something like:
SELECT t.id,
EXEC(dbo.queryToExecute(t.id, t.ColumnToFetch, t.TableToFetchFrom)) ExecutedQuery
FROM Table t
So the result set will be:
| ID | ExecutedQuery
| 1 | Jacob
| 2 | Sarah
How can I do that?
I already have a stored procedure that gets the job done when I need to run individually, but I wanted to have the same thing on a scalar function in order to be able to embed the sub-results in more complex queries.
Thanks!
You need to use dynamic SQL:
DECALRE #sql nvarchar(max)
SELECT #sql = COALESCE(#sql,'') +
REPLACE(
dbo.queryToExecute(t.id, t.ColumnToFetch, t.TableToFetchFrom),
'SELECT ',
'SELECT '+ CAST(t.ID as nvarchar(max) +' as ID, '
) +' UNION ALL '
FROM Table t
SELECT #sql = LEFT(#sql,LEN(#sql)-LEN('UNION ALL '))
EXEC sp_executesql #sql
This will get all query's in one batch and execute it
You need to take your dynamic sql one step deeper, and include the id number.
This script will generate a select statement for each row, and union them all together. You then run this whole select in one go to get your output.
--set up a string variable to store your query
declare #tsql nvarchar(max);
set #tsql = '';
-- populate it with the string statements
select #tsql = #tsql + 'select ' + cast(t.id as nvarchar(10)) + ' as id , (' + dbo.queryToExecute(t.id, t.ColumnToFetch, t.TableToFetchFrom) + ') QueryToExecute union ' from Table t
--chop off the final "union"
select #tsql = left (#tsql,len(#tsql)-7);
--and run
EXEC sp_executesql #tsql

Create table with column names from another tables column data

I have table with a single column like this:
---------
| col |
---------
| A |
| B |
| C |
---------
I want to create a new table with the following column names like this:
-------------------
| A | B | C |
-------------------
Any suggestions? Thanks a lot.
One way is to use dynamic sql.
Assuming data type int for all columns, you can do something like this:
Create and populate sample table (Please save us this step in your future questions):
DECLARE #T table
(
col char(1)
)
INSERT INTO #T VALUES ('a'), ('b'), ('c')
Build the dynamic sql:
DECLARE #Sql nvarchar(max) = 'CREATE TABLE YourNewTableName ('
SELECT #Sql = #Sql + col +' int,'
FROM #T
SET #Sql = LEFT(#Sql, LEN(#Sql) - 1) +');'
--Print #sql
Execute it (You will probably want to print it before to make sure it's correct):
EXEC(#Sql)

SQL - Dynamically add columns to temp table based on value

I need to perform some dynamic operation temp table based on some condition.
(add columns based of number and update only those columns)
I have one one master table which contains unit information -
E.G.
ID UNIT
1 kg
2 cm
3 mm
Here, number of rows can vary. It can contain 3 rows or 4 rows or 2 rows.
Now i want create some columns in my temp table based on this.
E.G.
if master table has 2 values then #temp should contain 2 columns as unit1 and unit2.
if 3 values then unit1, unit2 and unit3.
Is it possible? Or do i need to create max number of columns directly in temp table?
Thanks
You have to use Dynamic PIVOT and GLOBAL TEMP TABLE in following:
IF OBJECT_ID('tempdb..#t') IS NOT NULL
DROP TABLE #t
GO
CREATE table #t
(id varchar(max),unit varchar(max))
insert into #t (id,unit)values
(1,'kg'),
(2,'cm'),
(3,'mm'),
(4,'m')
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ',', '') + N'[' + cast(tbl.id as varchar(max)) + ']'
FROM (
SELECT DISTINCT id
FROM #t
) AS tbl
SELECT #statement = 'select *
INTO ##temp
from (
SELECT id,[unit]
FROM #t
) as s
PIVOT
(max(unit) FOR id in(' + #columns + ')) as pvt
'
EXEC sp_executesql #statement = #statement
SELECT * FROM ##temp
DROP TABLE ##temp