Get column names in SQL server that satisfy a where condition on data - sql

I just had a random doubt while working with SQL-server to which i thought i could get it clarified here.
Say- i have a condition that i want to find out all the column names in the database which satisfy my where condition on data.
Example:-
There are some 20-30 tables in a SQL-Server DB.Now all i need is a query to find out the list of column names which have "Ritesh" as a data field in them.
I don't know if it is really possible in the first place.
I hope i am clear. Please, any help will be most appreciated.
Thank You.
Ritesh.

This should work, but be aware, this will take a while to execute in large databases. I have assumed that the search string might be just a part of the data contained and am using wildcards. I feel this is purely academic, as I am unable to imagine a scenario, where this will be required.
--you need to iterate the whole columns of entire table to find the matched record
--another thing is that you need dynamic sql to find the table name
DECLARE #Value varchar(50) --value for that find the column Name
SET #Value = 'Ritesh'
CREATE TABLE #Table
(
TableName Varchar(500),ColumnName Varchar(500),
Id int Identity(1,1) --use for iteration
)
CREATE TABLE #Results
(
TableName varchar(500),
ColumnName varchar(500)
)
INSERT INTO #Table
SELECT
TABLE_SCHEMA + '.' + TABLE_NAME AS TableNam,
Column_name AS ColumnName
FROM INFORMATION_SCHEMA.COLUMNS
WHERE Data_type IN ('char', 'nchar', 'varchar', 'nvarchar')
--change the datatype based on the datatype of sample data you provide
-- also remember to change the wildcard, if the input datatype is not a string
DECLARE #Count Int --total record to iterated
SET #Count = 0;
SELECT
#Count = COUNT(*)
FROM #Table
DECLARE #I int --initial value one to iterate
SET #I = 1;
DECLARE #TableName varchar(500)
SET #TableName = ''
DECLARE #ColumnName varchar(500)
SET #ColumnName = ''
DECLARE #Str nvarchar(1000)
SET #Str = ''
DECLARE #param nvarchar(1000)
SET #param = ''
DECLARE #TableNameFound varchar(max)
SET #TableNameFound = ''
DECLARE #Found bit
SET #Found = 0;
WHILE #I<=#Count
BEGIN
SET #Found = 0;
SELECT
#TableName = TableName,
#ColumnName = ColumnName
FROM #Table
WHERE Id = #I;
SET #param = '#TableName varchar(500),#ColumnName varchar(500),#Value varchar(50),#TableNameFound varchar(max),#Found bit output'
SET #str = 'Select #Found=1 From ' + #TableName + ' where ' + #ColumnName + ' Like ' + '''' + '%' + #Value + '%' + ''''
-- here we are using tablename and actual value to find in table
EXEC sp_executesql #str,
#param,
#TableName,
#ColumnName,
#Value,
#TableNameFound,
#Found OUTPUT
IF #Found=1
BEGIN
INSERT INTO #Results (TableName, ColumnName)
SELECT
#TableName,
#ColumnName
END
--increment value of #I
SET #I = #I + 1;
END
--Display Results
SELECT * FROM #Results
--Clean Up
DROP TABLE #Table
DROP TABLE #Results

Related

Verify all columns can convert from varchar to float

I have tried a bunch of different ways like using cursors and dynamic SQL, but is there a fast way to verify that all columns in a given table can convert from varchar to float (without altering the table)?
I want to get a print out of which columns fail and which columns pass.
I am trying this method now but it is slow and cannot get the list of columns that pass or error out.
drop table users;
select *
into users_1
from users
declare #cols table (i int identity, colname varchar(100))
insert into #cols
select column_name
from information_schema.COLUMNS
where TABLE_NAME = 'users'
and COLUMN_NAME not in ('ID')
declare #i int, #maxi int
select #i = 1, #maxi = MAX(i) from #cols
declare #sql nvarchar(max)
while(#i <= #maxi)
begin
select #sql = 'alter table users_1 alter column ' + colname + ' float NULL'
from #cols
where i = #i
exec sp_executesql #sql
select #i = #i + 1
end
I found this code on one of the SQL tutorials sites.
Why all the drop/create/alter nonsense? If you just want to know if a column could be altered, why leave your table in a wacky state, where the columns that can be altered are altered, and the ones that can't just raise errors?
Here's one way to accomplish this with dynamic SQL (and with some protections):
DECLARE #tablename nvarchar(513) = N'dbo.YourTableName';
IF OBJECT_ID(#tablename) IS NOT NULL
BEGIN
DECLARE #sql nvarchar(max) = N'SELECT ',
#tmpl nvarchar(max) = N'[Can $colP$ be converted?]
= CASE WHEN EXISTS
(
SELECT 1 FROM ' + #tablename + N'
WHERE TRY_CONVERT(float, COALESCE($colQ$,N''0'')) IS NULL
)
THEN ''No, $colP$ cannot be coverted''
ELSE ''Yes, $colP$ CAN be converted'' END';
SELECT #sql += STRING_AGG(
REPLACE(REPLACE(#tmpl, N'$colQ$',
QUOTENAME(name)), N'$colP$', name), N',')
FROM sys.columns
WHERE object_id = OBJECT_ID(#tablename)
AND name <> N'ID';
EXEC sys.sp_executesql #sql;
END
Working db<>fiddle
This is never going to be "fast" - there is no great shortcut to having to read and validate every value in the table.

Html output of a stored procedure into a table or variable

I have a stored procedure dbo.someprocedure which takes input as sql query and returns Html table format.
Exec someprocedure 'Select * from dbo.Table'
This html I would like to insert into a table or a variable so that I can perform few changes on the result html.
I tried using
Declare #variable varchar(max)
Exec #variable = someprocedure 'Select * from dbo.Table'
it is executing but returning 0 the variable is not assigned.
Thanks in advance, looking for your answer.
I found an alternative procedure, which served my purpose.
CREATE PROC [dbo].[spQueryToHtmlTable]
(
#query nvarchar(MAX),
#orderBy nvarchar(MAX) = NULL,
#html nvarchar(MAX) = NULL OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
IF #orderBy IS NULL BEGIN
SET #orderBy = ''
END
SET #orderBy = REPLACE(#orderBy, '''', '''''');
DECLARE #realQuery nvarchar(MAX) = '
DECLARE #headerRow nvarchar(MAX);
DECLARE #cols nvarchar(MAX);
SELECT * INTO #dynSql FROM (' + #query + ') sub;
SELECT #cols = COALESCE(#cols + '', '''''''', '', '''') + ''['' + name + ''] AS ''''td''''''
FROM tempdb.sys.columns
WHERE object_id = object_id(''tempdb..#dynSql'')
ORDER BY column_id;
SET #cols = ''SET #html = CAST(( SELECT '' + #cols + '' FROM #dynSql ' + #orderBy + ' FOR XML PATH(''''tr''''), ELEMENTS XSINIL) AS nvarchar(max))''
EXEC sys.sp_executesql #cols, N''#html nvarchar(MAX) OUTPUT'', #html=#html OUTPUT
SELECT #headerRow = COALESCE(#headerRow + '''', '''') + ''<th>'' + name + ''</th>''
FROM tempdb.sys.columns
WHERE object_id = object_id(''tempdb..#dynSql'')
ORDER BY column_id;
SET #headerRow = ''<tr>'' + #headerRow + ''</tr>'';
SET #html = ''<table border="1">'' + #headerRow + #html + ''</table>'';
';
EXEC sys.sp_executesql #realQuery, N'#html nvarchar(MAX) OUTPUT', #html=#html OUTPUT
END
GO
DECLARE #html nvarchar(MAX);
EXEC spQueryToHtmlTable #html = #html OUTPUT, #query = N'SELECT * FROM sometable';
#html contains the html output so that u can perform your operations on the html reformatting
example:
select #htmlTable = Concat('<html>
<style>
table {
border-collapse: collapse;
width: 50%;
}
td, th {
border: 1px solid #B8B8B8;
text-align: left;
padding: 8px;
}
thead {
color:white;
}
</style>
<body>
<table>
<tr>
<th bgcolor="#B8B8B8">col1</th>
<th bgcolor="#B8B8B8">col2</th>
<th bgcolor="#B8B8B8">col3</th>
</tr>',substring(#html,charindex('</tr>',#html,1)+5,len(#html)),'</body></html>')
thanks for your answers.
What #SeanLange said is right. If you want to use SQL stored procedure to convert SQL table into HTML, you must use output when you execute SQL stored procedure.
For example - my table:
Create stored procedure
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[CustomTable2HTMLv4]
(#TSQL_QUERY NVARCHAR(4000),
#OUTPUT NVARCHAR(MAX) OUTPUT,
#TBL_STYLE NVARCHAR(1024) = '',
#ALIGNMENT INT = 0)
AS
-- #exec_str stores the dynamic SQL Query
DECLARE #exec_str NVARCHAR(MAX)
-- #ParmDefinition stores the parameter definition for the dynamic SQL
DECLARE #ParmDefinition NVARCHAR(500)
IF #ALIGNMENT = 0
BEGIN
-- We need to use dynamic SQL at this point so we can expand the input table name parameter
SET #exec_str = N'DECLARE #exec_str NVARCHAR(MAX)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #DEBUG INT
SET #DEBUG = 0
IF #DEBUG=1 Print ''Table2HTML -Horizontal alignment''
-- Make a copy of the original table adding an indexing column. We need to add an index column to the table to facilitate sorting so we can maintain the
-- original table order as we iterate through adding HTML tags to the table columns.
-- New column called CustColHTML_ID (unlikely to be used by someone else!)
--
select CustColHTML_ID=0,* INTO #CustomTable2HTML FROM (' + #TSQL_QUERY + ') SUB
IF #DEBUG=1 PRINT ''Created temporary custom table''
--Now alter the table to add the auto-incrementing index. This will facilitate row finding
DECLARE #COUNTER INT
SET #COUNTER=0
UPDATE #CustomTable2HTML SET #COUNTER = CustColHTML_ID=#COUNTER+1
IF #DEBUG=1 PRINT ''Added counter column to custom table''
-- #HTMLROWS will store all the rows in HTML format
-- #ROW will store each HTML row as fields on each row are iterated through
-- using dynamic SQL and a cursor
-- #FIELDS will store the header row for the HTML Table
DECLARE #HTMLROWS NVARCHAR(MAX) DECLARE #FIELDS NVARCHAR(MAX)
SET #HTMLROWS='''' DECLARE #ROW NVARCHAR(MAX)
-- Create the first HTML row for the table (the table header). Ignore our indexing column!
SELECT #FIELDS=COALESCE(#FIELDS, '' '','''')+''<td>'' + name + ''</td>''
FROM tempdb.sys.Columns
WHERE object_id=object_id(''tempdb..#CustomTable2HTML'')
AND name not like ''CustColHTML_ID''
SET #FIELDS=#FIELDS + ''</tr>''
IF #DEBUG=1 PRINT ''table fields: '' + #FIELDS
-- #ColumnName stores the column name as found by the table cursor
-- #maxrows is a count of the rows in the table, and #rownum is for marking the
-- ''current'' row whilst processing
DECLARE #ColumnName NVARCHAR(500)
DECLARE #maxrows INT
DECLARE #rownum INT
--Find row count of our temporary table
SELECT #maxrows=count(*) FROM #CustomTable2HTML
--Create a cursor which will look through all the column names specified in the temporary table
--but exclude the index column we added (CustColHTML_ID)
DECLARE col CURSOR FOR
SELECT name FROM tempdb.sys.Columns
WHERE object_id=object_id(''tempdb..#CustomTable2HTML'')
AND name not like ''CustColHTML_ID''
ORDER BY column_id ASC
--For each row, generate dynamic SQL which requests the each column name in turn by
--iterating through a cursor
SET #rowNum=1
SET #ParmDefinition=N''#ROWOUT NVARCHAR(MAX) OUTPUT,#rowNum_IN INT''
While #rowNum <= #maxrows
BEGIN
SET #HTMLROWS=#HTMLROWS + ''<tr>''
OPEN col
FETCH NEXT FROM col INTO #ColumnName
IF #DEBUG=1 Print ''#ColumnName: '' + #ColumnName
WHILE ##FETCH_STATUS=0
BEGIN
--Get nth row from table
--SET #exec_str=''SELECT #ROWOUT=(select top 1 ['' + #ColumnName + ''] from (select top '' + cast(#rownum as varchar) + '' * from #CustomTable2HTML order by CustColHTML_ID ASC) xxx order by CustColHTML_ID DESC)''
SET #exec_str=''SELECT #ROWOUT=(select ['' + #ColumnName + ''] from #CustomTable2HTML where CustColHTML_ID=#rowNum_IN)''
IF #DEBUG=1 PRINT ''#exec_str: '' + #exec_str
EXEC sp_executesql
#exec_str,
#ParmDefinition,
#ROWOUT=#ROW OUTPUT,
#rowNum_IN=#rownum
IF #DEBUG=1 SELECT #ROW as ''#Row''
SET #HTMLROWS =#HTMLROWS + ''<td>'' + IsNull(#ROW,'''') + ''</td>''
FETCH NEXT FROM col INTO #ColumnName
END
CLOSE col
SET #rowNum=#rowNum +1
SET #HTMLROWS=#HTMLROWS + ''</tr>''
END
SET #OUTPUT=''''
IF #maxrows>0
SET #OUTPUT= ''<table ' + #TBL_STYLE + '>'' + #FIELDS + #HTMLROWS + ''</table>''
DEALLOCATE col
'
END
ELSE
BEGIN
--This is the SQL String for table columns to be aligned on
--the vertical. So we select a table column, and then iterate
--through all the rows for that column, this forming one row
--of our html table.
SET #exec_str= N'
DECLARE #exec_str NVARCHAR(MAX)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #DEBUG INT
SET #DEBUG=0
IF #DEBUG=1 Print ''Table2HTML -Vertical alignment''
--Make a copy of the original table adding an indexing column.
--We need to add an index column to the table to facilitate sorting
--so we can maintain the original table order as we iterate through
--adding HTML tags to the table fields.
--
--New column called CustColHTML_ID (unlikely to be used by someone
--else!)
select CustColHTML_ID=0,* INTO #CustomTable2HTML FROM (' + #TSQL_QUERY + ') SUB
IF #DEBUG=1 PRINT ''CustomTable2HTMLv2: Modfied temporary table''
--Now alter the table to add the auto-incrementing index.
--This will facilitate row finding
DECLARE #COUNTER INT
SET #COUNTER=0
UPDATE #CustomTable2HTML SET #COUNTER = CustColHTML_ID=#COUNTER+1
-- #HTMLROWS will store all the rows in HTML format
-- #ROW will store each HTML row as fields on each row are iterated
-- through using dynamic SQL and a cursor
DECLARE #HTMLROWS NVARCHAR(MAX)
DECLARE #ROW NVARCHAR(MAX)
SET #HTMLROWS=''''
-- #ColumnName stores the column name as found by the table cursor
-- #maxrows is a count of the rows in the table
DECLARE #ColumnName NVARCHAR(500)
DECLARE #maxrows INT
--Find row count of our temporary table
--This is used here purely to see if we have any data to output
SELECT #maxrows=count(*) FROM #CustomTable2HTML
--Create a cursor which will iterate through all the column names
--in the temporary table (excepting the one we added above)
DECLARE col CURSOR FOR
SELECT name FROM tempdb.sys.Columns
WHERE object_id=object_id(''tempdb..#CustomTable2HTML'')
AND name not like ''CustColHTML_ID''
ORDER BY column_id ASC
--For each **HTML** row, we need to for each iterate through
--each table column as the outer loop.
--Once the column name is identified, we use Coalesc to
--combine all the column values into a single string.
SET #ParmDefinition=N''#COLOUT NVARCHAR(MAX) OUTPUT''
OPEN col
FETCH NEXT FROM col INTO #ColumnName
WHILE ##FETCH_STATUS=0
BEGIN
--Using current column name, grab all column values and
--combine into an HTML cell string using COALESCE
SET #ROW=''''
SET #exec_str='' SELECT #COLOUT=COALESCE(#COLOUT + ''''</td>'''','''''''') + ''''<td>'''' + Cast(IsNull(['' + #ColumnName + ''],'''''''') as nvarchar(max)) from #CustomTable2HTML ''
IF #DEBUG=1 PRINT ''#exec_str: '' + #exec_str
EXEC sp_executesql
#exec_str,
#ParmDefinition,
#COLOUT=#ROW OUTPUT
SET #HTMLROWS =#HTMLROWS + ''<tr>'' + ''<td>'' + #ColumnName + ''</td>'' + #ROW + ''</tr>''
IF #DEBUG=1 SELECT #ROW as ''Current Row''
IF #DEBUG=1 SELECT #HTMLROWS as ''HTML so far..''
FETCH NEXT FROM col INTO #ColumnName
END
CLOSE col
SET #OUTPUT=''''
IF #maxrows>0
SET #OUTPUT= ''<table ' + #TBL_STYLE + '>'' + #HTMLROWS + ''</table>''
DEALLOCATE col
'
END
DECLARE #ParamDefinition nvarchar(max)
SET #ParamDefinition=N'#OUTPUT NVARCHAR(MAX) OUTPUT'
--Execute Dynamic SQL. HTML table is stored in #OUTPUT
--which is passed back up (as it's a parameter to this SP)
EXEC sp_executesql #exec_str,
#ParamDefinition,
#OUTPUT=#OUTPUT OUTPUT
RETURN 1
Execute stored procedure:
DECLARE #HTML1 NVARCHAR(MAX)
DECLARE #HTML2 NVARCHAR(MAX)
EXEC dbo.CustomTable2HTMLv4 'select * from StarWars',#HTML1 OUTPUT,'class="horizontal"',0
EXEC dbo.CustomTable2HTMLv4 'select * from StarWars',#HTML2 OUTPUT,'class="vertical"',1
SELECT #HTML1+#HTML2

How to store a dynamic SQL result in a variable in T-SQL?

I have a stored procedure which takes 'table name' as parameter. I want to store my 'exec' results to a variable and display using that variable.
Here is my T-SQL stored procedure..
create procedure DisplayTable( #tab varchar(30))
as
begin
Declare #Query VARCHAR(30)
set #Query='select * from ' +#tab
EXEC (#Query)
END
I want to do something like this..
SET #QueryResult = EXEC (#Query)
select #QueryResult
How do i achieve this.. Please help.. I am a beginner..
You can use XML for that. Just add e.g. "FOR XML AUTO" at the end of your SELECT. It's not tabular format, but at least it fulfills your requirement, and allows you to query and even update the result. XML support in SQL Server is very strong, just make yourself acquainted with the topic. You can start here: http://technet.microsoft.com/en-us/library/ms178107.aspx
alter procedure DisplayTable(
#tab varchar(30)
,#query varchar(max) output
)
as
BEGIN
Declare #execution varchar(max) = 'select * from ' +#tab
declare #tempStructure as table (
pk_id int identity
,ColumnName varchar(max)
,ColumnDataType varchar(max)
)
insert into
#tempStructure
select
COLUMN_NAME
,DATA_TYPE
from
INFORMATION_SCHEMA.columns
where TABLE_NAME= #tab
EXEC(#execution)
declare #ColumnCount int = (SELECT count(*) from #tempStructure)
declare #counter int = 1
while #counter <= #ColumnCount
BEGIN
IF #counter = 1
BEGIN
set #query = (SELECT ColumnName + ' ' + ColumnDataType FROM #tempStructure where pk_id= #counter)
END
IF #counter <> 1
BEGIN
set #query = #query + (SELECT ',' + ColumnName + ' ' + ColumnDataType FROM #tempStructure where #counter = pk_id)
END
set #counter = #counter + 1
END
END
When you execute the SP, you'll now get a return of the structure of the table you want.
This should hopefully get you moving.
If you want the table CONTENTS included, create yourself a loop for the entries, and append them to the #query parameter.
Remember to delimit the #query, else when you read it later on, you will not be able to restructure your table.
First of all you have to understand that you can't just store the value of a SELECTon a table in simple variable. It has to be TABLE variable which can store the value of a SELECTquery.
Try the below:
select 'name1' name, 12 age
into MyTable
union select 'name2', 15 union
select 'name3', 19
--declaring the table variable and selecting out of it..
declare #QueryResult table(name varchar(30), age int)
insert #QueryResult exec DisplayTable 'MyTable'
select * from #QueryResult
Hope this helps!

how to execute query foreach cell in a database

I need to replace whitespace with NULL in every cell in my database. SQL server 2008 r2. I'm looking for something efficient, but looks like cursor is only way?
First find all tables and columns that are Nullable and of type CHAR or VARCHAR, using INFORMATION_SCHEMA:
SELECT TABLE_NAME, COLUMN_NAME
FROM MyDatabase.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND IS_NULLABLE = 'YES'
Cursors are NEVER the answer :)
ypercube did the hard part. You need to take that info and iterate through it, executing an update statement for each column in each table. You can do that using a WHILE statement. Here is an UNTESTED example of how you could do this:
--Set database to use
USE [MyDatabase];
GO
--Create table variable to hold table/column pairs
DECLARE #table TABLE (
[Key] BIGINT PRIMARY KEY IDENTITY (1, 1),
[TABLE_NAME] VARCHAR(100),
[COLUMN_NAME] VARCHAR(100)
);
--Populate table variable
INSERT INTO #table ([TABLE_NAME], [COLUMN_NAME])
SELECT [TABLE_NAME], [COLUMN_NAME]
FROM MyDatabase.INFORMATION_SCHEMA.COLUMNS
WHERE [TABLE_SCHEMA] = 'dbo'
AND [IS_NULLABLE] = 'YES';
--Initialize counting variables
DECLARE #counter BIGINT = 1;
DECLARE #max BIGINT = (SELECT COUNT(1) FROM #table);
--Iterate through each pair
WHILE #counter <= #max
BEGIN
--Assign the current pair values to variables
DECLARE #TableName VARCHAR(100), #ColumnName VARCHAR(100);
SELECT #TableName = [TABLE_NAME], #ColumnName = [COLUMN_NAME]
FROM #table
WHERE [Key] = #counter;
--Execute dynamic SQL
EXEC
(
'UPDATE [' + #TableName + ']' +
'SET [' + #ColumnName + '] = NULL' +
'WHERE RTRIM([' + #ColumnName + ']) = '''';'
);
--Increment the counter
SET #counter = #counter + 1;
END
I guess it depends on how you define whitespace. Will the following work?
update mytable set mycolumn = null where len(rtrim(ltrim(mycolumn))) = 0

How can I update all empty string fields in a table to be null?

I have a table with 15 columns ( 10 of them are string value) and about 50000 rows.
It contain a lot empty string value ... I search if is there a query that I can pass a table name for it to iterate all values and if it equal empty then update it to NULL ..
UPDATE mytable
SET col1 = NULLIF(col1, ''),
col2 = NULLIF(col2, ''),
...
this is a simple way to do it based on table. just pass the proc the table names. you can also make a sister proc to loop thought table names and call this proc inside the while loop to work on each table in your loop logic.
CREATE PROC setNullFields
(#TableName NVARCHAR(100))
AS
CREATE TABLE #FieldNames
(
pk INT IDENTITY(1, 1) ,
Field NVARCHAR(1000) NULL
);
INSERT INTO #FieldNames
SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #TableName
DECLARE #maxPK INT;
SELECT #maxPK = MAX(PK) FROM #FieldNames
DECLARE #pk INT;
SET #pk = 1
DECLARE #dynSQL NVARCHAR(1000)
WHILE #pk <= #maxPK
BEGIN
DECLARE #CurrFieldName NVARCHAR(100);
SET #CurrFieldName = (SELECT Field FROM #FieldNames WHERE PK = #pk)
-- update the field to null here:
SET #dynSQL = 'UPDATE ' + #TableName + ' SET ' + #CurrFieldName + ' = NULLIF('+ #CurrFieldName+ ', '''' )'
EXEC (#dynSQL)
SELECT #pk = #pk + 1
END