As far as I understand MySQL does not support functions with OUT (as well as IN / INOUT) parameter types.
I am creating a function
DROP FUNCTION IF EXISTS `GETGOSTAUTHRUS`;
CREATE DEFINER = `root`#`localhost` FUNCTION `GETGOSTAUTHRUS`(`PublID` int)
RETURNS varchar(1024) CHARSET utf8
BEGIN
RETURN .....;
END;
This function is called from SELECT statement:
SELECT
GETGOSTAUTHRUS(p.ID) `AuthList`,.......
FROM....
Everything works fine. However I need to extend the function and return another value of varchar type but I can not declare out prefix varchar(50) variable in the same way as I do in procedure declaration:
CREATE procedure `GETGOSTAUTHRUS`(PublID int, OUT prefix varchar(50))
BEGIN
The only way out I have invented is to declare another function and call it separately, but it seems not optimal as the second function will fetch and process the same data from the tables.
How can I manage the issue?
Functions are supposed to return only one value, you might have the wrong approach here. We don't know what you're exactly trying to do, so we can't tell if we're dealing with a XY problem here. There may be better solutions to your overall problem.
You can solve this however with user-defined variables. These are session bound, so make sure to reset them in your function.
Related
Here's my user-defined table type...
CREATE TYPE [dbo].[FooType] AS TABLE(
[Bar] [INT],
)
This is what ive had to do in my table-valued function to return the type:
CREATE FUNCTION [dbo].[GetFoos]
RETURN #FooTypes TABLE ([Bar] [INT])
INSERT INTO #FooTypes (1)
RETURN
Basically, im having to re-declare my type definition in the RETURN statement of the function. Isnt there a way i can simply declare the type in the RETURN statement?
I would have thought this would work:
CREATE FUNCTION [dbo].[GetFoos]
RETURN #FooTypes [FooType]
INSERT INTO #FooTypes (1)
RETURN
Cannot find any help on MSDN/Google regarding this....anyone?
EDIT
I unmarked my answer, and bumping this question - as i am encountering the same scenario 6 months later.
Does anyone have any idea if it's possible to return a user defined table type from a table valued function? If not, is there a better workaround other than what i have done? (re-declare the type again).
Even though you can not return the UDTT from a function, you can return a table variable and receive it in a UDTT as long as the schema match. The following code is tested in SQL Server 2008 R2
-- Create the UDTT
CREATE TYPE dbo.MyCustomUDDT AS TABLE
(
FieldOne varchar (512),
FieldTwo varchar(1024)
)
-- Declare your variables
DECLARE #uddt MyCustomUDDT;
DECLARE #Modifieduddt MyCustomUDDT;
// Call the function
INSERT INTO #Modifieduddt SELECT * FROM dbo.MyUDF(#uddt);
Function signature
CREATE FUNCTION dbo.MyUDF(#localUDDT MyCustomUDDT)
RETURNS #tableVar TABLE
(
FieldOne varchar (512),
FieldTwo varchar(1024)
)
AS
BEGIN
--Modify your variable here
RETURN
END
Hopefully this will help somebody.
Ok - so it cant be done.
Easy enough to duplicate the table definition in the return type (with the use of scripting).
Still - hopefully this issue gets rectified in the next version of SQL Server.
The syntax for CREATE FUNCTION indicates that the only way to define a table return type is by listing columns and types, a <table_type_definition>. Even SQL Server "Denali" has the same definition for <table_type_definition>. Although strangely, it's syntax doesn't include multi-statement Table valued functions, or anything else that references this fragment.
I do not believe this is possible. You cannot use a UDTT as the return type of a Scalar-Valued Function because it is not a scalar value. You also cannot replace the table declaration of a Table-Valued Function with a UDTT. Repeating the table definition seems to be the only option. If we knew why you were doing this, perhaps we could find an alternative.
I'm facing the exact issue as described in this SO link which hasn't been answered. I've tried the suggestions given in the comment section, nothing works.
I've searched online for the answers and found no luck.
My Procedure looks like this.
DROP PROCEDURE IF EXISTS userdb.new_test;
CREATE PROCEDURE userdb.new_test (IN arg varchar(255))
BEGIN
select * FROM message
END;
and from this link I got to know
This exception indicates that a method is called with incorrect input arguments. Then, the only thing you must do is correct the values of the input parameters. In order to achieve that, follow the call stack found in the stack trace and check which method produced the invalid argument.
does anyone know how to fix this?
That's most probably because of the non-default value parameter in your procedure IN arg varchar(255) and if not wrong you are probably calling the procedure without passing any parameter. You need to call like
call userdb.new_test 'some value'
MySQL doesn't support parameter default value likewise in SQL Server and so you can't say IN arg varchar(255) = null
Also, I don't see you are using that parameter in your query and so best is drop it;
DROP PROCEDURE IF EXISTS userdb.new_test;
CREATE PROCEDURE userdb.new_test
BEGIN
select * FROM message
END;
Here, I will show that referencing a non-existing function from another function is possible and SQL Server doesn't check it until the execution time:
USE [SomeDataBase];
SELECT dbo.Booo();
Obviously, if you don't have function Booo then an error will be generated regarding function Booo is not recognized. This isn't a surprise though!
Now, try this:
CREATE FUNCTION dbo.Foo()
RETURNS INT
AS
BEGIN
DECLARE #Temp INT
SET #Temp = (SELECT dbo.Booo())
RETURN 1
END
Surprisingly, this scrip creates the function Foo despite the fact that the Booo function doesn't exit.
Any idea?
Why do you think that's a bug? Since the code isn't actually executed until you run the Foo function, there's a case to be made that that is the point where the check should be made.
Maybe you write your functions in a top-down manner, rather than a bottom-up manner, and you want to write the upper levels first, drilling down to specifics later.
Unless it's documented to work one way and it works another way, it's not a bug, just a disagreement between you and Microsoft :-)
If you do
CREATE FUNCTION dbo.Foo()
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
DECLARE #Temp INT
SET #Temp = (SELECT dbo.Booo())
RETURN 1
END
You get your desired error and the function is not created. That does make altering the definition of dbo.Booo in the future more painful however (need to drop dbo.Foo first).
You can also use a SQL Server Data Tools project to validate things like referencing non existent objects/columns without using schemabinding.
I am writing some MySQL procedures for a web-based application, and something that strikes me is that there is no argument's type check at all.
For instance, if I have the following :
CREATE PROCEDURE foo(n CHAR(4))
I can call it with whatever I want, it will accept it and only take the four first characters. But if I want to do something like this :
use base;
DELIMITER $$
DROP PROCEDURE IF EXISTS open $$
CREATE PROCEDURE open(n INT)
BEGIN
SELECT * FROM prod_charts LIMIT n;
END $$
DELIMITER ;
It will just crash when called with a non-int parameter. And there is no feedback : when called from php, I just get nothing, and when I try it in phpMyAdmin, I am sent back to the home's page.
So my question is : how can I make it a little bit safer ? is there a way to check a variable's type in those procedures ?
Unfortunately, I don't know of a way of doing this directly in mySQL. In other RDMS - like MS SQL, there are functions like isNumeric() that you can use.
Create the following function in mySQL and use it to check to see if the value passed in is numberic.
CREATE FUNCTION ISNUMERIC(myVal VARCHAR(1024))
RETURNS TINYINT(1) DETERMINISTIC
RETURN myVal REGEXP '^(-|\\+)?([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$';
That should cover most (if not all) possibilities.
I'm a SQL noob, and I need a little bit of help understanding the big picture of if it is possible, and if so how to go about filtering a result set based on the return value of a function which is passed one of the fields of the record.
Let's say I have a table called "Numbers" with just one field: "Value".
How could I correctly specify the following "pseudo-sql"?:
SELECT Value FROM numbers WHERE IsPrime(Value)=true
Can I accomplish such a thing, and if so, where/how do I put/store "IsPrime"?
I'm using MySQL.
I agree with extraneon that it's usually better to store this value in the database rather than compute it in the where clause. This way you can compute it once per row and index the data for faster performance.
As long as you are on MySQL 5.x, I would recommend a stored function, as opposed to a UDF. You can add an IS_PRIME column of type TINYINT to your DB, add an index on that column, then use the stored function to calculate the value at insert time. You can even calculate the IS_PRIME value using a before insert trigger if you don't want to change the insert code.
The stored function would look something like this:
DELIMITER $$
DROP FUNCTION IF EXISTS IS_PRIME $$
CREATE FUNCTION IS_PRIME(P_INT BIGINT) RETURNS TINYINT
BEGIN
DECLARE V_FACTOR BIGINT;
DECLARE V_MAX_FACTOR BIGINT;
SET V_FACTOR := 2;
SET V_MAX_FACTOR := round(sqrt(P_INT),0);
WHILE (V_FACTOR <= V_MAX_FACTOR)
DO
IF (P_INT % V_FACTOR) = 0
THEN
RETURN FALSE;
END IF;
SET V_FACTOR := V_FACTOR + 1;
END WHILE;
RETURN TRUE;
END $$
DELIMITER ;
I think you may find some help with the doc about the user-defined functions: http://dev.mysql.com/doc/refman/5.1/en/adding-functions.html
I don't know anything about user defined functions, but I could imagine that for computation-intensive functions it might be best to have that value precomputed and stored in the database somewhere.
Depending on how the data gets in the database you could require the client to compute isPrime (that can be done if the client is a web service or app on your own server), or perhaps a scheduled job which processes every record with isPrime is null or something like that. That is not instantaneous, but for some scenario's it may be good enough.
If isPrime is only used sometimes you could also post-process/filter the data on the client when retrieving data.