Thanks for the feedback, but I was hoping for help with an UPDATE command, not SELECT.
Can anyone help with the syntax for an UPDATE command?
I am passing a table name into a Stored Procedure but the SQL does not seem to recognize it.
DECLARE #userTable AS VARCHAR(200);
SET #userTable = #currTable
UPDATE #userTable
SET [lang_String] = #lang_String, [date_Changed] = #submitDate1
WHERE (ID = #ID)
#currTable is passed into the Stored Procedure. All tables names are built by design in code.
You can't, you need to build the entire SQL string and then execute it, like this for example:
DECLARE #sql nvarchar(4000)
SELECT #sql = ' SELECT col1, col2, col3 ' +
' FROM dbo.' + quotename(#tblname) +
' WHERE keycol = #key'
EXEC sp_executesql #sql, N'#key varchar(10)', #key
Got this to work quite easily....
#myTable varchar(150)
/* Comments:
*/
AS
SET NOCOUNT ON;
DECLARE #sql varchar(max);
SET #sql = 'SELECT [ID], [StringID], [GUID] FROM ' + #myTable + ' ORDER BY [GUID]';
print (#sql)
EXECUTE(#sql);
SET #langTable = Null;
FYI, the values available for myTable are stored in another table and are not available to users for edit. Table names are built dynamically in code based on a unique combination of values.
Related
I need help with a piece of code in a stored procedure that returns a dataset to a .NET app containing a variable set of columns--standard columns, plus user-defined columns. My code creates a temp table to hold the dataset and appends the custom columns. The issue I'm having is with the population of these custom columns. (By the way, my code needs to be compatible with Microsoft SQL Server 2008 R2).
I want to use dynamic SQL to put together an Update statement that updates the values of the custom columns in a temp table using SQL snippets stored in a lookup table.
For example, a user might want a custom field that contains an employee's name concatenated a certain way (e.g. "Last Name, First Name"), so the SQL snippet for the custom field would be "LastName + ', ' + FirstName" to concatenate the FistName and LastName fields in the temp table. That's easy. The hard part is when the custom field needs to get populated using a variable passed into the sproc, say to create a unique ID (e.g. The SQL snippet for the custom field is 'Inc_' + CAST(MONTH(#PayrollDate) AS VARCHAR)' to get something like 'Inc_10' if the input parameter #PayrollDate is '10/15/17').
Are still with me? Good, let's do some SQL.
Let's assume we have a temp table with our standard fields and then append a couple of custom fields, as follows (please don't pay attention to my alter table method; in my real sproc, I use dynamic SQL to append the fields, based on saved values in a lookup table).
-- 1. Create the temp table with the standard fields
IF OBJECT_ID('tempdb..#MyTempTable') IS NOT NULL
DROP TABLE #MyTempTable
CREATE TABLE #MyTempTable (
EmpID VARCHAR(50),
FirstName VARCHAR(100),
LastName VARCHAR(100),
EarningsValue MONEY)
-- 2. Add sample earnings data to the temp table
INSERT INTO #MyTempTable (EmpID,FirstName,LastName,EarningsValue) VALUES('1234','Tom','Jones',525.50)
INSERT INTO #MyTempTable (EmpID,FirstName,LastName,EarningsValue) VALUES('4455','Mary','Smith',800.25)
INSERT INTO #MyTempTable (EmpID,FirstName,LastName,EarningsValue) VALUES('9876','Aaron','Lee',200.00)
-- 3. Add the custom fields to the temp table
ALTER TABLE #MyTempTable ADD EmployeeName VARCHAR(100)
ALTER TABLE #MyTempTable ADD BatchID VARCHAR(50)
I know of two methods to execute dynamic SQL to populate my custom fields. The method that works partway is the EXEC(#SQL) method, where you do something like this:
DECLARE #SQL VARCHAR(1000), #CustomField VARCHAR(50), #SQLSnippet VARCHAR(500)
SELECT #CustomField = 'EmployeeName', #SQLSnippet = 'LastName + '','' + FirstName'
SET #SQL = 'UPDATE #MyTempTable SET ' + #CustomField + ' = ' + #SQLSnippet
EXEC(#SQL)
If you were to do PRINT #SQL instead of EXEC(#SQL), you would get:
UPDATE #MyTempTable SET EmployeeName = LastName + ',' + FirstName
If I do SELECT * FROM #MyTempTable, I'll see my 'EmployeeName' custom field populated just fine.
The other dynamic SQL method to use is sp_executesql. However, if I try to do my UPDATE, I get NOTHING, because the it doesn't recognize #CustomField in my SET statement.
DECLARE #NSQL NVARCHAR(1000), #CustomField NVARCHAR(50), #SQLSnippet NVARCHAR(500)
SELECT #CustomField = 'EmployeeName', #SQLSnippet = 'LastName + '','' + FirstName'
SET #NSQL = 'UPDATE #MyTempTable SET #CustomField = #SQLSnippet'
EXECUTE sp_executesql #NSQL,N'#CustomField NVARCHAR(50), #SQLSnippet NVARCHAR(500)',#CustomField,#SQLSnippet
If I do PRINT #NSQL, I get UPDATE #MyTempTable SET #CustomField = #SQLSnippet. Obviously, that doesn't look good, but theoretically the values passed into the #CustomField and #SQLSnippet fields should work, shouldn't it?
At this point, you're thinking, "Steve, why don't you use the EXEC(#SQL) method and forget the sp_executesql nonsense?" Ah, but there's a catch.
In the case where I need to use dynamic SQL using a variable in the SQL snippet, the EXEC(#SQL) method fails. It complains with 'Must declare the scalar variable "#PayrollDate"'. Really? Yeah, really. Here, try it...
DECLARE #SQL VARCHAR(1000), #CustomField VARCHAR(50), #SQLSnippet VARCHAR(500), #PayrollDate SMALLDATETIME
SET #PayrollDate = '10/15/17'
SELECT #CustomField = 'BatchID', #SQLSnippet = '''INC_'' + CAST(MONTH(#PayrollDate) AS VARCHAR)'
SET #SQL = 'UPDATE #MyTempTable SET ' + #CustomField + ' = ' + #SQLSnippet
EXEC(#SQL)
From what I've researched online, only sp_executesql works with parameters in the dynamic SQL. However, I still don't get any results using it. Here's the dynamic SQL using sp_executesql:
DECLARE #NSQL NVARCHAR(1000), #CustomField NVARCHAR(50), #SQLSnippet NVARCHAR(500), #PayrollDate SMALLDATETIME
SET #PayrollDate = '10/15/17'
SELECT #CustomField = 'BatchID', #SQLSnippet = '''INC_'' + CAST(MONTH(#PayrollDate) AS VARCHAR)'
SET #NSQL = 'UPDATE #MyTempTable SET #CustomField = #SQLSnippet'
EXECUTE sp_executesql #NSQL, N'#CustomField NVARCHAR(50),#SQLSnippet NVARCHAR(500),#PayrollDate SMALLDATETIME',#CustomField,#SQLSnippet,#PayrollDate
If you do a SELECT * FROM #MyTempTable, the BatchID custom field is NULL. Grrrr!
So how do I get the blanking dynamic SQL to work properly? Do I use the EXEC(#SQL) method or the sp_executesql method, and how? Much appreciated!
In order to Insert the data into a column, first you need to ADD the column (with its datatype) to the table and because ALTER and UPDATE cannot be in the same batch you will have to use sp_executesql twice. So below is the query which will accomplish what you want.
DECLARE #NSQL NVARCHAR(1000),#ALTSQL NVARCHAR(1000), #CustomField NVARCHAR(50), #CustomFieldDataType NVARCHAR(50), #SQLSnippet NVARCHAR(500), #PayrollDate SMALLDATETIME
SET #PayrollDate = '10/15/17'
SELECT #CustomField = 'BatchID', #CustomFieldDataType = ' NVARCHAR(50)', #SQLSnippet = '''INC_'' + CAST(MONTH(#PayrollDate) AS VARCHAR)'
SET #ALTSQL = 'ALTER TABLE #MyTempTable ADD '+ #CustomField + #CustomFieldDataType
SET #NSQL = 'UPDATE #MyTempTable SET '+ #CustomField +' = '+ #SQLSnippet
EXECUTE sp_executesql #ALTSQL, N'#CustomField NVARCHAR(50), #CustomFieldDataType NVARCHAR(50)',#CustomField, #CustomFieldDataType
EXECUTE sp_executesql #NSQL, N'#CustomField NVARCHAR(50), #SQLSnippet NVARCHAR(500),#PayrollDate SMALLDATETIME',#CustomField, #SQLSnippet,#PayrollDate
SELECT * FROM #MyTempTable
RE:
sp_executeSQL - you cannot pass a column name as a variable. If you want to the column name to come from a variable, you need dynamically construct the query string:
SET #NSQL = 'UPDATE #MyTempTable SET ' + #CustomField + ' = #SQLSnippet'
EXECUTE sp_executesql #NSQL, N'#PayrollDate SMALLDATETIME, #SQLSnippet NVARCHAR(500)',#PayrollDate, #SQLSnippet
What your original query was doing is assigning the values in variable #SQLSnippet to variable #CustomField.
try this
DECLARE #SQL VARCHAR(1000), #CustomField VARCHAR(50), #SQLSnippet VARCHAR(500), #PayrollDate smalldatetime
SET #PayrollDate = '10/15/17'
SELECT #CustomField = 'BatchID', #SQLSnippet = '''INC_' + CAST(MONTH(#PayrollDate) AS VARCHAR)+''''
SET #SQL = 'UPDATE #MyTempTable SET ' + #CustomField + ' = ' + #SQLSnippet
exec(#SQL)
this seems like it should be extraordinarily simple, so I apologize in advance if this information is easily accessible on the transact-sql documentation pages. I searched myself, but couldn't seem to find anything.
I'm trying to modify a transact-sql statement that currently runs on our Windows server 2000 box. I want to check if a table in another database exists, and then do a bunch of stuff. The database name is given as a string argument, '#dbName'
CREATE PROCEDURE CopyTables
#dbName char(4)
AS
IF EXISTS (SELECT * FROM #dbName.INFORMATION_SCHEMA.TABLES WHERE
TABLE_NAME = N'MainTable')
BEGIN
--Do Stuff
In it's current state, it doesn't like using the bare #dbName variable within the select statement. Is there special syntax for doing this?
Thanks in advance.
The below code should do what you want. As was mentioned previously, the account running the query would need the privilege to query the INFORMATION_SCHEMAs in the target database.
To future-proof your stored procedure, I'd also suggest increasing the length of the database name parameter and declaring it as an nchar or nvarchar in stead of char.
CREATE PROCEDURE CopyTables
#dbName char(4)
AS
DECLARE
#SQLStr nvarchar (max),
#Params nvarchar (max),
#Count tinyint;
SET
#Count = 0;
SET #SQLStr = N'SELECT #qCount = 1 FROM [' + #dbName + N'].INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N''MainTable''';
SET #Params = N'#qdbName char (4), #qCount tinyint OUTPUT';
EXECUTE sp_executesql #SQLStr, #Params, #qdbName = #dbName, #qCount = #Count OUTPUT;
IF #Count = 1
BEGIN
--Do Stuff
END; -- if
GO
Try doing the following:
DECLARE #dbName NVARCHAR(MAX) = 'master', #TableName NVARCHAR(MAX) = N'spt_monitor';
DECLARE #sql NVARCHAR(MAX) = N'SELECT * FROM [' + #dbName + N'].INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''' + REPLACE(#TableName,N'''',N'''''') + N'''';
SET NOCOUNT OFF;
EXEC(#sql);
IF ##ROWCOUNT > 0 BEGIN;
-- DO STUFF
SELECT NULL;
END;
There are a few shortcomings to this solution:
1) It requires that the user executing the statement has SELECT access to the other database's INFORMATION_SCHEMA.TABLES
2) It has the side-effect of actually selecting the rows, so if you're using a reader to access the results, you'll have to call reader.NextResult() or await reader.NextResultAsync() because it actually outputs the results of the SELECT statement, rather than doing it in an IF EXISTS context.
By merging the two solutions, we get this:
DECLARE #dbName NVARCHAR(MAX) = 'master', #TableName NVARCHAR(MAX) = N'spt_monitor';
DECLARE #sql NVARCHAR(MAX) = N'SELECT #count = COUNT(*) FROM [' + #dbName + N'].INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''' + REPLACE(#TableName,N'''',N'''''') + N'''';
DECLARE #Count INT;
EXECUTE sp_executesql #sql, N'#Count INT OUTPUT', #Count OUTPUT;
IF #Count > 0 BEGIN;
-- Do stuff
SELECT 'the table exists';
END ELSE BEGIN;
-- Do stuff
SELECT 'the table does not exist';
END;
This solution requires that the user executing the statement has SELECT access to the other database's INFORMATION_SCHEMA.TABLES, but it does not have the side-effect of selecting rows, like my previous solution.
In a stored procedure I pass a table name as the input variable.
I want to return the number of rows of this table with that stored procedure.
I tried something like this but it did not work:
declare #maxRowCount bigint
exec('set '+ #maxRowCount + ' =(select COUNT(1) from ' + #tableName + ')')
This is SQL Server 2008.
You can try this
CREATE PROCEDURE dbo.sp_selectcount
#tablename NVARCHAR(200)
AS
DECLARE #cmd NVARCHAR (255)
SET #cmd = 'SELECT count(*) from ' + #tablename
EXEC sp_executesql #cmd
The following example should give you something to work with.
-- fully qualify your table name (this is probably an input value in your sproc?)
-- please note that I use system view master.sys.tables as an example table here
DECLARE #tablename NVARCHAR(MAX) = N'[master].[sys].[tables]';
-- build the sql statement that you will execute
DECLARE #sql NVARCHAR(MAX) = N'SELECT COUNT(*) FROM ' + #tablename;
-- create a variable to hold the number of rows later on
DECLARE #nrofrows BIGINT;
-- create a temp table to store the result of executing the sql statement
CREATE TABLE #temp (NrOfRows BIGINT);
-- insert the result of the execution of the sql statement into the temp table
INSERT INTO #temp
EXECUTE(#sql);
-- extract the number of rows from the temp table
SET #nrofrows = (SELECT NrOfRows FROM #temp);
-- check the result so you can test!
PRINT #nrofrows;
If you want good background information on dynamic SQL, check out Erland Sommarskogs article The Curse and Blessings of Dynamic SQL.
You should remove the quotes around #maxRowCount.
Try this:
declare #maxRowCount bigint
exec('set #maxRowCount =(select COUNT(*) from ' + #tableName + ')')
OR
exec('SELECT #maxRowCount = COUNT(*) from ' + #tableName)
Analysis:
With the query you tried, it will execute:
set blablabla = (select count(1) from MyTable)
By removing the quotes:
set #maxRowCount = (select count(*) from MyTable)
You can try this instead.
declare #maxRowCount bigint(5)
exec('SELECT COUNT(*) INTO #maxRowCount FROM ' + #tableName)
create procedure sp_First
#columnname varchar
AS
begin
select #columnname from Table_1
end
exec sp_First 'sname'
My requirement is to pass column names as input parameters.
I tried like that but it gave wrong output.
So Help me
You can do this in a couple of ways.
One, is to build up the query yourself and execute it.
SET #sql = 'SELECT ' + #columnName + ' FROM yourTable'
sp_executesql #sql
If you opt for that method, be very certain to santise your input. Even if you know your application will only give 'real' column names, what if some-one finds a crack in your security and is able to execute the SP directly? Then they can execute just about anything they like. With dynamic SQL, always, always, validate the parameters.
Alternatively, you can write a CASE statement...
SELECT
CASE #columnName
WHEN 'Col1' THEN Col1
WHEN 'Col2' THEN Col2
ELSE NULL
END as selectedColumn
FROM
yourTable
This is a bit more long winded, but a whole lot more secure.
No. That would just select the parameter value. You would need to use dynamic sql.
In your procedure you would have the following:
DECLARE #sql nvarchar(max) = 'SELECT ' + #columnname + ' FROM Table_1';
exec sp_executesql #sql, N''
Try using dynamic SQL:
create procedure sp_First #columnname varchar
AS
begin
declare #sql nvarchar(4000);
set #sql='select ['+#columnname+'] from Table_1';
exec sp_executesql #sql
end
go
exec sp_First 'sname'
go
This is not possible. Either use dynamic SQL (dangerous) or a gigantic case expression (slow).
Create PROCEDURE USP_S_NameAvilability
(#Value VARCHAR(50)=null,
#TableName VARCHAR(50)=null,
#ColumnName VARCHAR(50)=null)
AS
BEGIN
DECLARE #cmd AS NVARCHAR(max)
SET #Value = ''''+#Value+ ''''
SET #cmd = N'SELECT * FROM ' + #TableName + ' WHERE ' + #ColumnName + ' = ' + #Value
EXEC(#cmd)
END
As i have tried one the answer, it is getting executed successfully but while running its not giving correct output, the above works well
You can pass the column name but you cannot use it in a sql statemnt like
Select #Columnname From Table
One could build a dynamic sql string and execute it like EXEC (#SQL)
For more information see this answer on dynamic sql.
Dynamic SQL Pros and Cons
As mentioned by MatBailie
This is much more safe since it is not a dynamic query and ther are lesser chances of sql injection . I Added one situation where you even want the where clause to be dynamic . XX YY are Columns names
CREATE PROCEDURE [dbo].[DASH_getTP_under_TP]
(
#fromColumnName varchar(10) ,
#toColumnName varchar(10) ,
#ID varchar(10)
)
as
begin
-- this is the column required for where clause
declare #colname varchar(50)
set #colname=case #fromUserType
when 'XX' then 'XX'
when 'YY' then 'YY'
end
select SelectedColumnId from (
select
case #toColumnName
when 'XX' then tablename.XX
when 'YY' then tablename.YY
end as SelectedColumnId,
From tablename
where
(case #fromUserType
when 'XX' then XX
when 'YY' then YY
end)= ISNULL(#ID , #colname)
) as tbl1 group by SelectedColumnId
end
First Run;
CREATE PROCEDURE sp_First #columnname NVARCHAR(128)--128 = SQL Server Maximum Column Name Length
AS
BEGIN
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT ' + #columnname + ' FROM Table_1'
EXEC(#query)
END
Second Run;
EXEC sp_First 'COLUMN_Name'
Please Try with this.
I hope it will work for you.
Create Procedure Test
(
#Table VARCHAR(500),
#Column VARCHAR(100),
#Value VARCHAR(300)
)
AS
BEGIN
DECLARE #sql nvarchar(1000)
SET #sql = 'SELECT * FROM ' + #Table + ' WHERE ' + #Column + ' = ' + #Value
--SELECT #sql
exec (#sql)
END
-----execution----
/** Exec Test Products,IsDeposit,1 **/
I'm trying to create a simple stored procedure to count the number of empty records in my database:
CREATE PROCEDURE dbo.cnt_empty
#col NVARCHAR(10)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
SELECT COUNT(#col) AS cnt
FROM dbo.mytable
WHERE #col = ''
END
GO
EXECUTE dbo.cnt_empty #col = N'field1' -- nvarchar(10)
I returns 0 for all the columsn I tested. What is wrong with this procedure?
Your string is not being assessed as the column name, so you are actually running "where 'field1' = ''"
You need to do something like this
set #sql = 'select #cnt = COUNT(*) from [' + #tableSchema + '].[' + #tableName +
'] where [' + #columnName + '] is not null';
-- print #sql; --uncomment for debugging
exec sp_executesql #sql, N'#cnt bigint output', #cnt = #cnt output;
Look at http://blog.hoegaerden.be/2009/02/15/script-find-all-empty-columns-in-database/ for the full script.
By doing this, your SQL statement is treating the parameter like a string, not like the name of a column. Take a look at sp_executesql. That will help you build up a SQL string and execute it.
you are matching #col (i.e. 'field1') against empty (i.e. '') in your where clause - that will never return a row.
What you want to do is declare a variable like #sql VARCHAR(500)
Then do
SET #sql = 'SELECT COUNT('+#col+') AS cnt FROM dbo.mytable'
Then try use the built in sp called sp_Executesql
http://msdn.microsoft.com/en-us/library/ms188001.aspx
This is because you are selecting the count of the variable not the count of the column.
Take a look at this article: http://www.mssqltips.com/sqlservertip/1160/execute-dynamic-sql-commands-in-sql-server/
Basically using EXEC statement or sp_executesql should be your choice.