Dynamic Database in SubQuery - sql

SELECT
email, password,GP_employee_id, company,
(select distinct CHEKNMBR from [BSL].[dbo].[UPR30300] WHERE EMPLOYID = GP_employee_id and CHEKDATE > GETDATE() - 20 ) as slip_number,
(select distinct CONVERT(date , CHEKDATE) from [BSL].[dbo].[UPR30300] WHERE EMPLOYID = GP_employee_id and CHEKDATE > GETDATE() - 20 ) as slip_number
FROM [payslips].[dbo].[myapp_user]
I would like [BSL] to be dynamic. The value would depend on the company field of the main query. So I want something like this [company].[dbo].[UPR30300]

You can do one big dynamic UNION ALL query
DECLARE #unioned nvarchar(max) = (
SELECT STRING_AGG(CAST(
'
SELECT *, company = ' + QUOTENAME(company, '''') + '
FROM ' + QUOTENAME(company) + '.[dbo].[UPR30300]
WHERE CHEKDATE > DATEADD(day, -20, GETDATE())
'
AS nvarchar(max)), 'UNION ALL')
FROM (
SELECT DISTINCT company
FROM [payslips].[dbo].[myapp_user]
) au
);
DECLARE #sql nvarchar(max) = '
SELECT
au.email,
au.password,
au.GP_employee_id,
au.company,
slip_number = u.CHEKNMBR,
slip_number2 = CONVERT(date, u.CHEKDATE)
FROM [payslips].[dbo].[myapp_user] au
LEFT JOIN (
' + #unioned + '
) u ON u.company = au.company
AND u.EMPLOYID = au.GP_employee_id;
';
PRINT #sql; -- for testing
EXEC sp_executesql #sql;

DECLARE #sql VARCHAR(1000);
DECLARE #company VARCHAR(50);
DROP TABLE IF EXISTS #myapp_user;
CREATE TABLE #myapp_user
(
email VARCHAR(256),
[password] VARCHAR(256),
GP_employee_id INT,
slip_number INT,
slip_number2 INT
);
DECLARE db_cursor CURSOR FOR
SELECT DISTINCT company FROM [payslips].[dbo].[myapp_user];
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #company
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = '
SELECT
email,
password,
GP_employee_id,
slip_number = (select distinct CHEKNMBR from ' + QUOTENAME(#company) + '.[dbo].[UPR30300] WHERE EMPLOYID = GP_employee_id and CHEKDATE > GETDATE() - 20),
slip_number2 = (select distinct CONVERT(date , CHEKDATE) from ' + QUOTENAME(#company) + '.[dbo].[UPR30300] WHERE EMPLOYID = GP_employee_id and CHEKDATE > GETDATE() - 20)
FROM
[payslips].[dbo].[myapp_user]';
INSERT INTO #myapp_user EXECUTE (#sql);
FETCH NEXT FROM db_cursor INTO #company;
END
CLOSE db_cursor
DEALLOCATE db_cursor
SELECT * FROM #myapp_user;

Related

Join using dynamic column names SQL Server

I have a table which can output any number of different columns (from 'Level1' to 'Level'N).
I need to perform a left join on each of these dynamic columns against a CTE
I have written the following script but keep getting this error:
Msg 102, Level 15, State 1, Line 15 Incorrect syntax near '10'.
To troubleshoot, I have tried removing the each of the variables in the CTE with no luck.
Any help would be much appreciated!
DECLARE #rel varchar(4) = CAST('X112' AS varchar(4))
DECLARE #todaysdate date = CONVERT(date,GETDATE())
--create cte
DECLARE #sqltext varchar(MAX) =
' WITH CTE AS
(
SELECT
ID
,STARTDATE
,ENDDATE
,NEWID
FROM Tbl
WHERE TYPE = ''' + #rel + '''
AND ENDDATE >= ' + CAST(#todaysdate AS varchar(30)) +' AND STARTDATE <= ' + CAST(#todaysdate AS varchar(30)) +'
)
SELECT ID, NEWID, Level';
--find max lvl, convert to str
DECLARE #counter int = (SELECT MAX(lvl) FROM tbl2)
DECLARE #counterstring varchar(3)
SET #counterstring = CAST(#counter AS varchar(3))
WHILE #counter != 0
BEGIN
SET #sqltext = #sqltext + #counterstring + ' INTO tbl3 '
+ ' FROM tbl2 a '
+ ' LEFT JOIN CTE c ON a.Level' + #counterstring + ' = c.NEWID'
SET #counter = #counter - 1
END
EXEC(#sqltext)
--edited version
DECLARE #rel varchar(4) = CAST('X112' AS varchar(4))
DECLARE #todaysdate date = CONVERT(date,GETDATE())
DECLARE #sqltext varchar(MAX) =
' WITH CTE AS
(
SELECT
ID
,STARTDATE
,ENDDATE AS mgmt_ENDDA
,NEWID
FROM tbl
WHERE SUBTY = ''' + #rel + '''
AND ENDDATE >= ' + CAST(#todaysdate AS varchar(30)) +' AND STARTDATE <= ' + CAST(#todaysdate AS varchar(30)) +'
)
INSERT INTO tbl3
SELECT ID, NEWID, Level';
DECLARE #counter int = (SELECT MAX(lvl) FROM tbl2)
DECLARE #counterstring varchar(3)
WHILE #counter != 0
BEGIN
SET #counterstring = CAST(#counter AS varchar(3))
SET #sqltext = #sqltext + #counterstring
+ ' FROM tbl2 a '
+ ' LEFT JOIN CTE c ON a.Level' + #counterstring + ' = c.NEWID'
SET #counter = #counter - 1
END
EXEC(#sqltext)
Since select * into query creates a new table each time, I am assuming that you are trying to create 'n' number of tables for 'n' number of levels, with the result obtained by joining with nth column. I have 2 suggestions for you
Bring the select query within the while loop and append ';' at the end of the loop to split select queries.
instead of INTO tbl3 use INTO tbl + #counterstring as select * into will create new table
Hope this helps you
Can you change it like this and try again?
--edited version
DECLARE #rel varchar(4) = CAST('A012' AS varchar(4))
DECLARE #todaysdate date = CONVERT(date,GETDATE())
DECLARE #sqltext varchar(MAX) =
' WITH CTE AS
(
SELECT
ID
,STARTDATE
,ENDDATE AS mgmt_ENDDA
,NEWID
FROM tbl
WHERE SUBTY = ''' + #rel + '''
AND ENDDATE >= ' + CAST(#todaysdate AS varchar(30)) +' AND STARTDATE <= ' + CAST(#todaysdate AS varchar(30)) +'
)
INSERT INTO tbl3';
DECLARE #counter int = (SELECT MAX(lvl) FROM tbl2)
DECLARE #counterstring varchar(3)
WHILE #counter != 0
BEGIN
SET #counterstring = CAST(#counter AS varchar(3))
SET #sqltext = #sqltext + CHAR(10) +'SELECT ID, NEWID, Level'+#counterstring
SET #sqltext = #sqltext + ' FROM tbl2 a '
+ ' LEFT JOIN CTE c ON a.Level' + #counterstring + ' = c.NEWID'
SET #counter = #counter - 1
IF #counter <> 0
SET #sqltext = #sqltext + CHAR(10) + ' UNION '
END
EXEC(#sqltext)
You can try 'UNION ALL' instead of 'UNION' if you dont want to get rid of duplicate data. Hope this helps

How can I return a distinct count of a variable for all tables in my database?

I have a SQL database with 60+ tables, almost all of which are populated with a CLIENTID field. I want to count the number of unique client IDs in each table.
The results I'm looking for are:
TABLE_NAME; CLIENTID_COUNT
dbo.HISTORY; 650
dbo.VISITS; 596
dbo.SALES; 1053
...; ...
This seems like it should be so simple but I've been playing around with cursors for hours and can't figure this one out. Please help!
IF OBJECT_ID('tempdb..#temp_RESULTS') IS NOT NULL DROP TABLE #temp_RESULTS
CREATE TABLE #TEMP_RESULTS
(
TABLENAME VARCHAR(MAX),
CLIENTCNT BIGINT
)
DECLARE #TABLENAME VARCHAR(MAX)
DECLARE #command VARCHAR(MAX)
IF OBJECT_ID('tempdb..#temp_PROCESS') IS NOT NULL DROP TABLE #temp_PROCESS
SELECT * INTO #TEMP_PROCESS FROM sys.tables
WHILE EXISTS(SELECT * FROM [#TEMP_PROCESS])
BEGIN
SET #TABLENAME = (SELECT TOP 1 [NAME] FROM [#TEMP_PROCESS])
SET #command = ('SELECT ''' + #TABLENAME + ''', COUNT(DISTINCT CLIENTID) AS CLIENTCNT FROM ' + #TABLENAME)
SELECT #command
INSERT INTO #TEMP_RESULTS
EXEC(#command)
DELETE FROM [#TEMP_PROCESS] WHERE [NAME] = #TABLENAME
END
SELECT * FROM [#TEMP_RESULTS]
Assuming the column is exactly ClientId in every table, you should be able to use this as is:
DROP TABLE IF EXISTS #clientId
CREATE TABLE #clientId
(
TableName nvarchar(1000),
ClientIdCount bigint
)
DECLARE #TableName nvarchar(1000);
DECLARE #CurrentQuery nvarchar(2000);
DECLARE result_cursor CURSOR local fast_forward FOR
SELECT DISTINCT
'['+TABLE_SCHEMA + '].[' + TABLE_NAME + ']'
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
COLUMN_NAME = 'ClientId'
OPEN result_cursor
FETCH NEXT FROM result_cursor into #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #CurrentQuery = 'SELECT ''' + #TableName + ''', COUNT(DISTINCT ClientId) FROM ' + #TableName
--print #CurrentQuery
INSERT INTO
#clientId
(
TableName,
ClientIdCount
)
EXEC(#CurrentQuery)
FETCH NEXT FROM result_cursor into #TableName
END
--end loop
--clean up
CLOSE result_cursor
DEALLOCATE result_cursor
GO
SELECT
*
FROM
#clientId
You could use dynamic sql.
This will read through your system tables, find those that have a ClientID column, and build the text of a query that's in the general shape of 'Select Count(DISTINCT ClientID)' from each table.
DECLARE #SQLQuery as nvarchar(max) = ''
------------------------------------
-- GET THE TABLES THAT HAVE A CLIENTID FROM SCHEMA
SELECT #SQLQuery = #SQLQuery + qryTxt FROM (
SELECT DISTINCT 'SELECT ''' + tables.name + ''', COUNT(DISTINCT CLIENTID) FROM ' + tables.name + ' UNION ' AS qryTxt
FROM sys.columns left join sys.tables on columns.object_id = tables.object_id where columns.name = CLIENTID AND isnull(tables.name, '') <> '') subquery
------------------------------------
-- REMOVE THE LAST 'UNION' KEYWORD FROM SQLQUERY
SET #SQLQuery = left(#sqlQuery, len(#sqlQuery) - 5)
------------------------------------
-- EXECUTE
execute sp_executesql #SQLQuery
I really dislike cursors and loops. Even though this is not going to be much difference for a performance perspective I like to share how you can leverage the system tables and dynamic sql to avoid using a cursor, while loop or temp tables for something like this.
This code is literally all you need to to do this.
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'select TableName = ''' + t.name + ''', ClientID_Count = count(distinct clientID)
from ' + QUOTENAME(t.name) + ' UNION ALL '
from sys.tables t
join sys.columns c on c.object_id = t.object_id
where c.name = 'clientID'
select #SQL = left(#SQL, len(#SQL) - 10) --removes the last UNION ALL
select #SQL
--once your comfortable the dynamic sql is correct just uncomment the line below.
--exec sp_executesql #SQL
A similar pattern to other answers here, but this is how I would tackle it:
IF OBJECT_ID('#Tables', 'U') IS NOT NULL
DROP TABLE #Tables;
SELECT ID = IDENTITY(INT, 1, 1),
SchemaName = OBJECT_SCHEMA_NAME([object_id]),
TableName = OBJECT_NAME([object_id]),
ColumnName = name,
DistinctCount = 0
INTO #Tables
FROM sys.columns
WHERE name = 'CLIENTID';
DECLARE #ID INT = 1,
#MaxID INT = (SELECT MAX(ID) FROM #Tables);
WHILE #ID < #MaxID
BEGIN;
DECLARE #SQLCommand VARCHAR(MAX);
SELECT #SQLCommand = FORMATMESSAGE('
UPDATE #Tables SET DistinctCount = (
SELECT COUNT(DISTINCT %s) FROM %s.%s
)
WHERE ID = %i;',
QUOTENAME(ColumnName), QUOTENAME(SchemaName), QUOTENAME(TableName), ID)
FROM #Tables
WHERE ID = #ID;
EXEC (#SQLCommand);
SET #ID += 1;
END;
SELECT *
FROM #Tables;

Bulk select into FROM Information_schema.Tables

I want to copy records from a bunch of tables into one table. I run through the tables dynamically. This works OK for the first encountered table. However, when it gets to the next variable table, it reports the destination table is already existing:
DECLARE #SQL nvarchar(max) = ''
SELECT #SQL = #SQL + 'select Datum, Tijd, Scanner into my_destination_table from '+ TABLE_NAME +' where tijd > 12 '
FROM Information_schema.Tables
WHERE TABLE_NAME LIKE 'tbl_%_Tijden'
EXEC sp_executesql #SQL;
Msg 2714, Level 16, State 6, Line 1
There is already an object named 'my_destination_table' in the database.
I just need it to keep filling my_destination_table with the records found.
Any suggestions?
thx,
James
#Giorgos, your solution seems to be working OK. I have tweaked it a liitle bit, and it does work. What I don't understand is why the results are doubled? This is the SQL:
DECLARE #SQL nvarchar(max) = ''
declare #t nvarchar(max) = '';
select #t = min(TABLE_NAME) from Information_schema.Tables
where TABLE_NAME > #t and TABLE_NAME like 'tbl_%_Tijden';
delete from tblfouttijden;
while #t is not null
begin
set #SQL = 'insert into tblfouttijden (Projectnr, Datum, Start, Einde, Tijd, TijdTijd, Scanner, StartID, EindID, Naam) select Projectnr, Datum, Start, Einde, Tijd, TijdTijd, Scanner, StartID, EindID, Naam from '+ #t +' where tijd > 12 ';
EXEC sp_executesql #SQL;
-- Move to the next table, if one exists:
select #t = min(TABLE_NAME) from Information_schema.Tables WHERE TABLE_NAME > #t and TABLE_NAME LIKE 'tbl_%_Tijden';
end
This will avoid duplicates:
create table tblfouttijden (Datum varchar(10), Tijd int, Scanner varchar(20)
, ... ) ;
DECLARE #SQL nvarchar(max) = '';
declare #t nvarchar(max) = '';
select #t = min(TABLE_NAME) from Information_schema.Tables WHERE TABLE_NAME > #t and TABLE_NAME LIKE 'tbl_%_Tijden';
set #SQL = 'select Projectnr, Datum, Start, Einde, Tijd, TijdTijd, Scanner, StartID, EindID, Naam from '
+ #t +' where tijd > 12 ';
while #t is not null
begin
select #t = min(TABLE_NAME) from Information_schema.Tables WHERE TABLE_NAME > #t and TABLE_NAME LIKE 'tbl_%_Tijden';
if #t is not null
set #SQL = #SQL + 'union select Projectnr, Datum, Start, Einde, Tijd, TijdTijd, Scanner, StartID, EindID, Naam from '
+ #t +' where tijd > 12 ';
end
set #SQL = 'insert into tblfouttijden (Projectnr, Datum, Start, Einde, Tijd, TijdTijd, Scanner, StartID, EindID, Naam) '
+ #SQL;
EXEC sp_executesql #SQL;

cursor loop - >while (##FETCH_STATUS=0) not going into loop

I have below code:
declare #prefix varchar(50)
set #prefix = 'schema1'
declare #TablesAndIdentifiers table (TableT0 varchar(50), TableX0 varchar(50), IdentifierT0 varchar(50), IdentifierX0 varchar(50))
insert into #TablesAndIdentifiers(TableT0, TableX0, IdentifierT0, IdentifierX0)
values
('table1', 'table2', 'external_Id', 'Key Details | External Id')
declare #TableT varchar(50)
declare #TableX varchar(50)
declare #IdentifierT varchar(50)
declare #IdentifierX varchar(50)
------------------------------------------OUTER LOOP------------------------------------------
declare #OuterCursor cursor
set #OuterCursor = cursor for select * from #TablesAndIdentifiers
open #OuterCursor
fetch next from #OuterCursor into #TableT, #TableX, #IdentifierT, #IdentifierX
while(##FETCH_STATUS = 0)
begin
declare #ColList2 table (ColListT varchar(50), ColListX varchar(50))
insert into #ColList2(ColListT,ColListX)
select ColListT, ColListX
from (
select COLUMN_NAME as ColListT, row_number() over (order by table_name) as r from INFORMATION_SCHEMA.Columns
where table_name = #TableT and COLUMN_NAME!=#IdentifierT) a
full outer join
(select COLUMN_NAME as ColListX, row_number() over (order by table_name) as r from INFORMATION_SCHEMA.Columns
where table_name = #TableX and COLUMN_NAME!=#IdentifierX) b
on a.r = b.r
--Declare and set variables containing the query which will insert the mismatch columns into a new table
--#sqlfull is a concatenation of #sqlpre, #sql, #sqlpost, #sqlwhere, #sqlpregroup, #sqlgroupstatement, #sqlpostgroup
--The reason for this is that #sql is the only part of the query we want to be contained in the loop - the others should run outside of the loop
declare #sqlpre varchar(max)
declare #sql varchar(max)
declare #sqlpost varchar(max)
declare #sqlgroupstatement varchar(max)
declare #sqlpostgroup varchar(max)
declare #sqlfull varchar(max)
set #sqlpre = 'select * from (select '
set #sql = ''
set #sqlpost = #IdentifierT + ' from '+#prefix+'.dbo.' +#TableX +' x inner join '+#prefix+'.dbo.' +#TableT + ' t on t.' +#IdentifierT + ' = x.[' + #IdentifierX +'])dt1 group by '
set #sqlgroupstatement = ''
set #sqlpostgroup = ' ' + #IdentifierT
declare #Cursor cursor, #ColListTvar varchar(100), #ColListXvar varchar(100)
set #Cursor = cursor for select * from #ColList2
open #Cursor
fetch next from #Cursor into #ColListTvar,#ColListXvar
Print 'Before While => ' + CAST(##FETCH_STATUS AS varchar(32))
while (##FETCH_STATUS = 0)
begin
Print 'Inside while -=> ' + CAST(##FETCH_STATUS AS varchar(32))
set #sql = #sql + 'case when t.' +#ColListTvar + ' != x.[' +#ColListXvar + '] then 1 else null end as ' + #ColListTvar+'_mismatch, '
set #sqlgroupstatement = #sqlgroupstatement + #ColListTvar+'_mismatch, '
fetch next from #Cursor into #ColListTvar,#ColListXvar
end
close #Cursor
Print 'After While => ' + CAST(##FETCH_STATUS AS varchar(32))
set #sqlfull = concat(#sqlpre,#sql,#sqlpost,#sqlgroupstatement,#sqlpostgroup)
print(#sqlfull)
--exec(#sqlfull)
declare #ColListMismatch varchar(max)
select #ColListMismatch = coalesce(#ColListMismatch+'_count,' ,'') + column_name
from INFORMATION_SCHEMA.COLUMNS where table_name = 'mismatches_' + #TableT and COLUMN_NAME!=#IdentifierT
-- The last column in the list won't get a '_count' in its name (but it needs it as the rest of the code assumes this is the naming convention)
-- See below for workaround to get round this
--Create table variable containing the list of mismatch columns (in which we want to count the non-nulls - non-null implies there has been a mismatch)
declare #ColListMismatchTable table (ColListM varchar(50))
insert into #ColListMismatchTable(ColListM)
select ColListM
from (select [COLUMN_NAME] as ColListM from INFORMATION_SCHEMA.Columns
where table_name = 'mismatches_'+#TableT and COLUMN_NAME!=#IdentifierT)dt1
--Declare variables for use in queries
declare #sqlpre2 varchar(max)
declare #sqlloop varchar(max)
declare #sqlpost2 varchar(max)
declare #sqlfull2 varchar(max)
-- Select counts from the transformation layer table and the XPLAN table; also select the count of the table produced as a result of the inner join between the two
-- If the migration has functioned correctly, these three counts should all be the same
set #sqlpre2 = 'select countXPLAN, countTransfLayer, countXPLAN-countTransfLayer as CountDiff, countMatchedIdentifiers, '
-- As mentioned above, the "+ #ColListMismatch + '_count into " part of the below is necessary to append the _count to the last variable
+ #ColListMismatch + '_count into '+#prefix+'.[dbo].report_' + #TableT + ' from '
set #sqlloop = ''
set #sqlpost2 = ' select * from ((select count(*) as countTransfLayer from '+#prefix+'.dbo.'+#TableT+')dt1 cross join (select count(*) as countXPLAN from '+#prefix+'.dbo.['+#TableX+'])dt2 cross join (select count(*) as countMatchedIdentifiers from '+#prefix+'.dbo.mismatches_'+#TableT+')dt4)'
------------------------------------------SECOND INNER LOOP------------------------------------------
--Use Cursor to create loop to produce counts for each column in mismatches_*
declare #Cursor2 cursor, #ColListMismatchvar varchar(50)
set #Cursor2 = cursor for select * from #ColListMismatchTable
open #Cursor2
fetch next from #Cursor2 into #ColListMismatchvar
while(##FETCH_STATUS = 0)
begin
-- Select all the counts of non-nulls
set #sqlloop = #sqlloop + '(select count(*) as '+ #ColListMismatchvar + '_count from mismatches_' + #TableT + ' where ' + #ColListMismatchvar + '=1)dt_' + #ColListMismatchvar + ' cross join '
fetch next from #Cursor2 into #ColListMismatchvar
end
-- Remove variables so that they can be reused by the next data entity
delete #ColListMismatchTable
select #ColListMismatch=null
close #Cursor2
print('in loop to execute sqlfull2')
set #sqlfull2 = concat(#sqlpre2,#sqlloop,#sqlpost2)
print(#sqlfull2)
-- exec(#sqlfull2)
print('executed sqlfull2')
fetch next from #OuterCursor into #TableT, #TableX, #IdentifierT, #IdentifierX
end
close #OuterCursor
out put of is:
(1 row(s) affected)
(0 row(s) affected)
Before While => -1
After While => -1
select * from (select external_Id from schema1.dbo.table22 x inner join schama1.dbo.table1 t on t.external_Id = x.[Key Details | External Id])dt1 group by external_Id
(0 row(s) affected)
(0 row(s) affected)
in loop to execute sqlfull2..
The problem i am facing code is not going into while loop of below code
declare #Cursor cursor, #ColListTvar varchar(100), #ColListXvar varchar(100)
set #Cursor = cursor for select * from #ColList2
open #Cursor
fetch next from #Cursor into #ColListTvar,#ColListXvar
Print 'Before While => ' + CAST(##FETCH_STATUS AS varchar(32))
while (##FETCH_STATUS = 0)
begin
Print 'Inside while -=> ' + CAST(##FETCH_STATUS AS varchar(32))
set #sql = #sql + 'case when t.' +#ColListTvar + ' != x.[' +#ColListXvar + '] then 1 else null end as ' + #ColListTvar+'_mismatch, '
set #sqlgroupstatement = #sqlgroupstatement + #ColListTvar+'_mismatch, '
fetch next from #Cursor into #ColListTvar,#ColListXvar
end
close #Cursor
Print 'After While => ' + CAST(##FETCH_STATUS AS varchar(32))
set #sqlfull = concat(#sqlpre,#sql,#sqlpost,#sqlgroupstatement,#sqlpostgroup)
print(#sqlfull)
--exec(#sqlfull)
any suggestions will be much appreciated.
Thanks in advance.
After lot of analysis i found that issue with
select ColListT, ColListX
from (
select COLUMN_NAME as ColListT, row_number() over (order by table_name) as r from INFORMATION_SCHEMA.Columns
where table_name = #TableT and COLUMN_NAME!=#IdentifierT) a
full outer join
(select COLUMN_NAME as ColListX, row_number() over (order by table_name) as r from INFORMATION_SCHEMA.Columns
where table_name = #TableX and COLUMN_NAME!=#IdentifierX) b
on a.r = b.r
Instead of Full outer join if i use inner join it worked.
There was issue with number of columns in 2 tables, one of table has less column than other, that's the reason it wasn't working properly.

Select columns based on values from any table(number of columns is variable) SQL

I have a following table:
Table 1
And I want to show only columns that have at least one value under 50:
Table 2
I need a stored procedure that does this. The trick is that I want to use it on multiple tables but the number of columns can vary from table to table.
Can this be done?
Wish this will have some help.
SET NOCOUNT ON
DECLARE
#tablename VARCHAR(50) = 'Table1',
#valuetocompare INT = 50,
#otherfields VARCHAR(100) = 'Date, Hour,';
DECLARE #t AS TABLE (cname VARCHAR(10), cvalue INT)
DECLARE #sql NVARCHAR(1000);
DECLARE #cname VARCHAR(128);
DECLARE c CURSOR
FOR
SELECT NAME
FROM sys.[columns] AS c
WHERE c.[object_id] = OBJECT_ID(#tablename)
;
OPEN c;
FETCH NEXT FROM c INTO #cname;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'select ''' + #cname + ''', ' + #cname + ' from ' + #tablename;
INSERT INTO #t
(
cname,
cvalue
)
EXECUTE (#sql);
FETCH NEXT FROM c INTO #cname;
END
CLOSE c;
DEALLOCATE c;
DECLARE #cnames VARCHAR(100) = '';
WITH dcnames AS (
SELECT DISTINCT cname
FROM #t
WHERE cvalue < #valuetocompare
)
SELECT #cnames = #cnames + cname + ','
FROM dcnames;
IF #cnames = ''
PRINT 'No column value is less than ' + CAST(#valuetocompare AS VARCHAR);
ELSE
BEGIN
SET #sql = 'select ' + #otherfields + LEFT(#cnames, LEN(#cnames) - 1) + ' from ' + #tablename;
EXECUTE (#sql);
END