I am using an openquery to get my data. Because of the length of my query which exceeds 8000 characters, I am using this approach :
DECLARE #myStatement VARCHAR(MAX)
SET #myStatement 'SELECT * FROM Employee...'
EXECUTE (#myStatement) AT [MyLinkedServer]
Knowing that it is not possible to use variables in a view, I am trying to use a User Defined function that returns a table like below :
CREATE FUNCTION dbo.EmployeeDetailsForHR
(#myStatement VARCHAR(MAX))
RETURNS TABLE
AS RETURN(EXECUTE (#myStatement) AT [MyLinkedServer]);
SELECT *
FROM dbo.EmployeeDetailsForHR('SELECT * FROM Employee...');
But my CREATE FUNCTION isn't correct. What is the correct syntax in my case?
Related
I have created the following User Defined Function :
CREATE FUNCTION MyTable
(
#dd_YearNo INT,
#txt_WeekNoFrom INT,
#txt_WeekNoTo INT,
#dd_Group VARCHAR(MAX),
#dd_Team VARCHAR(MAX),
#dd_SalesPerson NVARCHAR(MAX)
)
RETURNS TABLE
AS
RETURN
SELECT *
FROM T1 (NOLOCK)
WHERE YearNo IN (#dd_YearNo)
AND (WeekNo BETWEEN #txt_WeekNoFrom AND #txt_WeekNoTo )
AND LEFT(Team,2) IN (#dd_Group)
AND Team IN (#dd_Team)
AND SalesPerson IN(#dd_SalesPerson)
I am using it as a my data set n SSRS like below :
How to map the parameters I created for my SSRS package to this user defined query. This is waht I get since I validate it :
These are the parameters I am using in my SSRS package and I am getting them from different queries :
I get the following error :
Invalid Object MyTable
This question already has answers here:
Alter a SQL server function to accept new optional parameter
(3 answers)
Closed 4 years ago.
I have a stored procedure that looks like this:
CREATE FUNCTION [my_schema].[isEligible]
(#product NUMERIC(8))
RETURNS INT
AS
BEGIN
DECLARE #result INT;
/* do eligibility checking, setting #result */
RETURN #result;
END;
This is referenced in several existing queries similar to this:
SELECT *
FROM person
WHERE my_schema.isEligible(?) > -1 -- negative numbers are eligibility error codes
Where ? is the parameter for a given product id.
In one of the several queries that call the function, I need to pass in a new additional parameter, #exception. I want to have the function behave by default like it did before, and only change behavior for the one call that will be passing in a value for #exception, so I have added the new parameter like so:
CREATE FUNCTION [my_schema].[isEligible]
(#product NUMERIC(8),
#exception CHAR(1) = 'N')
RETURNS INT
AS
BEGIN
DECLARE #result INT;
/*
do eligibility checking (conditionally accounting for
#exception being 'Y'), and setting #result
*/
RETURN #result;
END;
But when I deploy the new version of the function and run a query which only passes in #product I'm getting An insufficient number of arguments were supplied for the procedure or function [my_schema].[isEligible]. I thought that adding = 'N' would provide a default value and avoid this issue.
I read here that sometimes this generic sounding error is actually hiding other errors which aren't allowed to bubble up, but I don't know if that's the case, since it's talking about procedures and this is a function. Not sure if there's a difference or if functions don't support optional arguments like procedures.
I'd love to not have to pass in NULL for the new parameter if possible, which would simplify the rollout of the updated version of the function. Is there a way to do call this function both like isEligible(?) and isEligible(?, ?) or do I need the first one to be isEligible(?, NULL) for it to work?
You could call your function as:
SELECT *
FROM person
WHERE my_schema.isEligible(?, default) > -1
and:
SELECT *
FROM person
WHERE my_schema.isEligible(?, value) > -1
I have seen a similar post here but my situation is slightly different from anything I've found so far. I am trying to call a postgres function with parameters that I can leverage in the function logic as they pertain to the jsonb query. Here is an example of the query I'm trying to recreate with parameters.
SELECT *
from edit_data
where ( "json_field"#>'{Attributes}' )::jsonb #>
'{"issue_description":"**my description**",
"reporter_email":"**user#generic.com**"}'::jsonb
I can run this query just fine in PGAdmin but all my attempts thus far to run this inside a function with parameters for "my description" and "user#generic.com" values have failed. Here is a simple example of the function I'm trying to create:
CREATE OR REPLACE FUNCTION get_Features(
p1 character varying,
p2 character varying)
RETURNS SETOF edit_metadata AS
$BODY$
SELECT * from edit_metadata where ("geo_json"#>'{Attributes}' )::jsonb #> '{"issue_description":**$p1**, "reporter_email":**$p2**}'::jsonb;
$BODY$
LANGUAGE sql VOLATILE
COST 100
ROWS 1000;
I know that the syntax is incorrect and I've been struggling with this for a day or two. Can anyone help me understand how to best deal with these double quotes around the value and leverage a parameter here?
TIA
You could use function json_build_object:
select json_build_object(
'issue_description', '**my description**',
'reporter_email', '**user#generic.com**');
And you get:
json_build_object
-----------------------------------------------------------------------------------------
{"issue_description" : "**my description**", "reporter_email" : "**user#generic.com**"}
(1 row)
That way there's no way you will input invalid syntax (no hassle with quoting strings) and you can swap the values with parameters.
Is it mandatory to pass input parameters for all the user defined functions?
We know, Stored procedure has both input and output parameters.
Function has only input parameters.
We can write a stored procedure without using these parameters too..
Is it possible to write the user defined function without input parameter?
Yes you can definitely write User defined function without parameter.
One more thing I want to clarify that function may have input parameter and it has return value. Return value would be scalar or table depend on type of function you are creation.
Why ask if it is possible when you can just type a few lines and see that it is possible ;-)
CREATE FUNCTION dbo.NoParamsUDF()
RETURNS NVARCHAR(50)
AS
BEGIN
RETURN N'It worked!';
END;
GO
CREATE FUNCTION dbo.NoParamsTVF()
RETURNS TABLE
AS RETURN
SELECT dbo.NoParamsUDF() AS [DidItWork?];
GO
SELECT * FROM dbo.NoParamsTVF();
Returns:
DidItWork?
-------------
It worked!
CREATE FUNCTION dbo.NoParamsUDF()
RETURNS VARCHAR(50)
AS
BEGIN
RETURN N'It worked!';
END;
GO
CREATE FUNCTION dbo.NoParamsTVF()
RETURNS TABLE
AS RETURN
SELECT dbo.NoParamsUDF() AS [DidItWork?];
GO
SELECT * FROM dbo.NoParamsTVF();
I want to generate some XML in a stored procedure based on data in a table.
The following insert allows me to add many nodes but they have to be hard-coded or use variables (sql:variable):
SET #MyXml.modify('
insert
<myNode>
{sql:variable("#MyVariable")}
</myNode>
into (/root[1]) ')
So I could loop through each record in my table, put the values I need into variables and execute the above statement.
But is there a way I can do this by just combining with a select statement and avoiding the loop?
Edit I have used SELECT FOR XML to do similar stuff before but I always find it hard to read when working with a hierarchy of data from multiple tables. I was hoping there would be something using the modify where the XML generated is more explicit and more controllable.
Have you tried nesting FOR XML PATH scalar valued functions?
With the nesting technique, you can brake your SQL into very managable/readable elemental pieces
Disclaimer: the following, while adapted from a working example, has not itself been literally tested
Some reference links for the general audience
http://msdn2.microsoft.com/en-us/library/ms178107(SQL.90).aspx
http://msdn2.microsoft.com/en-us/library/ms189885(SQL.90).aspx
The simplest, lowest level nested node example
Consider the following invocation
DECLARE #NestedInput_SpecificDogNameId int
SET #NestedInput_SpecificDogNameId = 99
SELECT [dbo].[udfGetLowestLevelNestedNode_SpecificDogName]
(#NestedInput_SpecificDogNameId)
Let's say had udfGetLowestLevelNestedNode_SpecificDogName had been written without the FOR XML PATH clause, and for #NestedInput_SpecificDogName = 99 it returns the single rowset record:
#SpecificDogNameId DogName
99 Astro
But with the FOR XML PATH clause,
CREATE FUNCTION dbo.udfGetLowestLevelNestedNode_SpecificDogName
(
#NestedInput_SpecificDogNameId
)
RETURNS XML
AS
BEGIN
-- Declare the return variable here
DECLARE #ResultVar XML
-- Add the T-SQL statements to compute the return value here
SET #ResultVar =
(
SELECT
#SpecificDogNameId as "#SpecificDogNameId",
t.DogName
FROM tblDogs t
FOR XML PATH('Dog')
)
-- Return the result of the function
RETURN #ResultVar
END
the user-defined function produces the following XML (the # signs causes the SpecificDogNameId field to be returned as an attribute)
<Dog SpecificDogNameId=99>Astro</Dog>
Nesting User-defined Functions of XML Type
User-defined functions such as the above udfGetLowestLevelNestedNode_SpecificDogName can be nested to provide a powerful method to produce complex XML.
For example, the function
CREATE FUNCTION [dbo].[udfGetDogCollectionNode]()
RETURNS XML
AS
BEGIN
-- Declare the return variable here
DECLARE #ResultVar XML
-- Add the T-SQL statements to compute the return value here
SET #ResultVar =
(
SELECT
[dbo].[udfGetLowestLevelNestedNode_SpecificDogName]
(t.SpecificDogNameId)
FROM tblDogs t
FOR XML PATH('DogCollection') ELEMENTS
)
-- Return the result of the function
RETURN #ResultVar
END
when invoked as
SELECT [dbo].[udfGetDogCollectionNode]()
might produce the complex XML node (given the appropriate underlying data)
<DogCollection>
<Dog SpecificDogNameId="88">Dino</Dog>
<Dog SpecificDogNameId="99">Astro</Dog>
</DogCollection>
From here, you could keep working upwards in the nested tree to build as complex an XML structure as you please
CREATE FUNCTION [dbo].[udfGetAnimalCollectionNode]()
RETURNS XML
AS
BEGIN
DECLARE #ResultVar XML
SET #ResultVar =
(
SELECT
dbo.udfGetDogCollectionNode(),
dbo.udfGetCatCollectionNode()
FOR XML PATH('AnimalCollection'), ELEMENTS XSINIL
)
RETURN #ResultVar
END
when invoked as
SELECT [dbo].[udfGetAnimalCollectionNode]()
the udf might produce the more complex XML node (given the appropriate underlying data)
<AnimalCollection>
<DogCollection>
<Dog SpecificDogNameId="88">Dino</Dog>
<Dog SpecificDogNameId="99">Astro</Dog>
</DogCollection>
<CatCollection>
<Cat SpecificCatNameId="11">Sylvester</Cat>
<Cat SpecificCatNameId="22">Tom</Cat>
<Cat SpecificCatNameId="33">Felix</Cat>
</CatCollection>
</AnimalCollection>
Use sql:column instead of sql:variable. You can find detailed info here: http://msdn.microsoft.com/en-us/library/ms191214.aspx
Can you tell a bit more about what exactly you are planning to do.
Is it simply generating XML data based on a content of the table
or adding some data from the table to an existing xml structure?
There are great series of articles on the subject on XML in SQLServer written by Jacob Sebastian, it starts with the basics of generating XML from the data in the table