I'm working on a webapp that displays data from a Microsoft SQL Server dynamic pivot table.
Normally I'd try and figure out a way to do the dynamic pivot in c#, but in this case the pivot has to be a SQL Server stored procedure because other apps also need access to the pivot table.
Here's the SQL:
DECLARE #DynamicPivot AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
SELECT
#ColumnName = ISNULL(#ColumnName + ',', '')
+ QUOTENAME(xml_tag_name)
FROM
(SELECT DISTINCT xml_tag_name FROM DataEntries) AS TagValues
SET #DynamicPivot =
N'SELECT DISTINCT capture_id, ' + #ColumnName + '
FROM DataEntries
PIVOT(MAX(xml_tag_value)
FOR xml_tag_name IN (' + #ColumnName + ')) AS PVTTable'
EXEC sp_executesql #DynamicPivot
All the articles I've gone through deal with normal export to Excel or static pivots. eg: Export Table from SQL Server to Excel 2007 using C#.
How do I go about exporting this dynamic pivot to Excel?
heres a example for you.
It creates dynamic pivot to global temp table and then exports it to excel.
If you find problems with export part - let me know.
CREATE TABLE Table1 (ColId INT,ColName VARCHAR(10))
INSERT INTO Table1 VALUES(1, 'Country')
INSERT INTO Table1 VALUES(2, 'Month')
INSERT INTO Table1 VALUES(3, 'Day')
CREATE TABLE Table2 (tID INT,ColID INT,Txt VARCHAR(10))
INSERT INTO Table2 VALUES (1,1, 'US')
INSERT INTO Table2 VALUES (1,2, 'July')
INSERT INTO Table2 VALUES (1,3, '4')
INSERT INTO Table2 VALUES (2,1, 'US')
INSERT INTO Table2 VALUES (2,2, 'Sep')
INSERT INTO Table2 VALUES (2,3, '11')
INSERT INTO Table2 VALUES (3,1, 'US')
INSERT INTO Table2 VALUES (3,2, 'Dec')
INSERT INTO Table2 VALUES (3,3, '25')
DECLARE #cols NVARCHAR(2000);
SELECT #cols = COALESCE(#cols + ',[' + colName + ']', '[' + colName + ']')
FROM Table1
ORDER BY colName;
IF OBJECT_ID('tempdb..##t1') IS NOT NULL
BEGIN
DROP TABLE ##t1;
END;
DECLARE #query NVARCHAR(4000);
SET #query = N'SELECT tID, ' + #cols + ' into ##t1
FROM
(SELECT t2.tID
, t1.ColName
, t2.Txt
FROM Table1 AS t1
JOIN Table2 AS t2 ON t1.ColId = t2.ColID) p
PIVOT
(
MAX([Txt])
FOR ColName IN
( ' + #cols + ' )
) AS pvt
ORDER BY tID;';
EXECUTE(#query);
SELECT *
FROM ##t1;
DECLARE #sql VARCHAR(MAX);
DECLARE #FileName VARCHAR(MAX) = 'C:\Test.xls';
SET #sql = 'INSERT INTO OPENROWSET(''Microsoft.ACE.OLEDB.12.0'',''Excel 12.0;Database='
+ #FileName + ''',''SELECT * FROM [Sheet1$]'') SELECT * FROM ##T1';
EXECUTE(#sql);
Related
I have a DataSet like below :
Where B1,B2 C1,C2 and C3 are the Column names. G1,G2,S1 and T1 are the first Row elements of my Data Set.
Now i want to combine Similar Columns/ROws in to Group .
Example : Columns B1, B2 and B3 combines to a single group B,
Rows : G1 and G2 Combines together to form a single row G.
Below is the O/P DataSet i need.
I have tried to use Dictionaries and DataSet Loops using but cant get this O/P .
Can anyone help me out with this.
This having to be dynamic adds a huge amount of complexity to this solution. As you haven't responded to the version question, I have not used STRING_AGG, however, if you are using SQL Server 2017+ you can simplify the query to use it.
Firstly, some sample data:
CREATE TABLE dbo.Matrix ([Data] char(2),
B1 tinyint,
B2 tinyint,
C1 tinyint,
C2 tinyint,
C3 tinyint)
INSERT INTO dbo.Matrix ([Data],
B1,
B2,
C1,
C2,
C3)
VALUES('G1',1,1,2,2,4),
('G2',1,1,1,1,1),
('S1',2,1,2,1,1),
('T1',1,3,2,2,3);
GO
Now, if this wasn't dynamic, you could use a a Cross tab to pivot the data into groups, like this:
SELECT LEFT(M.[Data],1) AS [Data],
SUM(CASE V.Col WHEN 'B' THEN V.ColVal END) AS B,
SUM(CASE V.Col WHEN 'C' THEN V.ColVal END) AS C
FROM dbo.Matrix M
CROSS APPLY(VALUES('B',M.B1),
('B',M.B2),
('C',M.C1),
('C',M.C2),
('C',M.C3))V(Col,ColVal)
GROUP BY LEFT(M.[Data],1);
Unfortunately, as it is dynamic then we need dynamic SQL. Honestly, this isn't beginning stuff, and I'm not here to support this SQL; it's up to you to understand it, maintain it, support it, and (because it is dynamic SQL) keep it secure. I'm happy to answer some questions on how it works, but for someone that doesn't knowe SQL well this is a steep learning curve:
DECLARE #SQL nvarchar(MAX);
SET #SQL = N'SELECT LEFT(M.[Data],1) AS [Data],' + NCHAR(13) + NCHAR(10) +
STUFF((SELECT N',' + NCHAR(13) + NCHAR(10) +
N' SUM(CASE V.Col WHEN N' + QUOTENAME(LEFT(C.COLUMN_NAME,1),'''') + N' THEN V.ColVal END) AS ' + QUOTENAME(LEFT(C.COLUMN_NAME,1))
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE C.TABLE_SCHEMA = N'dbo'
AND C.TABLE_NAME = N'Matrix'
AND C.COLUMN_NAME != N'Data' --Assumes that all other columns are applicable
GROUP BY LEFT(C.COLUMN_NAME,1)
ORDER BY LEFT(C.COLUMN_NAME,1)
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,3,N'') + NCHAR(13) + NCHAR(10) +
N'FROM dbo.Matrix M' + NCHAR(13) + NCHAR(10) +
N' CROSS APPLY(VALUES' + STUFF((SELECT ',' + NCHAR(13) + NCHAR(10) +
N' (N' + QUOTENAME(LEFT(C.COLUMN_NAME,1),'''') + N',M.' + QUOTENAME(C.COLUMN_NAME) + N')'
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE C.TABLE_SCHEMA = N'dbo'
AND C.TABLE_NAME = N'Matrix'
AND C.COLUMN_NAME != N'Data' --Assumes that all other columns are applicable
ORDER BY C.COLUMN_NAME
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,26,N'') + N')V(Col,ColVal)' + NCHAR(13) + NCHAR(10) +
N'GROUP BY LEFT(M.[Data],1)' + NCHAR(13) + NCHAR(10) +
N'ORDER BY LEFT(M.[Data],1);';
PRINT #SQL; --Your debugging best friend.
EXEC sp_executesql #SQL;
db<>fiddle
You can apply below logic to get desired output from SQL Server:
create table T_DataSet
(
Data varchar(50),
B1 int,
B2 int,
C1 int,
C2 int,
C3 int
)
INSERT INTO T_DataSet ([Data],B1,B2,C1,C2,C3)
VALUES('G1',1,1,2,2,4),
('G2',1,1,1,1,1),
('S1',2,1,2,1,1),
('T1',1,3,2,2,3);
DECLARE #QUERY VARCHAR(MAX)=''
DECLARE #Columns VARCHAR(MAX)=''
;with tbl_COLUMN_NAME (COLUMN_NAME) AS
(
select name as COLUMN_NAME from sys.all_columns
where object_id = (select object_id from sys.tables where name = 'T_DataSet')
and name <> 'Data'
)
SELECT
#Columns = ISNULL(#Columns +',', '') + T.COLUMN_NAME
FROM
(
select
COLUMN_NAME = 'SUM(' +
(select SUBSTRING(
(
SELECT '+'+ COLUMN_NAME
FROM tbl_COLUMN_NAME
where LEFT(COLUMN_NAME,1) = LEFT(inner_C1.COLUMN_NAME,1)
FOR XML PATH('')
), 2 , 9999))
+ ') AS ' + LEFT(COLUMN_NAME,1)
from tbl_COLUMN_NAME as inner_C1
Group by LEFT(COLUMN_NAME,1)
)T
set #QUERY = 'select LEFT([Data],1) as Data ' + #Columns + '
From T_DataSet
Group by LEFT([Data],1)';
PRINT #QUERY
EXEC(#QUERY)
I have 14 tables of different kinds of employees. I have a C# application which is wired to my SQL Server database and when I type a last name in a textbox it brings back a record with that last name and displays it in a listbox.
However I have managed to do this with only one table. So if I type “Jones” it will bring back and display Jones from one table.
I would like to bring back all the Jones’ from all 14 tables. In other words, when I type a last name, I need the application to show me all records of that last name from all 14 tables.
What would be a reasonable approach to this? It would be a lot easier if I had one table with all employees but I need the seperation. Basically when I click the search button I need the application to go fetch from any of the 14 tables with the given name.
What would be a suitable approach to this?
Define the following stored procedure in your database:
CREATE PROCEDURE GetAll_SP
(
#FirstName VARCHAR(50)
)
AS
BEGIN
(SELECT 1, first_name, last_name FROM UsersTable1 WHERE first_name = #FirstName)
UNION
(SELECT 2, first_name, last_name FROM UsersTable2 WHERE first_name = #FirstName)
UNION
(SELECT 3, first_name, last_name FROM UsersTable3 WHERE first_name = #FirstName)
-- ....
END
GO
or the following one instead of you don't need to have any kind of control over your users location:
CREATE PROCEDURE GetAll_SP
(
#FirstName VARCHAR(50)
)
AS
BEGIN
(SELECT first_name, last_name FROM UsersTable1 WHERE first_name = #FirstName)
UNION ALL
(SELECT first_name, last_name FROM UsersTable2 WHERE first_name = #FirstName)
UNION ALL
(SELECT first_name, last_name FROM UsersTable3 WHERE first_name = #FirstName)
-- ....
END
GO
Then, in your code:
String firstName = "Jones";
using (SqlCommand cmd = new SqlCommand("GetAll_SP", m_Connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar).Value = firstName;
m_Connection.Open();
cmd.ExecuteNonQuery();
}
You should repeat your Code 14 Times to collect values from all this tables or you submit a SQL Query for all 14 Tables at once with unions or 14 queries in one Statement - depending on your Data Access Technology...
Okay, to get results from all 14 tables you can use UNION ALL Operator, so your SQL would look something like:
(SELECT first_name, last_name FROM table1 WHERE first_name='John')
UNION ALL
(SELECT first_name, last_name FROM table2 WHERE first_name='John')
...
(SELECT first_name, last_name FROM table14 WHERE first_name='John')
You need to have equal amount of fields in every select. However better approach would be if you save all names (and any other shared data) in one table, and connect with Key with all those 14 tables that have different dataset. That way you can prevent such a long queries like this one above (and probably slow queries) and query would look more like this:
SELECT first_name, last_name, user_type, user_id WHERE first_name='John'
And then you can retreive fields from corresponding table as field user_type gives you info in which out of 14 tables to search for other data and user_id gives you data of that user, so second query would look something like this:
SELECT job_position, worksheet, other_data FROM tableN WHERE user_id=...
Simply set #SearchStr and every column in every table will be searched.
drop table #results
go
declare #SearchStr nvarchar(100)
set #SearchStr = 'Donna%' -- use wildcards
CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256), #ColumnName nvarchar(128), #SearchStr2 nvarchar(110)
SET #TableName = ''
SET #SearchStr2 = QUOTENAME('%' + #SearchStr + '%','''')
WHILE #TableName IS NOT NULL
BEGIN
SET #ColumnName = ''
SET #TableName =
(
SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > #TableName
AND OBJECTPROPERTY(
OBJECT_ID(
QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
), 'IsMSShipped'
) = 0
)
WHILE (#TableName IS NOT NULL) AND (#ColumnName IS NOT NULL)
BEGIN
SET #ColumnName =
(
SELECT MIN(QUOTENAME(COLUMN_NAME))
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(#TableName, 2)
AND TABLE_NAME = PARSENAME(#TableName, 1)
AND DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar', 'text')
AND QUOTENAME(COLUMN_NAME) > #ColumnName
)
print cast(#TableName as nvarchar(200)) + ' ' + #ColumnName
IF #ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC
(
--'SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630)
--FROM ' + #TableName + ' (NOLOCK) ' +
--' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
'SELECT ''' + #TableName + '.' + #ColumnName + ''', ' + #ColumnName + '
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
I would like to transpose the data from my table and do some plottings into powerBI.
Here is how I feel up my database from my application:
using (SqlCommand cmd = connect.CreateCommand())
{
cmd.CommandText = #"INSERT INTO PoD_NewPriceList_Data
(ID, Product_Barcode, Product_Name,
Store_Price, Internet_Price, InsertDate)
VALUES (#ID, #Product_Barcode, #Product_Name,
#Store_Price, #Internet_Price, #InsertDate)";
cmd.Parameters.Add("Product_Barcode", SqlDbType.NVarChar).Value = barcode;
cmd.Parameters.Add("Product_Name", SqlDbType.NVarChar).Value = PriceList.name;
cmd.Parameters.Add("Store_Price", SqlDbType.Float).Value = Convert.ToDouble(storePrice, CultureInfo.InvariantCulture);
cmd.Parameters.Add("Internet_Price", SqlDbType.Float).Value = Convert.ToDouble(PriceList.price, CultureInfo.InvariantCulture);
cmd.Parameters.Add("InsertDate", SqlDbType.DateTime).Value = InsertDate.AddDays(2);
cmd.Parameters.Add("ID", SqlDbType.Int).Value = barcode.GetHashCode();
result = result && (cmd.ExecuteNonQuery() > 0);
}
And in SQL Server Management Studio here is how my table looks like:
SELECT
[ID], [Product_Barcode], [Product_Name],
[Store_Price], [Internet_Price], [InsertDate]
FROM
[dbo].[PoD_NewPriceList_Data]
and I get the following output:
The main issue is when trying to create the plots as requested in PowerBI I need my data to look as follows:
F5321
Product_Name Sony Xperia...
Store_Price 399
Internet_Price 327.51
InsertDate 2017.04.27
Any help would be well appreciated.
Check and modify this SQL script. I use #t table variable, replace it with your table name [PoD_NewPriceList_Data].
DECLARE #t TABLE (
id int,
product_barcode varchar(max),
product_name varchar(max),
store_price int,
internet_price decimal,
insert_date date
)
INSERT INTO #t VALUES (1,'F5321', 'Sony Xperia', 399, 255.1, '2017-04-25')
INSERT INTO #t VALUES (2,'F5833', 'Sony Xperia XZ', 458, 398.2, '2017-04-26')
INSERT INTO #t VALUES (3,'F5121', 'Sony Xperia XA Rose', 161, 155.6, '2017-04-27')
IF OBJECT_ID ('tempdb..#Unpivoted') IS NOT NULL
DROP TABLE #Unpivoted
IF OBJECT_ID ('tempdb..#Transposed') IS NOT NULL
DROP TABLE #Transposed
/* Unpivot table to get rows instead of columns */
SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as rn
INTO #Unpivoted
FROM (SELECT product_barcode, product_name,
CAST(store_price as varchar(max)) store_price,
CAST(internet_price as varchar(max)) internet_price,
CAST(insert_date as varchar(max)) as insert_date
FROM #t) src
UNPIVOT (
value FOR field IN (
product_barcode, product_name, store_price, internet_price, insert_date
)
) unpiv
CREATE TABLE #Transposed
(Field varchar(50) PRIMARY KEY NOT NULL )
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = STUFF((
SELECT 'ALTER TABLE #Transposed ADD item' +
RIGHT('000' + CAST(sv.number AS VARCHAR(3)), 3) + ' varchar(max) '
FROM [master].dbo.spt_values sv
WHERE sv.[type] = 'p'
AND sv.number BETWEEN 1 AND (SELECT COUNT(*) FROM #t)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 0, '')
Exec(#SQL) /* Dynamically create columns */
INSERT INTO #Transposed (Field) SELECT DISTINCT Field FROM #Unpivoted
/*populate field names*/
DECLARE #fieldCount int = (SELECT COUNT(*) FROM #Transposed)
/* using rn to filter proper record from transposed table */
SELECT #SQL = STUFF((
SELECT '
UPDATE #Transposed SET item' + RIGHT('000' + CAST(sv.number AS VARCHAR(3)), 3)
+ ' = up.value FROM #Transposed t CROSS APPLY
( SELECT TOP 1 u.value FROM #unpivoted u WHERE u.field = t.field AND u.rn > '
+ CAST((sv.number-1)*#fieldCount AS VARCHAR(10)) + ' ORDER BY rn) up '
FROM [master].dbo.spt_values sv
WHERE sv.[type] = 'p'
AND sv.number BETWEEN 1 AND (SELECT COUNT(*) FROM #t)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 0, '')
Exec(#SQL) /*Dynamically fill in values */
SELECT t.* FROM #Transposed t
OUTER APPLY (SELECT TOP 1 rn FROM #Unpivoted u WHERE u.field=t.field) up
ORDER BY up.rn ASC /* add a link to Unpivoted to fix the item order */
DROP TABLE #Unpivoted
DROP TABLE #Transposed
It does what you need in several steps
converts columns to rows with UNPIVOT. Watch that you have to CAST all the values to the exactly same type. Adds a row number to filter the rows in step 3.
creates a temp table with dynamic number of columns corresponding to the number of rows
fills in the columns names into rows into the dynamically created table
fills in values into the dynamically created table
Credits to this answer and this answer.
Of course the number of columns is limited here, so if you try to convert many rows into columns, you get:
Cannot create a row of size 8066 which is greater than the allowable
maximum row size of 8060.
I've got a stored procedure which joins a number of tables to produce a large resultset which is then returned to my application. The application in turn loops through the results and combines rows on a particular ID and chooses data per row to include in a new object. This is perhaps easiest to explain using an example:
Inspection, Desc, Value
1, Description1, 3
1, Description2, 2
1, Description3, 5
This is in code turned into
Inspection, Description1, Description2, Description3
1, 3, 2, 5
The point of this is to have one row per inspection item with item description as headers and value as the cell value for inspection row and header. This is then exported to Excel.
The question is: how do I do this in SQL Server, as in expanding my SP to return a lot fewer but "wider" rows with a lot more columns?
Another complication is that one inspection may have rows which another one lacks, in that case the solution is to add an empty value or a '-'.
P.S. This is using Sql Server 2012.
If you are using mssql 2005+. You can use a pivot like this:
Test data
DECLARE #tbl TABLE(Inspection INT, [Desc] VARCHAR(100),Value INT)
INSERT INTO #tbl
VALUES
(1,'Description1', 3),
(1,'Description2', 2),
(1,'Description3', 5)
Query
SELECT
*
FROM
(
SELECT
tbl.Inspection,
tbl.[Desc],
tbl.Value
FROM
#tbl AS tbl
) AS tbl
PIVOT
(
SUM(Value)
FOR [Desc] IN ([Description1],[Description2],[Description3])
)AS pvt
Result:
Inspection, Description1, Description2, Description3
1 3 2 5
Edit
As juharr said in the comment:
The resulting column names (values in the table) are when building the query. Which might require another initial query to get
Edit 2
If you are not using mssql 2005+. Or want to have and alternitive explanation. Please see the following query:
SELECT
tbl.Inspection,
SUM(CASE WHEN [Desc]='Description1' THEN tbl.Value ELSE 0 END) AS Description1,
SUM(CASE WHEN [Desc]='Description2' THEN tbl.Value ELSE 0 END) AS Description2,
SUM(CASE WHEN [Desc]='Description3' THEN tbl.Value ELSE 0 END) AS Description3
FROM
#tbl AS tbl
GROUP BY
tbl.Inspection
This do not requiere a pivot and can be use on most of RDMS out there
You should use Sql Server Pivot. It converts rows into columns. You can have an easiest start by this example.
If you'd like to do this dynamically, without having to know what all of the Desc values are, you can build your pivot query and use Exec() or Execute sp_executesql
DECLARE #Columns NVARCHAR(MAX),
#Sql NVARCHAR(MAX)
--Build your column headers based on Distinct Desc values
SELECT #Columns = COALESCE(#Columns + ',', '') + QUOTENAME([Desc])
FROM (SELECT DISTINCT [Desc] FROM tbl) t
ORDER BY [Desc]
--Build your pivot query
SET #Sql = '
SELECT
*
FROM
tbl
PIVOT
(
MAX([Value])
FOR [Desc] IN (' + #Columns + ')
) p
'
EXEC(#Sql)
If you want - for null values, you'll need to create another variable to hold the conversion scripts for the Select part of your sql.
DECLARE #Columns NVARCHAR(MAX),
#Sql NVARCHAR(MAX),
#ColumnAliases NVARCHAR(MAX)
--Build your pivot columns based on Distinct Desc values
SELECT #Columns = COALESCE(#Columns + ',', '') + QUOTENAME([Desc])
FROM (SELECT DISTINCT [Desc] FROM tbl) t
ORDER BY [Desc]
--Build your column headers, replacing NULL with -
SELECT #ColumnAliases = COALESCE(#ColumnAliases + ',', '')
+ 'COALESCE(CONVERT(VARCHAR,' + QUOTENAME([Desc]) + '),''-'') AS ' + QUOTENAME([Desc])
FROM (SELECT DISTINCT [Desc] FROM tbl) t
ORDER BY [Desc]
--Build your pivot query
SET #Sql = '
SELECT
Inspection,'
+ #ColumnAliases + '
FROM
tbl
PIVOT
(
MAX([Value])
FOR [Desc] IN (' + #Columns + ')
) p
'
EXEC(#Sql)
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