Hello I am having a problem here.
I wanted to read subjectname from a dynamic table name and the save it to a variable.
but i am getting an error
DECLARE #retval varchar(200)
DECLARE #sSQL nvarchar(500);
DECLARE #ParmDefinition nvarchar(500);
DECLARE #academicYear varchar(200) = '20212022';
Declare #subjectId varchar(200) = '202041962';
DECLARE #tablename nvarchar(50) = 'abc' + CAST(#academicyear As varchar)
DECLARE #CONDITION NVARCHAR(128)
SET #CONDITION = 'WHERE [subjectid] = 202041962'
SELECT #sSQL = N'SELECT #retvalOUT = [subjectname] FROM ' + #tablename + #CONDITION;
SET #ParmDefinition = N'#retvalOUT varchar OUTPUT';
EXEC sp_executesql #sSQL, #ParmDefinition, #retvalOUT=#retval OUTPUT;
SELECT #retval;
If you actually looked at the value of #sSQL eg by printing it, you'll note it contains FROM abc20212022WHERE, therefore,
you are not delimiting your table names - use quotename()
you need a space between your table name and the where
you should always specify a length for a varchar value (you don't need to cast a variable when concatenating two strings but you should be consistent with your use of [n]varchar)
using concat to concatenate strings is easier and safer
Related
How do I create variables that are specified once and then used in queries later in a script? These variables may be used multiple times in a query, and in multiple queries in a script. I use #x as such a variable in the examples below.
What I want to do is something like:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ' + #x + ' as [TestCase]
From mytable'
Exec (#Query)
-- returns "Invalid column name 'test'"
Which returns the error mentioned above. I would like it to achieve the equivalent of:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ''test'' as [TestCase]
From mytable'
Exec (#Query)
-- Returns e.g.
-- Name TestCase
-- Alice Test
-- Bob Test
I also note that the following doesn't work and returns the same error as the first:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ' + 'test' + ' as [TestCase]
From mytable'
Exec (#Query)
-- returns "Invalid column name 'test'"
Based on the error and since I'm not trying to use the #x as a column name, but just as a variable, I assume I'm using an invalid implementation of a variable.
Since you're not trying to use a variable as a column name, you do not need to use dynamic SQL at all. (Which is a Good Thing(TM) since dynamic SQL should only be used with a great deal of caution due to it being a great attack surface.)
A simple:
declare #x nvarchar(40)
set #x = 'test'
select [Name], #x as TestCase
from mytable
will do.
That being said, if you have a use case for dynamic SQL (again the particular query in question here does not but perhaps an ad-hoc query is being passed in to the procedure), the thing to do would be to pass your variable as a parameter to the query via sp_executesql. This is akin to creating a stored procedure with parameters:
declare #x nvarchar(40)
declare #query nvarchar(1000)
set #x = 'test'
set #query = 'select [Name], #x as TestCase from mytable'
exec sp_executesql #query, N'#x nvarchar(1000)', #x
You were missing quotes. Thats it. Try below code.
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ''' + #x + ''' as [TestCase]
From mytable'
Exec (#Query)
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name],'++''''+#x+''''+ ' as [TestCase]
From mytable'
print #query
Output:
Select [Name],'test' as [TestCase]
From mytable
This question already has an answer here:
Creating SumIf function in SQL Server 2012
(1 answer)
Closed 7 years ago.
I have the following sql function, but not running correctly, the intended returned value is the total
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Create FUNCTION [dbo].[SumIf](#ColumnName [varchar](100), #Criteria [varchar](500))
RETURNS [decimal] AS
BEGIN
-- Declare the return variable here
DECLARE #Total Decimal
DECLARE #TableName Decimal
Select #Total = SUM(#ColumnName) from #TableName where #Criteria
RETURN #Total
END
the use syntax would be something like
Select dbo.sumif(fees.fee_amount, Fees.Fee_Code ='B01')
So the tablename would also need to be extracted from the columnname variable passed.
I don't think you will be able to implement your function that way. You're essentially trying to pass an expression to the function which I don't think is possible in SQL Server. You may be able to do it with dynamic SQL passing in strings but not as cleanly as you're hoping.
you need dynamic SQL to do this, but unfortunately you can't use dynamic SQL inside a UDF. try this-
DECLARE #ColumnName [nvarchar](100) = '' --fill in values here
DECLARE #TableName [nvarchar](100) = ''
DECLARE #Criteria [nvarchar](500) = ''
DECLARE #s nvarchar(max)
DECLARE #res bigint
set #s = 'SELECT #result = SUM(' + #ColumnName + ') from ' + #TableName + ' where ' + #Criteria
exec sp_executesql #s, N'#result OUTPUT', #result = #res OUTPUT
select #res
You are way on the wrong track. If you wanted to put sumif() in a select statement, it would need to be a user-defined aggregation function, rather than just a user-defined function. The fact that you've declared #TableName to be decimal and then use it in a from clause points to other issues.
So, my suggestion is that you just do this in-line:
select sum(case when <condition> then <columnname> else 0 end) as sumval
from <tablename>
If you wanted a programming block to put the data together, then use a stored procedure. Something like:
Create FUNCTION [dbo].SumIf(#ColumnName varchar(100),
#TableName varchar(255)
#Criteria varchar(500),
#Total Decimal OUTPUT)
) AS
BEGIN
DECLARE #sql nvarchar(max) = 'Select #Total = SUM(#ColumnName) from #TableName where #Criteria';
set #sql = replace(#sql, '#ColumnName', #ColumnName);
set #sql = replace(#sql, '#TableName', #TableName);
set #sql = replace(#sql, '#Criteria', #Criteria);
sp_execute_sql #sql, N'#total decimal output', #total = #total output;
END;
Once more I stumble upon an SQL mishappening. The following code:
create trigger tc_trigger_olt_UPDATE on tick_orderline_type
for update as
declare #UserId varchar(32) --
declare #ClientId varchar(32) --
declare #CaseId varchar(32) --
declare #TableName varchar(64) --Used
declare #RecordId varchar(512) --Used
declare #Descr varchar(128) --
declare #RemoteIP varchar(16) --Used
select #TableName = object_name(parent_id) from sys.triggers where object_id = ##procid
select #RemoteIP = client_net_address from sys.dm_exec_connections where Session_id = ##SPID
if exists(select * from information_schema.columns where table_name = #TableName and column_name = 'id')
begin
select #RecordId = id from inserted
end
declare #sql nvarchar(max)
set #sql = 'select case_id from '+#TableName+' where id = '''+#RecordId+'''';
exec sp_executesql #sql, N'#out_param varchar(32) OUTPUT', #out_param=#CaseId OUTPUT
execute update_tick_orderline_type #UserId, #ClientId, #CaseId, #TableName, #RecordId, #Descr, #RemoteIP
Is used for filling and audit-table in SSMS, which works. It stores which table, which record, on which date and from which IP-Address the table has been edited.
I am currently trying to get which client's data, for which case, has been edited using the following snipped from above:
declare #sql nvarchar(max)
set #sql = 'select case_id from '+#TableName+' where id = '''+#RecordId+'''';
exec sp_executesql #sql, N'#out_param varchar(32) OUTPUT', #out_param=#CaseId OUTPUT
In my Results window (the one that shows select statement results), I can see that the #sql statement has selected the correct case_id; storing it in the #CaseId variable however, returns NULL. Once I have the #CaseId I can get the #ClientId, so I'm stumped here.
Why is the statement outputting the correct case_id, but stores it as NULL?
A little sidenote: the case_id is only being output when the exec statement is present, otherwise it is not
I managed to fix my own predicament, by changing the previous 'select x from #TableName' block, to this:
declare #sql nvarchar(max)
declare #params nvarchar(max)
set #params = N'#iCaseId varchar(max) output'
select #sql = N'select #iCaseId = case_id from '+quotename(#TableName)+
' where id = '''+#RecordId+''''
execute sp_executesql #sql, #params, #CaseId output
What changed?
I declared an additional #params variable, for readability
Instead of set I select-ed the #sql variable
quotename now surrounds the #TableName variable
instead of the last param for sp_executesql being #x = #y output I simply replaced it with #y output
Conclusion
After several tests (mainly removing some of the changes), I can conclude that the last point on that list was key to solving the issue.
With quotename removed from the statement, I still manage to save the result in a variable, and since the #param variable is not mandatory, but rather a personal preference, it also had no real significance.
How do I write a query in SQL where when the string variable is not '' we include the WHERE clause and check where the ID exists in the list or not?
The following does not seem to work.
DECLARE #var varchar(20)
DECLARE #clause varchar(20)
DECLARE #sql varchar(20)
SET #var= '1,2,3'
IF #var <> ''
SET #clause=' WHERE ID IN ('+ #var + ')'
SET #sql='SELECT [ID]
,[SOURCE]
,[LAST_KEY]
FROM [oms].[dbo].[MIGRATION]'
EXEC (#sql + #clause)
Error Message:
Msg 156, Level 15, State 1, Line 2
Incorrect syntax near the keyword 'WHERE'.
Increase your #sql variable's length to MAX like
DECLARE #sql varchar(MAX)
You have defined 20 length which is not enough to store whole query in that variable. Also remove #clause variable and change your code like below. You can also print whole query by print #sql and check what is wrong in that.
DECLARE #var varchar(500)
DECLARE #sql varchar(MAX)
SET #var= '1,2,3'
SET #sql = 'SELECT [ID],
[SOURCE],
[LAST_KEY]
FROM [oms].[dbo].[MIGRATION]'
IF #var IS NOT NULL AND #var <> ''
BEGIN
SET #sql = #sql + ' WHERE ID IN ('+ #var + ')'
END
EXEC (#sql)
This issue is because of length for variable #sql. Please change it from #sql varchar(20) to #sql varchar(max) will resolve your issue.
Below is the code for the same
DECLARE #var varchar(20)
DECLARE #clause varchar(20)
DECLARE #sql varchar(max)
SET #var= '1,2,3'
IF #var <> ''
SET #clause=' WHERE ID IN ('+ #var + ')'
SET #sql='SELECT [ID]
,[SOURCE]
,[LAST_KEY]
FROM [oms].[dbo].[MIGRATION]'
EXEC (#sql + #clause)
my sql statement is something like this below
DECLARE #OLD_NAV_VALUE AS INT
DECLARE #FINAL AS INT
SELECT #OLD_NAV_VALUE = [col1] from TBL_BA where DATE = #id_Date
SET #FINAL = #OLD_NAV_VALUE * 50
But the problem i am haveing here is that the column name in the select statement which is given as [col1] is a dynamic value. So i am trying something like this below.
DECLARE #OLD_NAV_VALUE AS INT
DECLARE #FINAL AS INT
EXEC('SELECT #OLD_NAV_VALUE = [' + #DYNAMIC_COL_NAME + '] from TBL_BA where DATE = ' + #id_Date)
SET #FINAL = #OLD_NAV_VALUE * 50
this gives an error that #OLD_NAV_VALUE has to be declared. So i tried declaring #OLD_NAV_VALUE inside the EXEC statement. But if i do this i am not able to use the same outside the EXEC statement.
Please let me know how to do this.
You can also use the sp_executesql statement with an output parameter:
declare #field nvarchar(50);
set #field = N'FieldToSelect';
declare #sql nvarchar(3000);
declare #parmDefinition nvarchar(500);
SET #parmDefinition = N'#returnValueOUT nvarchar(50) OUTPUT';
set #sql = N'SELECT #ReturnValueOUT = ' + #Field + ' FROM [TableName] WHERE [SomeCondition]'
declare #returnValue nvarchar(50);
EXECUTE sp_executesql #sql, #parmDefinition, #returnValueOut = #returnValue OUTPUT;
SELECT #returnValue
First, I'd suggest that you do a Google on "Erland dynamic SQL" and read his white paper on the subject.
Your design is probably not the best if it requires that you use a dynamic column name like this.
The reason that you can't do what you're trying to do is that everything in the EXEC is entirely in its own scope. If you absolutely have to do it this way though then you could use a table (either a normal table, or a global temporary table) to store the value for use outside of the EXEC.
We've used sp_executesql. Here's another example of a parameterized record count:
DECLARE #sql AS nvarchar(MAX)
SET #sql = N'SELECT #RecordCount = COUNT(*) FROM [{#SchemaName}].[{#TableName}]'
SET #sql = REPLACE(#sql, '{#SchemaName}', #SchemaName)
SET #sql = REPLACE(#sql, '{#TableName}', #TableName)
DECLARE #RecordCount AS int
EXEC sp_executesql
#query = #sql,
#params = N'#RecordCount INT OUTPUT',
#RecordCount = #RecordCount OUTPUT
This worked for me.
I declared a temp table and used it to receive the values from the select statement.
Something like below.
declare #i int
declare #v int
create table #t (val int)
insert into #t
exec ('declare #i int set #i = 0 select #i+1')
select * from #t