Sql Server: How do you select a column only if it exists? - sql-server

I have a situation where I have many tables that are similar data structures but not exactly the same along these lines:
Table 1
A int not null
B int not null
C int not null
Table 2
A int not null
B int not null
What I want to end up with after doing some data transformation is:
Table 3
A int not null
B int not null
C int null
There are several more tables that have varied but similar schemas so I am working on a script that will import to Table 3 from a variety of tables that are missing some columns.
Based on this question I've tried a query like this:
SELECT A
,B
,case
when COL_LENGTH('t2', 'C') IS NULL
then NULL
ELSE C
end as C
FROM t2
But it throws an error of "Invalid column name C" even though it would be selecting null.
Is there another way to select a column only if it exists and NULL if it doesn't?

This script generate dynamic SQL for any table structure.
Query:
SET NOCOUNT ON
IF OBJECT_ID (N'dbo.Table_1') IS NOT NULL
DROP TABLE dbo.Table_1
IF OBJECT_ID (N'dbo.Table_2') IS NOT NULL
DROP TABLE dbo.Table_2
CREATE TABLE dbo.Table_1 (A INT NOT NULL, B INT NOT NULL, C INT NOT NULL)
CREATE TABLE dbo.Table_2 (A INT NOT NULL, B INT NOT NULL)
INSERT INTO dbo.Table_1 (A, B, C)
VALUES (1, 1, 1), (2, 2, 2)
INSERT INTO dbo.Table_2 (A, B)
VALUES (6, 1), (8, 2)
DECLARE #SQL NVARCHAR(2000)
;WITH cte AS
(
SELECT
column_name = '[' + c.name + ']'
, table_name = '[' + s.name + '].[' + o.name + ']'
FROM sys.columns c WITH (NOLOCK)
JOIN sys.objects o WITH (NOLOCK) ON c.[object_id] = o.[object_id]
JOIN sys.schemas s WITH (NOLOCK) ON o.[schema_id] = s.[schema_id]
WHERE o.name IN ('Table_1', 'Table_2')
AND s.name = 'dbo'
AND o.[type] = 'U'
), cols AS
(
SELECT DISTINCT column_name
FROM cte
), tbl AS
(
SELECT DISTINCT table_name
FROM cte
), rs AS
(
SELECT
tbl.table_name
, column_name = ISNULL(cte.column_name, cols.column_name + ' = NULL')
FROM cols
CROSS JOIN tbl
LEFT JOIN cte ON cols.column_name = cte.column_name AND cte.table_name = tbl.table_name
), rs2 AS (
SELECT uni = ' UNION ALL' + CHAR(13) + 'SELECT ' + STUFF((
SELECT ', ' + rs.column_name
FROM rs
WHERE tbl.table_name = rs.table_name
GROUP BY rs.column_name
ORDER BY rs.column_name
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') +
' FROM ' + table_name
FROM tbl
)
SELECT #SQL = 'SELECT
' + STUFF((
SELECT CHAR(13) + ', ' + cols.column_name
FROM cols
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, ' ')
+ '
FROM
(' + STUFF((
SELECT CHAR(10) + uni
FROM rs2
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 11, '') + CHAR(13) +
') t'
PRINT #SQL
EXECUTE sys.sp_executesql #SQL
Output:
SELECT
[A]
, [B]
, [C]
FROM
(
SELECT [A], [B], [C] FROM [dbo].[Table_1]
UNION ALL
SELECT [A], [B], [C] = NULL FROM [dbo].[Table_2]
) t
Results:
A B C
----------- ----------- -----------
1 1 1
2 2 2
6 1 NULL
8 2 NULL

Can you just use a UNION?
select A, B, C FROM Table1
UNION
Select A, B, null FROM Table2

Related

Validate decimal and integer values by looping through list of dynamic columns

I was tasked to validate the decimal and integer values of the columns from a list of tables. I have around 10-12 tables having different column names.
I created a lookup table which has the table name and the column names of decimal and integer as shown below. for example 'Pricedetails' and 'Itemdetails' tables have many columns of which only the ones mentioned in the Lookup table are required.
lkpTable
TableName
requiredcolumns
Pricedetails
sellingPrice,RetailPrice,Wholesaleprice
Itemdetails
ItemID,Itemprice
Pricedetails
Priceid
Mafdate
MafName
sellingPrice
RetailPrice
Wholesaleprice
01
2020-01-01
Americas
25.00
43.33
33.66
02
2020-01-01
Americas
43.45
22.55
11.11
03
2021-01-01
Asia
-23.00
-34.00
23.00
Itemdetails
ItemID
ItemPrice
Itemlocation
ItemManuf
01
45.11
Americas
SA
02
25.00
Americas
SA
03
35.67
Americas
SA
I have created a stored procedure with table name as input parameter, and able to pull the required column names of the tables (input parameter) from the lookup table and store that resultset into a table variable, below is the code.
declare #resultset Table
(
id INT identity(1,1),
tablename varchar(200) ,
ColumnNames varchar(max)
)
declare #tblname varchar(200),#sql varchar(max),#cols varchar(max),
INSERT INTO #resultset
select tablename,ColumnNames
from lkptable where tablename ='itemdetails'
select #cols = ColumnNames from #resultset;
select #tblname = TableName from #resultset;
----- Split the comma separated columnnames
Create table ##splitcols
(
ID int identity(1,1),
Name varchar(50)
)
Insert into ##splitcols
select value from string_split(#cols,',')
set #sql = 'select ' +#cols + ' from ' +#tblname
--print (#cols)
exec (#sql)
select * from ##splitcols
On executing the above code i get the below result sets, similarly what ever table name i provide i can get the required columns and its relevant data, now i am stuck at this point on how to validate whether the columns are decimal or int. I tried using while loop and cursor to pass the Name value from Resultset2, to the new dynamic query, somehow i don't find any way on how to validate.
ItemID
ItemPrice
01
45.11
02
25.00
03
35.67
Resultset2
ID
Name
01
ItemID
02
ItemPrice
you can validate in this way
insert into #splitcols values (1.1),(1.11)
select case when (t * 100)%10 = 0 then 1 else 0 end as valid from #splitcols
Similarly for number/integer
You can generate one giant UNION ALL query using dynamic SQL, then run it.
Each query would be of the form:
SELECT
TableName = 'SomeTable',
ColumnName,
IsInt
FROM (
SELECT
[Column1] = CASE WHEN COUNT(CASE WHEN ROUND([Column1], 0) <> [Column1] THEN 1 END) = 0 THEN 'All ints' ELSE 'Not All ints' END,
[Column2] = CASE WHEN COUNT(CASE WHEN ROUND([Column2], 0) <> [Column2] THEN 1 END) = 0 THEN 'All ints' ELSE 'Not All ints' END
FROM SomeTable
) t
UNPIVOT (
ColumnName FOR IsInt IN (
[Column1], [Column2]
)
) u
The script is as follows
DECLARE #sql nvarchar(max);
SELECT #sql = STRING_AGG('
SELECT
TableName = ' + QUOTENAME(t.name, '''') + ',
ColumnName,
IsInt
FROM (
SELECT ' + c.BeforePivotCoumns + '
FROM ' + QUOTENAME(t.name) + '
) t
UNPIVOT (
ColumnName FOR IsInt IN (
' + c.UnpivotColumns + '
)
) u
', '
UNION ALL '
)
FROM sys.tables t
JOIN lkpTable lkp ON lkp.TableName = t.name
CROSS APPLY (
SELECT
BeforePivotCoumns = STRING_AGG(CAST('
' + QUOTENAME(c.name) + ' = CASE WHEN COUNT(CASE WHEN ROUND(' + QUOTENAME(c.name) + ', 0) <> ' + QUOTENAME(c.name) + ' THEN 1 END) = 0 THEN ''All ints'' ELSE ''Not All ints'' END'
AS nvarchar(max)), ','),
UnpivotColumns = STRING_AGG(QUOTENAME(c.name), ', ')
FROM sys.columns c
JOIN STRING_SPLIT(lkp.requiredcolumns, ',') req ON req.value = c.name
WHERE c.object_id = t.object_id
) c;
PRINT #sql;
EXEC sp_executesql #sql;
db<>fiddle
If you are on an older version of SQL Server then you can't use STRING_AGG and instead you need to hack it with FOR XML and STUFF.
DECLARE #unionall nvarchar(100) = '
UNION ALL ';
DECLARE #sql nvarchar(max);
SET #sql = STUFF(
(SELECT #unionall + '
SELECT
TableName = ' + QUOTENAME(t.name, '''') + ',
ColumnName,
IsInt
FROM (
SELECT ' + STUFF(c1.BeforePivotCoumns.value('text()[1]','nvarchar(max)'), 1, 1, '') + '
FROM ' + QUOTENAME(t.name) + '
) t
UNPIVOT (
ColumnName FOR IsInt IN (
' + STUFF(c2.UnpivotColumns.value('text()[1]','nvarchar(max)'), 1, 1, '') + '
)
) u'
FROM sys.tables t
JOIN (
SELECT DISTINCT
lkp.TableName
FROM lkpTable lkp
) lkp ON lkp.TableName = t.name
CROSS APPLY (
SELECT
',
' + QUOTENAME(c.name) + ' = CASE WHEN COUNT(CASE WHEN ROUND(' + QUOTENAME(c.name) + ', 0) <> ' + QUOTENAME(c.name) + ' THEN 1 END) = 0 THEN ''All ints'' ELSE ''Not All ints'' END'
FROM lkpTable lkp2
CROSS APPLY STRING_SPLIT(lkp2.requiredcolumns, ',') req
JOIN sys.columns c ON req.value = c.name
WHERE c.object_id = t.object_id
AND lkp2.TableName = lkp.TableName
FOR XML PATH(''), TYPE
) c1(BeforePivotCoumns)
CROSS APPLY (
SELECT
', ' + QUOTENAME(c.name)
FROM lkpTable lkp2
CROSS APPLY STRING_SPLIT(lkp2.requiredcolumns, ',') req
JOIN sys.columns c ON req.value = c.name
WHERE c.object_id = t.object_id
AND lkp2.TableName = lkp.TableName
FOR XML PATH(''), TYPE
) c2(UnpivotColumns)
FOR XML PATH(''), TYPE
).value('text()[1]','nvarchar(max)'), 1, LEN(#unionall), '');
PRINT #sql;
EXEC sp_executesql #sql;
db<>fiddle

Inserting records from a table to another using dynamic SQL with conditions to convert data type

I have two tables whose structures as follows:
table_A
CREATE TABLE table_A
(
col_a varchar(100),
col_b bigint,
col_c datetime
)
table_b
--Note that columns are same--
CREATE TABLE table_B
(
col_a varchar(10),
col_b varchar(10),
col_c varchar(20)
)
Now I want to INSERT data into table_A from table_B with proper data type conversion.
Below is the SQL string:
INSERT INTO table_A(col_a,col_b,col_c)
SELECT CONVERT(varchar,col_a),CONVERT(INT,col_b),CONVERT(datetime,col_c) FROM table_B
So far so good.
Now I want generate the SQL dynamically with the help of INFORMATION_SCHEMA.COLUMNS.
For this I have followed the below steps:
Step 1:
Join the Information Schema for the above two tables viz table_A and table_B and store them in a #TempTable. Lets assume that #TempTable has an ID column that is IDENTITY(1,1) but that doesn't follow any sequence like 1,2,3...(Typically this happens in Synapse SQL)
INSERT INTO #TempTable
SELECT S.COLUMN_NAME AS Src_Col,
S.DATA_TYPE AS Src_dtype,
D.COLUMN_NAME AS Dest_Col,
D.DATA_TYPE AS Dest_dtype,
CASE WHEN S.DATA_TYPE NOT LIKE D.DATA_TYPE THEN
'CONVERT('+ '''' + D.DATA_TYPE + '''' + ',' + '''' + S.DATA_TYPE + '''' + ')'
ELSE S.DATA_TYPE AS Modified_Col
FROM INFORMATION_SCHEMA S
JOIN INFORMATION_SCHEMA.COLUMNS D
ON S.COLUMN_NAME = D.COLUMN_NAME AND S.TABLE_NAME = REPLACE(D.TABLE_NAME,'_B','_A')
Step 2:
Iterate over #TempTable to fetch the Modified_Col values
SET #Max_ID = (SELECT MAX(ID) FROM #TempTable);
SET #Min_ID = (SELECT MIN(ID) FROM #TempTable);
SET #ColToInsert = '';
SET #Dest_Col = '';
WHILE #Min_ID <= #Max_ID
BEGIN
SET #ColToInsert = (SELECT #ColToInsert + Modified_Col FROM #TempTable T WHERE T.ID = #Min_ID);
SET #Dest_Col = (SELECT #Dest_Col + Dest_Col FROM #TempTable T WHERE T.ID = #Min_ID);
SET #Min_ID = #Min_ID + 1;
END
Step 3:
Use that #ColToInsert in the below Dynamic SQL
SET #DySQL = 'INSERT INTO Table_A(' + #Dest_Col + ') SELECT ' + #ColToInsert + ' FROM table_B';
exec (#DySQL);
Now at this step 3 I am not getting the expected result. No data is getting inserted into table_A. I can understand that in the CASE statement I have to make some fixes so that convert... portion becomes a string. And I am not able to do so.
Any clue would be appreciated.
I don't understand why you need the temp table at all. You just need to aggregate using STRING_AGG.
You also need to quote the objects and columns using QUOTENAME, and you should use sys.columns etc rather than INFORMATION_SCHEMA, which is for compatibility only.
DECLARE #tableA sysname = 't';
DECLARE #tableB sysname = 's';
DECLARE #sql nvarchar(max) = (
SELECT CONCAT(
'INSERT INTO ',
QUOTENAME(#tableA),
'(',
STRING_AGG(CAST(QUOTENAME(cA.name) AS nvarchar(max)), ', '),
')
SELECT ',
STRING_AGG(
CASE WHEN cA.user_type_id <> cB.user_type_id THEN
CONCAT(
'CONVERT(',
typ.name,
CASE
WHEN typ.name IN ('varchar','nvarchar','char','nchar','varbinary','binary')
THEN CONCAT('(', CASE WHEN cA.max_length = -1 THEN 'max' END, NULLIF(cA.max_length, -1), ')')
WHEN typ.name IN ('datetime2','datetimeoffset','time','float','real')
THEN CONCAT('(', cA.scale, ')')
WHEN typ.name IN ('float','real')
THEN CONCAT('(', cA.precision, ')')
WHEN typ.name IN ('decimal','numeric')
THEN CONCAT('(', cA.precision, ',', cA.scale, ')')
END,
', ',
CAST(QUOTENAME(cB.name) AS nvarchar(max)),
')'
)
ELSE
CAST(QUOTENAME(cB.name) AS nvarchar(max))
END
, ', '),
'
FROM ',
QUOTENAME(#tableB)
)
FROM sys.columns cA
JOIN sys.tables tA ON ta.object_id = cA.object_id AND tA.name = #tableA
JOIN sys.types typ ON typ.user_type_id = cA.user_type_id
JOIN sys.columns cB ON cB.name = cA.name
JOIN sys.tables tB ON tB.object_id = cB.object_id AND tB.name = #tableB
);
PRINT #sql; -- your friend
EXEC sp_executesql #sql;
db<>fiddle

How to combine rows dynamically

I have a table with many columns (even number of columns). Now I need to combine the second column and third column, the forth and fifth column, sixth and seventh column....etc. How to achieve this?
I tried static one, but what about dynamic one. Assume that there are 100 or more columns.
create table tb11 ( [id] int,[A] varchar(20),[B] varchar(20),
[C] varchar(20),[D] varchar(20))
insert into tb11 values
(1,'a','b','c','d'),
(2,'e','f','g','h'),
(3,'i','j','k','l')
select * from tb11
/*
id A B C D
---- --- ---- --- ----
1 a b c d
2 e f g h
3 i j k l
*/
select id,
[A] + [B] as '1' ,
[C] + [D] as '2'
from tb11
/*output with 3 columns
id 1 2
---- ----- ------
1 ab cd
2 ef gh
3 ij kl
*/
Try this
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = (
SELECT '
' +
STUFF((
SELECT ', ' + c.name + ' + ' + c2.name + ' AS [' + c.name + c2.name +']'
FROM sys.columns c
INNER JOIN sys.columns c2 ON c2.object_id = c.object_id
AND c2.column_id = c.column_id + 1
WHERE c.[object_id] = o.[object_id]
AND c.column_id > 1
AND c.column_id % 2 = 0
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, 'SELECT id, ') + '
FROM [' + SCHEMA_NAME(o.[schema_id]) + '].[' + o.name + ']' -- select *
FROM sys.objects o
WHERE o.[type] = 'U'
AND o.is_ms_shipped = 0
AND [name] = 'tb11'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
PRINT #SQL
EXEC sys.sp_executesql #SQL
You may use schema of tables to get the list of columns and create dynamic columns name from them.
Similarly by using that schema only create you table script for new structure.
Try this:
GO
;with cte as (
select ORDINAL_POSITION as slno, COLUMN_NAME from information_schema.columns where table_name = 'tb11'
)
select * into #tab_col from cte
declare #max int
set #max = (select Count(*) -1 from #tab_col)
declare #loop int
set #loop = 0
create table newtab (
id int )
declare #columns nvarchar(max) = ''
declare #values nvarchar(max) = ''
while(#Loop <= (#Max/2))
Begin
declare #Col1 varchar(100)
declare #Col2 varchar(100)
set #Col1 = (select Column_name from #tab_col where slno = #Loop+2)
set #Col2 = (select Column_name from #tab_col where slno = #Loop+3)
declare #alter nvarchar(max)
set #alter = ' Alter table newtab add [' + cast(((#Loop/2)+1) as varchar(100)) + '] nvarchar(max) '
set #columns = #columns + ',[' + (select cast(((#Loop/2)+1) as varchar(100))) + ']'
set #values = #values + ',''' + #Col1 + #Col2 + ''''
exec sp_executesql #alter
set #loop = #loop + 2
End
set #values =( select substring( #values, 2, len(#values)))
select #values
set #columns =( select substring( #columns, 2, len(#columns)))
select #columns
declare #altertab nvarchar(max)
set #altertab = ' insert into newtab ( id, ' + #columns + ' ) values ( 1, ' + #values + ' )'
exec sp_executesql #altertab
drop table newtab
Drop table #tab_col
GO
This will not exactly give you your answer but you'll get some idea.

Convert XML output to varchar

I have this query
select
',' + CONVERT(VARCHAR,FileID)
from
[RETRY_INPUT_JSON] A
inner join
RETRY_JSON_STATUS B on JsonStatus = StatusID
where
RetryStatus = 'FAILED'
Union
select
',' + CONVERT(VARCHAR,FileID)
from
[RETRY_INPUT_JSON] A
inner join
RETRY_JSON_STATUS B on SendESBStatus = StatusID
where
RetryStatus In ('FAILED', 'Success')
order by
',' + CONVERT(VARCHAR,FileID)
FOR XML PATH('')
This returns this output:
I want to convert it to varchar.
For that I tried :
DECLARE #FILEID AS VARCHAR(MAX)
SET #FILEID =(SELECT STUFF
(
(
select ',' + CONVERT(VARCHAR,FileID) from [RETRY_INPUT_JSON] A inner join RETRY_JSON_STATUS B
on JsonStatus=StatusID
where RetryStatus='FAILED'
Union
select ',' + CONVERT(VARCHAR,FileID) from [RETRY_INPUT_JSON] A inner join RETRY_JSON_STATUS B
on SendESBStatus=StatusID
where RetryStatus In ('FAILED','Success')
ORDER BY ',' + CONVERT(VARCHAR,FileID) FOR XML PATH('')
),
1, 1, ''
) )
print #FILEID
But I get an error :
Msg 1086, Level 15, State 1, Line 18
The FOR XML clause is invalid in views, inline functions, derived tables, and subqueries when they contain a set operator. To work around, wrap the SELECT containing a set operator using derived table syntax and apply FOR XML on top of it.
Check This.
DECLARE #FILEID AS VARCHAR(MAX)
DECLARE #xml_var XML
SET #xml_var = ( select ',' + CONVERT(VARCHAR,A)
from
(
select
CONVERT(VARCHAR,FileID) A
from
[RETRY_INPUT_JSON] A
inner join
RETRY_JSON_STATUS B on JsonStatus = StatusID
where
RetryStatus = 'FAILED'
Union
select
CONVERT(VARCHAR,FileID) A
from
[RETRY_INPUT_JSON] A
inner join
RETRY_JSON_STATUS B on SendESBStatus = StatusID
where
RetryStatus In ('FAILED', 'Success')
)A
order by A
FOR XML PATH('')
)
select #FILEID = CONVERT(VARCHAR(MAX), #xml_var)
SELECT #FILEID
pRINT #FILEID

Get a list of all columns that do not have only NULL values in SQL Server

I NEVER do complicated stuff in SQL - until now...
I have a database with over 2000 tables, each table has about 200 columns.
I need to get a list of all the columns in one of those tables that are populated at least 1 time.
I can get a list of all the columns like this:
SELECT [name] AS [Column name]
FROM syscolumns with (nolock)
WHERE id = (SELECT id FROM sysobjects where name like 'DOCSDB_TDCCINS')
But I need only the columns that are populated 1 or more times.
Any help would be appreciated.
Here is how I would do it, first run this:
SELECT 'SELECT '''+syscolumns.name+''' FROM '+sysobjects.name+' HAVING COUNT('+syscolumns.name+') > 0'
FROM syscolumns with (nolock)
JOIN sysobjects with (nolock) ON syscolumns.id = sysobjects.id
WHERE syscolumns.id = (SELECT id FROM sysobjects where name like 'Email')
Copy all the select statements and run them.
This will give you a list of the column names without nulls.
(nb I did not test because I don't have an SQL server available right now, so I could have a typo)
It may be also be useful to count the non-null instances, obviously 0 or not 0 was your initial question, and counting the instances versus exists not/exists will be slower.
select 'union select ''' + Column_Name + ''',count(*)'
+ ' from ' + table_name
+ ' where ' + column_name + ' is not null'
from
(
select * from information_schema.columns with (nolock)
where Is_Nullable = 'YES'
AND Table_Name like 'DOCSDB_TDCCINS'
) DD
Then remove the superfluous leading 'union' and run the query
A different idea is to create a dynamic unpivot for every table.
Declare #q NVarchar(MAX) = NULL
;With D AS (
SELECT TABLE_SCHEMA
, TABLE_NAME
, STUFF((SELECT ', ' + QUOTENAME(ci.COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS ci
WHERE (ci.TABLE_NAME = c.TABLE_NAME)
AND (ci.TABLE_SCHEMA = c.TABLE_SCHEMA)
FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)')
,1,2,'') AS _Cols
, STUFF((SELECT ', Count(' + QUOTENAME(ci.COLUMN_NAME) + ') '
+ QUOTENAME(ci.COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS ci
WHERE (ci.TABLE_NAME = c.TABLE_NAME)
AND (ci.TABLE_SCHEMA = c.TABLE_SCHEMA)
FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)')
,1,2,'') AS _ColsCount
FROM INFORMATION_SCHEMA.COLUMNS c
GROUP BY TABLE_SCHEMA, TABLE_NAME
)
SELECT #q = COALESCE(#q + ' UNION ALL ', '') + '
SELECT ''' + TABLE_SCHEMA + ''' _Schema, ''' + TABLE_NAME + ''' _Table, _Column
FROM (SELECT ' + _ColsCount + ' from ' + TABLE_SCHEMA + '.' + TABLE_NAME + ') x
UNPIVOT
(_Count FOR _Column IN (' + _Cols + ')) u
WHERE _Count > 0'
FROM D
exec sp_executesql #q
In the CTE _Cols returns the comma separated quoted name of the columns of the table, while _ColsCount returns the same list with the COUNT function, for example for a table of mine a row of D is
TABLE_SCHEMA | TABLE_NAME | _Cols | _ColsCount
------------- ----------------- ------------------------------ -----------------------------------------------------------------------------
dbo | AnnualInterests | [Product_ID], [Rate], [Term] | Count([Product_ID]) [Product_ID], Count([Rate]) [Rate], Count([Term]) [Term]
while the main query trasform this line in the UNPIVOT to return the columns in rows
SELECT 'dbo' _Schema, 'AnnualInterests' _Table, _Column
FROM (SELECT Count([Product_ID]) [Product_ID], Count([Term]) [Term]
, Count([Rate]) [Rate] from dbo.AnnualInterests) x
UNPIVOT
(_Count FOR _Column IN ([Product_ID], [Term], [Rate])
WHERE _Count > 0
using the string variable concatenation and sp_executesql to run the string complete the script.
Hope you can achieve this by a simple alteration on your code like
SELECT [name] AS [Column name]
FROM syscolumns with (nolock)
WHERE id = (SELECT id FROM sysobjects where name like 'DOCSDB_TDCCINS')
and (select count(*) from DOCSDB_TDCCINS)>0

Resources