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
Related
I am trying to execute this query:
declare #tablename varchar(50)
set #tablename = 'test'
select * from #tablename
This produces the following error:
Msg 1087, Level 16, State 1, Line 5
Must declare the table variable "#tablename".
What's the right way to have the table name populated dynamically?
For static queries, like the one in your question, table names and column names need to be static.
For dynamic queries, you should generate the full SQL dynamically, and use sp_executesql to execute it.
Here is an example of a script used to compare data between the same tables of different databases:
Static query:
SELECT * FROM [DB_ONE].[dbo].[ACTY]
EXCEPT
SELECT * FROM [DB_TWO].[dbo].[ACTY]
Since I want to easily change the name of table and schema, I have created this dynamic query:
declare #schema sysname;
declare #table sysname;
declare #query nvarchar(max);
set #schema = 'dbo'
set #table = 'ACTY'
set #query = '
SELECT * FROM [DB_ONE].' + QUOTENAME(#schema) + '.' + QUOTENAME(#table) + '
EXCEPT
SELECT * FROM [DB_TWO].' + QUOTENAME(#schema) + '.' + QUOTENAME(#table);
EXEC sp_executesql #query
Since dynamic queries have many details that need to be considered and they are hard to maintain, I recommend that you read: The curse and blessings of dynamic SQL
Change your last statement to this:
EXEC('SELECT * FROM ' + #tablename)
This is how I do mine in a stored procedure. The first block will declare the variable, and set the table name based on the current year and month name, in this case TEST_2012OCTOBER. I then check if it exists in the database already, and remove if it does. Then the next block will use a SELECT INTO statement to create the table and populate it with records from another table with parameters.
--DECLARE TABLE NAME VARIABLE DYNAMICALLY
DECLARE #table_name varchar(max)
SET #table_name =
(SELECT 'TEST_'
+ DATENAME(YEAR,GETDATE())
+ UPPER(DATENAME(MONTH,GETDATE())) )
--DROP THE TABLE IF IT ALREADY EXISTS
IF EXISTS(SELECT name
FROM sysobjects
WHERE name = #table_name AND xtype = 'U')
BEGIN
EXEC('drop table ' + #table_name)
END
--CREATES TABLE FROM DYNAMIC VARIABLE AND INSERTS ROWS FROM ANOTHER TABLE
EXEC('SELECT * INTO ' + #table_name + ' FROM dbo.MASTER WHERE STATUS_CD = ''A''')
Use:
CREATE PROCEDURE [dbo].[GetByName]
#TableName NVARCHAR(100)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #sSQL nvarchar(500);
SELECT #sSQL = N'SELECT * FROM' + QUOTENAME(#TableName);
EXEC sp_executesql #sSQL
END
You can't use a table name for a variable. You'd have to do this instead:
DECLARE #sqlCommand varchar(1000)
SET #sqlCommand = 'SELECT * from yourtable'
EXEC (#sqlCommand)
You'll need to generate the SQL content dynamically:
declare #tablename varchar(50)
set #tablename = 'test'
declare #sql varchar(500)
set #sql = 'select * from ' + #tablename
exec (#sql)
Use sp_executesql to execute any SQL, e.g.
DECLARE #tbl sysname,
#sql nvarchar(4000),
#params nvarchar(4000),
#count int
DECLARE tblcur CURSOR STATIC LOCAL FOR
SELECT object_name(id) FROM syscolumns WHERE name = 'LastUpdated'
ORDER BY 1
OPEN tblcur
WHILE 1 = 1
BEGIN
FETCH tblcur INTO #tbl
IF ##fetch_status <> 0
BREAK
SELECT #sql =
N' SELECT #cnt = COUNT(*) FROM dbo.' + quotename(#tbl) +
N' WHERE LastUpdated BETWEEN #fromdate AND ' +
N' coalesce(#todate, ''99991231'')'
SELECT #params = N'#fromdate datetime, ' +
N'#todate datetime = NULL, ' +
N'#cnt int OUTPUT'
EXEC sp_executesql #sql, #params, '20060101', #cnt = #count OUTPUT
PRINT #tbl + ': ' + convert(varchar(10), #count) + ' modified rows.'
END
DEALLOCATE tblcur
You need to use the SQL Server dynamic SQL:
DECLARE #table NVARCHAR(128),
#sql NVARCHAR(MAX);
SET #table = N'tableName';
SET #sql = N'SELECT * FROM ' + #table;
Use EXEC to execute any SQL:
EXEC (#sql)
Use EXEC sp_executesql to execute any SQL:
EXEC sp_executesql #sql;
Use EXECUTE sp_executesql to execute any SQL:
EXECUTE sp_executesql #sql
Declare #tablename varchar(50)
set #tablename = 'Your table Name'
EXEC('select * from ' + #tablename)
Also, you can use this...
DECLARE #SeqID varchar(150);
DECLARE #TableName varchar(150);
SET #TableName = (Select TableName from Table);
SET #SeqID = 'SELECT NEXT VALUE FOR ' + #TableName + '_Data'
exec (#SeqID)
Declare #fs_e int, #C_Tables CURSOR, #Table varchar(50)
SET #C_Tables = CURSOR FOR
select name from sysobjects where OBJECTPROPERTY(id, N'IsUserTable') = 1 AND name like 'TR_%'
OPEN #C_Tables
FETCH #C_Tables INTO #Table
SELECT #fs_e = sdec.fetch_Status FROM sys.dm_exec_cursors(0) as sdec where sdec.name = '#C_Tables'
WHILE ( #fs_e <> -1)
BEGIN
exec('Select * from ' + #Table)
FETCH #C_Tables INTO #Table
SELECT #fs_e = sdec.fetch_Status FROM sys.dm_exec_cursors(0) as sdec where sdec.name = '#C_Tables'
END
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 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.
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
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);