question

Ahmed Mamdouh avatar image
Ahmed Mamdouh asked

execute dynamic sql from within a Function

I'm creating a function that executes a dynamic sql to **fetch data from another database that is unknown to me and I'm getting the database name by a query**.. of course though the function is created I'm getting "only functions and extended stored procedures can be executed from within a function" error message when calling the function.. **is there any workaround?** ------------------------------------------------ Create Function fn_GetCurrencyDecimalDigits (@currency nvarchar (3)) returns int as begin Declare @Database nvarchar(50) set @Database = (select [Value] from configuration where [Key] = 'database') Declare @Sql nvarchar(max) Set @SqI = N'SELECT CurrDecimalDigit FROM ' + @Database + '..Currency WHERE CurrlSOCode = ''' + @currency + '''' Declare @res int exec sp_executesql @query = @Sql, @params = N’@res int output’, @res = @res output return @res end
t-sqlfunctionsdynamic-sql
1 comment
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Kev Riley avatar image Kev Riley ♦♦ commented ·
is there any particular reason that it has to be within a function?
4 Likes 4 ·
Oleg avatar image
Oleg answered
Using a multiline scalar function is really evil and should be avoided if at all possible. In your case, it would be easy enough to query the Currency table in the specified database only once rather than torture it once for each row in the Products table. How about creating a proc first and then using it to join its results with Products table after whatever records the proc returns are stored in the table variable: create proc dbo.usp_GetCurrencyDecimalDigits as begin; set nocount on; declare @sql nvarchar(max); select @sql = N'select CurrDecimalDigit, CurrlSOCode from ' + [Value] + '..Currency' from configuration where [Key] = 'database'; exec (@sql); set nocount off; end; go Once the procedure is created, you can use it like this (in place of your **select fn\_GetCurrencyDecimalDigits(CurrencyISOCode) from Products** thingy): declare @t table (CurrDecimalDigit int, CurrlSOCode varchar(50)); insert into @t exec dbo.usp_GetCurrencyDecimalDigits; select t.CurrDecimalDigit --, Products.* from Products left join @t t on Products.CurrencyISOCode = t.CurrlSOCode; Oleg
3 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Ahmed Mamdouh avatar image Ahmed Mamdouh commented ·
I'll try this now and get back... thanks a lot
0 Likes 0 ·
Ahmed Mamdouh avatar image Ahmed Mamdouh commented ·
this is it, works like a charm :D:D thanks man for this beautiful solution
0 Likes 0 ·
Pavel Pawlowski avatar image Pavel Pawlowski commented ·
Also solution @oleg and for performance better than using the scalar function. Only depending on the number of records returned I would use a normal temp table instead of table variable and Query optimizer takes a table variable like it contains 1 records. It doesn't use statistics for table variables. So then it can chose wrong join operator in the query plan.
0 Likes 0 ·
WilliamD avatar image
WilliamD answered
As @Kev Riley states, why a function?? If you place the code inside a stored procedure it will do what you want. As the error states, functions cannot execute dynamic sql.
4 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Kev Riley avatar image Kev Riley ♦♦ commented ·
You might even be better off having multiple calls from the application layer, rather than the database having to work out where the config database is
1 Like 1 ·
Ahmed Mamdouh avatar image Ahmed Mamdouh commented ·
Greetings, Unfortunately I can't do that as I want to get a reult for each row of a table.. this is why I created a function to be used like this: select fn_GetCurrencyDecimalDigits(CurrencyISOCode) from Products
0 Likes 0 ·
WilliamD avatar image WilliamD commented ·
I can't understand why you would want to have the schema split this way, so that you have to do a meta-data look-up before the actual function call happened. Wouldn't it make more sense to keep the function inside the same database as the Products table? Just as a side note, calling a function the way you do is also going to have hidden performance problems by calling the function inline. Take a look at the CROSS APPLY and OUTER APPLY commands.
0 Likes 0 ·
Ahmed Mamdouh avatar image Ahmed Mamdouh commented ·
Yes I agree with you, but this is the situation the currency decimal digits table is in a separate database other than the product and I'm working in a massive database .net product so we have to keep things that way :S, even if we had to sacrifice perfomance a little
0 Likes 0 ·
Pavel Pawlowski avatar image
Pavel Pawlowski answered
You can workaround this by creating a static SQL in your function, but instead of using a real database name and table, you will create a Synonym for which will point to the right database and table and use that **table synonym** in your static query . In case the DB name in the future is changed, you only alter the synonym and you are ready.
2 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

WilliamD avatar image WilliamD commented ·
Excellent catch!! +1
0 Likes 0 ·
Ahmed Mamdouh avatar image Ahmed Mamdouh commented ·
very nice approach, but unforunately unapplicable in my deployment scenario as the deployment team distributes the application in different sites with different configuration for each site.. I may implement this solution if all other solutions failed.. Big Thanks anyway :D
0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.