Get all UNIQUEIDENTIFIER values based on variables in query - sql

Goal is to get all UNIQUEIDENTIFIER values from all columns in database.
Code which is supposed to load all those values:
DECLARE #TableNames TABLE
(
ID INT NOT NULL IDENTITY(0, 1),
TableName NVARCHAR(50) NOT NULL,
ColName NVARCHAR(50) NOT NULL
);
DECLARE #Guids TABLE
(
ID INT NOT NULL IDENTITY(0, 1),
FoundGuid UNIQUEIDENTIFIER NOT NULL
);
DECLARE #Local NVARCHAR(50);
WHILE #Counter < 500
BEGIN
SELECT #Local = TableName FROM #TableNames WHERE Id = #Counter;
INSERT INTO #Guids EXEC('SELECT Id FROM [' + #Local + ']');
SET #Counter = #Counter + 1;
END;
Is this safe thing to do so? Eventually, what is the way to get those values?

I would use the system views to generate dynamic sql. This is 100% accurate and not limited to only those columns named Id. It won't matter what schema or column name is used. This will get you all those values with no looping at all.
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'select ' + QUOTENAME(c.name) + ' = ' + QUOTENAME(c.name)
+ ' FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name)
+ ' UNION ALL '
from sys.tables t
join sys.columns c on c.object_id = t.object_id
join sys.types ty on ty.user_type_id = c.user_type_id
join sys.schemas s on s.schema_id = t.schema_id
where ty.name = 'uniqueidentifier'
--removes the last UNION ALL
select #SQL = left(#SQL, len(#SQL) - 10)
select #SQL
--uncomment below to execute the dynamic sql when you are comfortable it is correct
--exec sp_executesql #SQL

Related

Need all columns on one row

I wrote the following query:
IF OBJECT_ID ('tempdb..#ColumnsType') IS NOT NULL DROP TABLE #ColumnsType
DECLARE #vQuery NVARCHAR(MAX) =''
IF OBJECT_ID ('tempdb..#random') IS NOT NULL DROP TABLE #random
CREATE TABLE #random (
ColumnID INT PRIMARY KEY IDENTITY(1,1) NOT NULL
, randomname VARCHAR(50)
, randomvalue INT)
INSERT INTO #random (randomname, randomvalue)
VALUES ('a3', 123)
, ('bla', 4325)
, ('another_bla', 5643)
, ('end_here', 3)
select *
from #random
CREATE TABLE #ColumnsType (
ColumnID INT PRIMARY KEY IDENTITY(1,1) NOT NULL
, ColumnName sysname
, DataType sysname
)
INSERT INTO #ColumnsType (ColumnName, DataType)
SELECT [name],
system_type_id
FROM Tempdb.Sys.Columns
WHERE Object_ID = Object_ID('tempdb..#random')
AND system_type_id = 56
DECLARE #i INT = (SELECT MIN(ColumnID) FROM #random);
DECLARE #maxId INT = (SELECT MAX(ColumnID) FROM #random);
DECLARE #ColumnName VARCHAR(200);
DECLARE #DataType VARCHAR(200);
WHILE #i <= #maxId
BEGIN
SET #ColumnName = (SELECT ColumnName FROM #ColumnsType WHERE ColumnId = #i)
-- SET #DataType = (SELECT DataType FROM #ColumnsType WHERE ColumnId = #i)
SELECT #vQuery =
'SELECT
MIN(TRY_CONVERT(NUMERIC(30, 4), ' +#ColumnName+ ')) AS ' +#ColumnName+ '_MinValue
, MAX(TRY_CONVERT(NUMERIC(30, 4), ' +#ColumnName+ ')) AS ' +#ColumnName+ '_MaxValue
, AVG(TRY_CONVERT(NUMERIC(30, 4), ' +#ColumnName+ ')) AS ' +#ColumnName + '_AvgValue
, STDEV(TRY_CONVERT(NUMERIC(30, 4), ' +#ColumnName+ ')) AS ' +#ColumnName+ '_StandardDeviation
, SUM(TRY_CONVERT(NUMERIC(30, 4), ' +#ColumnName+ ')) AS ' +#ColumnName+ '_TotalSum
FROM tempdb..#random' -- +#Schema+'.'+#Table+ ''
EXEC sp_executesql #vQuery
PRINT #vQuery
SET #i = #i + 1
END
For the sake of demonstration I create temp table with random values. I perform profiling on part of the columns which are consisting only of numeric values. To filter the columns I get their names and filter by type, using Tempdb.Sys.Columns. In normal case with my original data, I use INFORMATION_SCHEMA.COLUMNS but I think this is not that important.
The query returns the following:
The result is presented on two rows. What I'd like to do is to have this result on one row. The idea is to pivot the one row result after and to receive the following result:
As I mentioned, you need to not use a loop, use a set based method and UNION ALL your dynamic statements. I assume here, as well, that you are using a recent version of SQL Server. If not, you'll need to replace STRING_AGG with the old FOR XML PATH (and STUFF) method.
This should be enough to get you started:
USE Sandbox;
GO
CREATE TABLE dbo.YourTable (Col1 int,
Col2 varchar(10));
GO
DECLARE #SchemaName sysname = N'dbo',
#TableName sysname = N'YourTable';
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
DECLARE #Delimiter nvarchar(50) = #CRLF + N'UNION ALL' + #CRLF;
SELECT #SQL = STRING_AGG(CONVERT(nvarchar(MAX),N'SELECT MIN(') + QUOTENAME(c.[name]) + N') AS ' + QUOTENAME(c.[name] + N'_MIN') + N',' + #CRLF +
N' MAX(' + QUOTENAME(c.[name]) + N') AS ' + QUOTENAME(c.[name] + N'_MAX') + #CRLF +
N'FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name])
,#Delimiter) WITHIN GROUP (ORDER BY c.column_id)
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
WHERE s.[name] = #SchemaName
AND t.[name] = #TableName
PRINT #SQL;
EXEC sys.sp_executesql #SQL;
GO
DROP TABLE dbo.YourTable;
Here is a very clean and nice solution which is what I was looking for:
I choose the columns, from specific table, scan it once and perform multiple calculations on it
I use dynamic query and make it one statement for all columns.
It works really fast. It took a little over 5 minutes to return result for table with 50 mil rows.
The only thing that is left to do is to UNPIVOT in order to insert results in a table that I want.
DECLARE
#q1 NVARCHAR(MAX)
, #q2 NVARCHAR(MAX)
, #q3 NVARCHAR(500)
, #schema VARCHAR(50) = '' -- choose schema
, #table VARCHAR(200) = '' -- choose table
SET #Q1 = 'SELECT ' + '''' + #table + '''' + ' as tableName, '
SET #Q3 = ' FROM ' + #schema + '.' + #table
SELECT #q2 = COALESCE(#q2 + ', ', '')
+ ' max(' + columnName + ') as ' + columnName + '_max, '
+ ' min(' + columnName + ') as ' + columnName + '_min, '
+ ' avg(' + columnName + ') as ' + columnName + '_avg, '
+ ' stdev(' + columnName + ') as ' + columnName + '_stdev, '
+ ' sum(' + columnName + ') as ' + columnName + '_sum '
FROM (
SELECT s.[name] as schemaName, t.[name] as tableName, c.[name] as columnName, st.[name] as typeName
FROM sys.schemas s
INNER JOIN sys.tables t ON s.schema_id = t.schema_id
INNER JOIN sys.columns c ON t.object_id = c.object_id
INNER JOIN sys.types st ON st.user_type_id = c.user_type_id
WHERE 1=1
AND s.[name] = #schema
AND t.[name] = #table
AND st.[name] IN ('') -- choose columns of specific data type, that you want to profile
) data
SELECT #q1 = #q1 + #q2 + #q3
EXEC sys.sp_executesql #Q1
Enjoy!

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

Sql - Fetch next value to replace variable value

Hi guys my basic sql knowledge needs some help
I want to be able to replace a variable value with a value in a table and keep running the query until the end value in the table is reached
start query
DECLARE #prime_SCHEMA VARCHAR(20)
DECLARE #next_SCHEMA VARCHAR(20)
DECLARE #TABLE_name VARCHAR(100)
DECLARE #SQL VARCHAR(500)
SET #prime_SCHEMA = 'aaa'
SET #next_SCHEMA = 'bbb'
SET #TABLE = 'table1'
SET #sql = 'select top 1 * into '+#next_SCHEMA +'.'+#TABLE_name +' from '+#prime_SCHEMA +'.'+#TABLE_name +' TRUNCATE TABLE '+#next_SCHEMA +'.'+#TABLE_name
print #sql
I now want to wrap this in a Fetch and use a table called 'table_val' to update the TABLE_name value
and loop around till all the rows have been used in the table
so effectively i could end up with multiple #sql statements
thanks
Try this one -
Query:
DECLARE
#prime_schema SYSNAME = 'aaa'
, #next_schema SYSNAME = 'bbb'
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = (
SELECT CHAR(13) + '
SELECT *
INTO [' + #next_schema + '].[' + o.name + ']
FROM [' + s.name + '].[' + o.name + ']
WHERE 1 != 1'
FROM sys.objects o WITH (NOWAIT)
JOIN sys.schemas s WITH (NOWAIT) ON o.[schema_id] = s.[schema_id]
WHERE o.[type] = 'U'
AND s.name = #prime_schema
AND o.name IN ('table1', 'table2', 'table3')
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
PRINT #SQL
Output:
SELECT *
INTO [bbb].[table1]
FROM [aaa].[table1]
WHERE 1 != 1
SELECT *
INTO [bbb].[table2]
FROM [aaa].[table2]
WHERE 1 != 1
SELECT *
INTO [bbb].[table3]
FROM [aaa].[table3]
WHERE 1 != 1

How to get Column value without knowing column name ? SQL Server

I have table name as #Table_Name
I have column value as #Value but don't have the column name (but that exist at 1st position and can be Seek_id or prov_id ...I have to compare my value with this id )
How can I compare that table column name value ?
I want something like
SELECT * FROM #Table_Name
WHERE Table.Column[1].Value = #Value
for example #Table_Name = bb_match and #Value = 6
Possible this be helpful for you -
Query:
IF OBJECT_ID (N'dbo.bb_match') IS NOT NULL
DROP TABLE dbo.bb_match
CREATE TABLE dbo.bb_match (seek_id INT, prov_id INT)
INSERT INTO dbo.bb_match (seek_id, prov_id)
VALUES (6, 1), (2, 6)
DECLARE
#ColumnID TINYINT
, #Value INT
, #TableName SYSNAME
, #SQL NVARCHAR(500)
SELECT
#ColumnID = 1
, #Value = 6
, #TableName = 'dbo.bb_match'
SELECT #SQL = 'SELECT * FROM ' + #TableName + ' WHERE [' + c.name + '] = ' + CAST(#Value AS NVARCHAR(MAX))
FROM sys.objects o WITH (NOWAIT)
JOIN sys.schemas s WITH (NOWAIT) ON o.[schema_id] = s.[schema_id]
JOIN sys.columns c WITH (NOWAIT) ON o.[object_id] = c.[object_id]
WHERE o.[type] = 'U' -- <-- only for tables columns
AND s.name + '.' + o.name = #TableName
AND c.column_id = #ColumnID
PRINT #SQL
EXEC sp_executesql #SQL
Shorter, but unsafe (sys.columns contains column_name for tables, views, procedures, ...):
SELECT #SQL = 'SELECT * FROM ' + #TableName + ' WHERE [' + c.name + '] = ' + CAST(#Value AS NVARCHAR(MAX))
FROM sys.columns c WITH (NOWAIT)
WHERE c.[object_id] = OBJECT_ID(#TableName)
AND c.column_id = #ColumnID
EXEC sys.sp_executesql #SQL
Output:
SELECT * FROM dbo.bb_match WHERE [seek_id] = 6
Results:
seek_id prov_id
----------- -----------
6 1
declare #sql varchar(MAX)
declare #tablename varchar(100) = 'MyTable' --add your table name here
declare #value varchar(100) = 'SomeValue' -- add your desired value hree
select #sql = 'SELECT * FROM ' + #tablename + ' WHERE '
+ name
+ ' = ''' + #value + ''''
from sys.columns where object_id = object_id(#tablename) and column_id = 1
exec (#sql)
There are three parts to this. First I'm declaring three strings. #sql is where I will build up the query, #tablename and #value are the table and search value to look in/for. I've put in the dummy values MyTable and SomeValue to show what I'm talking about
Next I build up the sql statement. The first line sets the string as SELECT * FROM MyTable WHERE
I then add in the column name by selecting Name from the SQL SERver system table sys.columns, filtering on the first column (column_id = 1) and the table name
The next step is to add the value we want to search for in the column.
Finally, EXEC(#sql) interprets the string as a command and runs it.

Dynamic update statement with variable column names

We're looking to do an update in several SQL Server databases to change all NULL values in a certain table to be empty strings instead of NULL. We're potentially going to be doing this across hundreds of databases. The table name will always be the same, but the column names are variable based on how the front-end application is configured (don't judge... I didn't create this system).
Is there a way to do an update on all of these columns without knowing the column names ahead of time?
You can pass the name of the column in dynamic sql:
declare #sql nvarchar (1000);
set #sql = N'update table set ' + #column_name + '= ''''';
exec sp_executesql #sql;
You can look in the sys.columns table and join on the table name or object_id.
DECLARE #OBJ_ID INT
SELECT #OBJ_ID = OBJECT_ID
FROM SYS.tables
WHERE name = 'YOURTABLE'
SELECT * FROM SYS.columns
WHERE OBJECT_ID = #OBJ_ID
You could use the name field from the sys.columns query as a basis to perform the update on.
Assuming you want all columns of varchar/char types only (or change the type filter to whatever you need):
DECLARE #tableName varchar(10)
SET #tableName = 'yourtablenamehere'
DECLARE #sql VARCHAR(MAX)
SET #sql = ''
SELECT #sql = #sql + 'UPDATE ' + #tableName + ' SET ' + c.name + ' = '''' WHERE ' + c.name + ' IS NULL ;'
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
INNER JOIN sys.types y ON c.system_type_id = y.system_type_id
WHERE t.name = #tableName AND y.name IN ('varchar', 'nvarchar', 'char', 'nchar')
EXEC (#sql)
This can be achieved with cursors. You first select the column names like #Darren mentioned, then you Set a Cursor with those values and loop:
Open oColumnsCursor
Fetch Next From oColumnscursor
Into #ColumnName
While ##FETCH_STATUS=0
Begin
Set #oQuery = 'Update [DB]..[Table] Set [' + #ColumnName + '] = ''NewValue'' Where [' + #ColumnName + '] = ''OldValue'''
Execute(#oQuery)
Fetch Next From oColumnscursor Into #ColumnName
Set #oCount = #oCount + 1
End
Close oColumnsCursor;
Deallocate oColumnsCursor;
This will work when you know the Table Name:
DECLARE #tableName varchar(10)
SET #tableName = 'Customers'
DECLARE #sql VARCHAR(MAX)
SET #sql = ''
SELECT #sql = #sql + 'UPDATE ' + #tableName + ' SET ' + c.name + ' = ISNULL('+ c.name +','''');'
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
INNER JOIN sys.types y ON c.system_type_id = y.system_type_id
WHERE y.name IN ('varchar', 'nvarchar', 'char', 'nchar')
AND t.name = #tableName;
EXEC(#sql);
And this will iterate all Tables and all Columns in a Db:
DECLARE #sql VARCHAR(MAX)
SET #sql = ''
SELECT #sql = #sql + 'UPDATE ' + t.name + ' SET ' + c.name + ' = ISNULL('+ c.name +','''');'
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
INNER JOIN sys.types y ON c.system_type_id = y.system_type_id
WHERE y.name IN ('varchar', 'nvarchar', 'char', 'nchar');
EXEC(#sql);
Below is the procedure.
ALTER PROCEDURE [dbo].[util_db_updateRow]
#colval_name NVARCHAR (30), -- column and values e.g. tax='5.50'
#idf_name NVARCHAR (300), -- column name
#idn_name NVARCHAR (300), -- column value
#tbl_name NVARCHAR (100) -- table name
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX)
-- construct SQL
SET #sql = 'UPDATE ' + #tbl_name + ' SET ' + #colval_name +
' WHERE ' + #idf_name + '=' + #idn_name;
-- execute the SQL
EXEC sp_executesql #sql
SET NOCOUNT OFF
RETURN
END
Below is the stored procedure where you can pass Schema Name, Table Name and list of column names separted by comma.It works only in Sql Server 2016 or higher.
CREATE OR ALTER PROCEDURE UpdateData
(#SchemaName NVARCHAR(Max),#TableName NVARCHAR(MAX),#ColumnNames NVARCHAR(MAX))
AS
BEGIN
DECLARE #DynamicSql NVARCHAR(MAX);
SET #DynamicSql = 'UPDATE ' +'[' +#SchemaName+'].' + '[' +#TableName+']' +' SET ' + STUFF((SELECT ', [' + C.name + '] = ' + '''NEW_VALUE'''
FROM sys.columns C
INNER JOIN sys.tables T ON T.object_id = C.object_id
INNER JOIN sys.schemas S ON T.schema_id = S.schema_id
WHERE
T.name = #TableName
AND S.Name = #SchemaName
AND [C].[name] in (SELECT VALUE FROM string_split(#ColumnNames,','))
FOR XML PATH('')), 1,1, '')
print #DynamicSql;
EXEC (#DynamicSql);
END