Iterate through temporary table columns to select them - sql

I have a final temporary table (#tempTable) with unknown columns number.
My final select is like this, it works :
SELECT temp.* FROM #tempTable temp
But instead of a '*' I would like to call each columns individually :
SELECT temp.col1, temp.col2 FROM #tempTable temp
To do so I need to iterate through my columns names and create a procedure, I tried something like this :
DECLARE #ColName VARCHAR(255)
SELECT #ColName = min(name) FROM tempdb.sys.columns
WHERE object_id = Object_id('tempdb..#TEMPTABLE');
WHILE #ColName is not null
BEGIN
-- i need to do it all in once and not each time....
declare #sql varchar(max) = 'SELECT tp.'+'#COlName'+'FROM #TEMPTABLE tp'
exec(#sql)
-- Increment the value, how to go to next column ?
select #ColName = min(name) FROM tempdb.sys.columns WHERE object_id =
Object_id('tempdb..#TEMPTABLE') > #ColName -- does not work because it is a string (column name)
END

Try this:
DECLARE #ColName VARCHAR(2000) = 'select '
SELECT #ColName = #ColName + ' temp.' + name + ',' FROM tempdb.sys.columns
WHERE object_id = Object_id('tempdb..#TEMPTABLE')
--delete last character, which is comma and append table name
#ColName = substring(#ColName, 1, LEN(#ColName) - 1) + ' from #TEMPTABLE temp'
exec(#ColName)
This query construct whole table list combined in select ... from ... statement. I increased size of the varchar variable, so it can accomodate long queries.
Also, IMO variable name such as #sql or #query would be more meaningful.

A set based approach
IF OBJECT_ID('tempdb..#TEMPTABLE','U') IS NOT NULL
DROP TABLE #TEMPTABLE;
CREATE TABLE #TEMPTABLE (
Id INT IDENTITY(1,1)
,Col1 INT
,Col2 BIGINT
,Col3 BIGINT
,Col4 DATETIME
,Col5 DATETIME
) ;
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = N'SELECT ' + SUBSTRING((
SELECT N', temp.' + S.name
FROM
tempdb.sys.columns S
WHERE
S.object_id = OBJECT_ID('tempdb..#TEMPTABLE')
ORDER BY
S.column_id
FOR XML PATH('')
)
,2
,200000
) + N' FROM #TEMPTABLE temp'
EXEC sys.sp_executesql #SQL

Related

Dynamic query to find the length of rows in a column in sql server

I need to prepare a dynamic query to find the length of all the rows in a column in sql server. let say if there are 10 columns for a table with 100 rows. I need to find the row length for each column dynamically.
Assuming that your all columns are string columns, though len function should work anyways.
-- replace 'mytable' with the actual table name
declare #tableName nvarchar(128) = 'mytable';
declare #queryToRun nvarchar(max) = '';
-- IMPORTANT: following query is putting each column name as len_columnName
select #queryToRun = #queryToRun + ', len([' + c.name + ']) as [len_' + c.name + ']
'
from sys.tables as t
inner join sys.columns as c on t.object_id = c.object_id
where t.name = #tableName
-- removing the first comma
set #queryToRun = SUBSTRING(#queryToRun, 2, len(#queryToRun) - 1);
-- creating the query with dynamic column names
set #queryToRun = 'select ' + #queryToRun + ' from ' + #tableName;
--print #queryToRun
exec (#queryToRun)
you can use sys.tables and sys.all_columns
declare #Sql nvarchar(max)='select '
select #Sql=#sql+'Sum(len('+QUOTENAME(c.name)+')) as Len'+QUOTENAME(c.name)+',' from sys.tables t join sys.all_columns c on t.object_id=c.object_id
where t.Name='YourTableName'
set #Sql = left(#Sql,len(#sql)-1)+' from YourTableName'
select #Sql
Try this Script you will get data length of each columns in table dynamically
IF OBJECT_ID('dbo.LenghtOfRows')IS NOT NULL
DROP TABLE LenghtOfRows
CREATE TABLE LenghtOfRows (
Id Int IDENTITY,
Sqlode nvarchar(max)
)
DECLARE #SQL NVARCHAR(max),
#MinId INT,
#MaxId INT,
#tableName Varchar(100) ='StudentLabExamScore', --Give Table name here
#GetSQL NVARCHAR(max)
SET #SQL = 'SELECT ''SELECT DATALENGTH(''+COLUMN_NAME+'') As Len_'' +COLUMN_NAME +'' FROM ''+TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = '''+#tableName+''''
PRINT #SQL
INSERT INTO LenghtOfRows(Sqlode)
EXEC ( #SQL)
SELECT #MinId = MIN(Id) from LenghtOfRows
SELECT #MaxId = MAX(Id) from LenghtOfRows
WHILE (#MInId <=#MaxId)
BEGIN
SELECT #GetSQL= Sqlode FROM LenghtOfRows WHERE id=#MInId
EXEC (#GetSQL)
PRINT #GetSQL
SET #MInId=#MInId+1
END

Select table with name from column value

I have this SQL query
SELECT table_name
INTO #LukaTestTable
FROM information_schema.columns
WHERE column_name = 'GUID'
ORDER BY TABLE_NAME ;
How get the value of the column GUID in all tables with the name from TABLE_NAME?
Or can I get table like?
TABLE_NAME GUID_VALUE
In order to be able to query a table before you know what table you want you have to use dynamic queries. If you have an arbitrary number of tables, in SQL Server you could achieve this with cursors:
DECLARE
#column VARCHAR(256) = 'GUID',
#table VARCHAR(256),
#query VARCHAR(4000);
DECLARE #Tables CURSOR LOCAL FAST_FORWARD
FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = #column
ORDER BY TABLE_NAME;
OPEN #Tables
FETCH NEXT FROM #Tables INTO #table
WHILE ##FETCH_STATUS = 0
BEGIN
SET #query = 'SELECT ' + #column + ' FROM ' + #table
EXEC(#query)
FETCH NEXT FROM #Tables INTO #table
END
CLOSE #Tables
DEALLOCATE #Tables;
If you're sure your 'GUID' column will have same data type - you can create a temp table and insert to it in WHILE loop and SELECT everything in one go at the end.
You can use dynamic sql like this:
declare #sql varchar(max) = cast (' ' as varchar(max));
select #sql = #sql +
(select ' select GUID from ' + quotename(table_name) + ' union all ' as 'text()'
from #LukaTestTable
for xml path(''));
set #sql = reverse(stuff(reverse(#sql), 1, 10, ''));
--print #sql
exec(#sql);
And if you want table_name as e separate column you should first save it in your #LukaTestTable
Try this below script using While loop and dynamic Sql
IF OBJECT_ID('tempdb..#GetSqlQuery') IS NOT NULL
DROP TABLE #GetSqlQuery
IF OBJECT_ID('tempdb..#GetSpecficcolumnvalue') IS NOT NULL
DROP TABLE #GetSpecficcolumnvalue
GO
CREATE TABLE #GetSqlQuery
(
ID INT IDENTITY
,SELECtQuery nvarchar(max)
,TableName varchar(200)
)
CREATE TABLE #GetSpecficcolumnvalue
(
ID INT IDENTITY
,GetValue nvarchar(max)
,TableName varchar(200)
)
INSERT INTO #GetSqlQuery(SELECtQuery,TableName)
SELECT 'SELECT GUID,'''+TABLE_NAME+''' As TableName FROM '+QUOTENAME(TABLE_NAME) AS SELECtQuery,QUOTENAME(TABLE_NAME) AS TableName
FROM(
SELECT
TABLE_SCHEMA,
TABLE_NAME,
COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME ='GUID'
)dt
ORDER BY TABLE_NAME
DEclare #MinId INt,#MaxId INT,#Sql nvarchar(maX),#TableName varchar(1000)
SELECT #MinId =MIN(Id),#MaxId=MAX(ID) FROM #GetSqlQuery
WHILE (#MinId<=#MaxId)
BEgin
SELECT #Sql=SELECtQuery ,#TableName=TableName From #GetSqlQuery WHERE ID=#MinId
PRINT #Sql
INSERT INTO #GetSpecficcolumnvalue(GetValue,TableName)
EXEC (#Sql)
SET #MinId=#MinId+1
END
SELECT ROW_NUMBER()OVER(ORDER BY (SELECT 1)) AS Seq,GetValue,TableName
FROM
(
SELECT *, ROW_NUMBER ()OVER(PArtition by GetValue,TableName ORDER BY
TableName) AS dup FROM #GetSpecficcolumnvalue
)dt where dt.dup=1

Get top three most common values from every column in a table

I'm trying to write a query that will produce a very small sample of data from each column of a table, in which the sample is made up of the top 3 most common values. This particular problem is part of a bigger task, which is to write scripts that can characterize a database and its tables, its data integrity, and also quickly survey common values in the table on a per-column basis. Think of this as an automated "analysis" of a table.
On a single column basis, I do this already by simply calculating the frequency of values and then sorting by frequency. If I had a column called "color" and all colors were in it, and it just so happened that the color "blue" was in most rows, then the top 1 most frequently occurring value would be "blue". In SQL that is easy to calculate.
However, I'm not sure how I would do this over multiple columns.
Currently, when I do a calculation over all columns of a table, I perform the following type of query:
USE database;
DECLARE #t nvarchar(max)
SET #t = N'SELECT '
SELECT #t = #t + 'count(DISTINCT CAST(' + c.name + ' as varchar(max))) "' + c.name + '",'
FROM sys.columns c
WHERE c.object_id = object_id('table');
SET #t = SUBSTRING(#t, 1, LEN(#t) - 1) + ' FROM table;'
EXEC sp_executesql #t
However, its not entirely clear to me how I would do that here.
(Sidenote:columns that are of type text, ntext, and image, since those would cause errors while counting distinct values, but i'm less concerned about solving that)
But the problem of getting top three most frequent values per column has got me absolutely stumped.
Ideally, I'd like to end up with something like this:
Col1 Col2 Col3 Col4 Col5
---------------------------------------------------------------------
1,2,3 red,blue,green 29,17,0 c,d,j nevada,california,utah
I hacked this together, but it seems to work:
I cant help but think I should be using RANK().
USE <DB>;
DECLARE #query nvarchar(max)
DECLARE #column nvarchar(max)
DECLARE #table nvarchar(max)
DECLARE #i INT = 1
DECLARE #maxi INT = 10
DECLARE #target NVARCHAR(MAX) = <table>
declare #stage TABLE (i int IDENTITY(1,1), col nvarchar(max), tbl nvarchar(max))
declare #results table (ColumnName nvarchar(max), ColumnValue nvarchar(max), ColumnCount int, TableName NVARCHAR(MAX))
insert into #stage
select c.name, o.name
from sys.columns c
join sys.objects o on o.object_id=c.object_id and o.type = 'u'
and c.system_type_id IN (select system_type_id from sys.types where [name] not in ('text','ntext','image'))
and o.name like #target
SET #maxi = (select max(i) from #stage)
while #i <= #maxi
BEGIN
set #column = (select col from #stage where i = #i)
set #table = (select tbl from #stage where i = #i)
SET #query = N'SELECT ' +''''+#column+''''+' , '+ #column
SELECT #query = #query + ', COUNT( ' + #column + ' ) as count' + #column + ' , ''' + #table + ''' as tablename'
select #query = #query + ' from ' + #table + ' group by ' + #column
--Select #query
insert into #results
EXEC sp_executesql #query
SET #i = #i + 1
END
select * from #results
; with cte as (
select *, ROW_NUMBER() over (partition by Columnname order by ColumnCount desc) as rn from #results
)
select * from cte where rn <=3
Start with this SQL Statement builder, and modify it to suit your liking:
EDIT Added Order by Desc
With ColumnSet As
(
Select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME
From INFORMATION_SCHEMA.COLUMNS
Where 1=1
And TABLE_NAME IN ('Table1')
And COLUMN_NAME IN ('Column1', 'Column2')
)
Select 'Select Top 3 ' + COLUMN_NAME + ', Count (*) NumInstances From ' + TABLE_SCHEMA + '.'+ TABLE_NAME + ' Group By ' + COLUMN_NAME + ' Order by Count (*) Desc'
From ColumnSet

Dynamic SQL - Picking the values from the temp table

I have a temp table that has the following information.
TableName ColumnName PrimaryKeyColumnName Primarykey(A GUID)
(4 columns)
I need to include one more new column Value that should grab data based on the condition below
"for each row in the temp table"
select ColumnName from TableName where PrimaryKeyColumnName = Primarykey
To be even more precise , the query must retrieve the values from the table directly.
I am sure this can be achieved using cursor. But it might impact my query performance.
Could this be achieved using sp_sqlexecute? I tried converting the query as a varchar.
Like this
set #sql = 'select '+ #final.[primary field] +'from ' + #final.tablename +
'where '+ #final.PrimaryKeyColumnName + '='+ #final.Primarykey
exec sp_sqlexecute #sql
Possible this be helpful for you -
IF OBJECT_ID('tempdb.dbo.#temp') IS NOT NULL
DROP TABLE #temp
GO
CREATE TABLE #temp
(
[primary field] SYSNAME,
tablename SYSNAME,
PrimaryKeyColumnName SYSNAME,
Primarykey SYSNAME
)
INSERT INTO #temp ([primary field], tablename, PrimaryKeyColumnName, Primarykey)
VALUES
('[column1]','[table1]','[column3]', '[column12]'),
('[column2]','[table2]','[column4]', '[column24]')
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = (
SELECT CHAR(13) + 'SELECT '+ [primary field] + ' FROM ' + tablename +
' WHERE '+ PrimaryKeyColumnName + ' = '+ Primarykey
FROM #temp
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
PRINT #SQL
--EXEC sys.sp_executesql #SQL
Output -
SELECT [column1] FROM [table1] WHERE [column3] = [column12]
SELECT [column2] FROM [table2] WHERE [column4] = [column24]
I am not sure that I understood what you are trying to do but try this:
declare #sql varchar(8000);
set #sql = null;
select #sql =
coalesce(#sql+' union all select '+ColumnName+' from '+ tablename,
'select '+ColumnName+' from '+ tablename)
from final where ColumnName = PrimaryKeyColumnName;
exec sp_sqlexecute #sql;
Notice that the #sql is limited -in my sample 8000- if the temp table you have is too big you gonna have to make a separate executes,needs some changes in the code.
Always you have to set an initial value for #SQL as null.
I think no need for cursor, this will be solved using some SQL tricks.
Hope this will help...
Create Table #tempValueFetch
(
TableName sysname,
PrimaryKeyColumnName sysname,
AttributeColumnName sysname,
Primaryfield sysname,
PrimaryKey sysname,
Label nvarchar(max),
Value nvarchar(max)
)
this temp table has been populated with 5 columns namely TableName,PrimaryKeyColumnName,AttributeColumnName ,Primaryfield ,PrimaryKey
The columns label and value has to updated dynamically.Note that primary key is a uniqueidentifier

SQL schema and value

I have a select statement I want to make. I want to select
SELECT COLUMN_NAME AS FieldName FROM
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'table1'
However I want to create another column named Value which is a particular row in table1
so I have rows of the column name and the corresponding single value. Any thoughts on how to approach this?
The following query produces a value (the minimum) for each column:
SELECT '''select '+COLUMN_NAME+''' AS FieldName, (select cast(MIN('+COLUMN_NAME+') as varchar(8000)) from '+const.tablename+')'
FROM INFORMATION_SCHEMA.COLUMNS c cross join
(select 'AllCurveNames' as tablename) const
WHERE c.TABLE_NAME = const.tablename
However, this produces a separate query for each row. To combine them together, you need a string aggregate concatenation. This is how you would do it in SQL Server:
declare #sql varchar(max);
SELECT #sql = (select 'select '''+COLUMN_NAME+''' AS FieldName, (select cast(MIN('+COLUMN_NAME+') as varchar(8000)) from '+const.tablename + ') union all '
FROM INFORMATION_SCHEMA.COLUMNS c cross join
(select WHATEVER as tablename) const
WHERE c.TABLE_NAME = const.tablename
for xml path('')
);
select #sql = LEFT(#sql, len(#sql) - 9);
exec(#sql);
Use a cross join, which is implicit if you just select from two tables with no join (i.e., from t1, t2):
SELECT COLUMN_NAME AS FieldName,
Table1.MyField
FROM
INFORMATION_SCHEMA.COLUMNS, Table1
WHERE
TABLE_NAME = 'table1'
AND
MyTable.ID = 123
I actually came up with a bit of a crazy solution but it works:
declare #tbl_name as varchar(255)
declare #field as varchar(255)
declare #val as varchar(255)
declare #SQL as nvarchar(4000)
create table #tbl ( [FieldName][varchar](255), [FieldVal][varchar](255))
set #tbl_name = 'table1'
DECLARE mah_cursor CURSOR FAST_FORWARD
FOR
SELECT COLUMN_NAME FROM
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tbl_name
OPEN mah_cursor
FETCH NEXT FROM mah_cursor INTO #field
WHILE ##FETCH_STATUS = 0
BEGIN
set #SQL = 'set #val = (Select top 1 ' + #field + ' from ' + #tbl_name + ')'
print #SQL
exec sp_executesql #query = #SQL, #params = N'#val varchar(255) OUTPUT', #val = #val OUTPUT
insert into #tbl ([FieldName],[FieldVal] ) values (#field, #val)
FETCH NEXT FROM mah_cursor INTO #field
END
CLOSE mah_cursor
DEALLOCATE mah_cursor
select * from #tbl
drop table #tbl
It loops through each value and adds it. The Fast_Forward feature optimizes the query for high performance