Select statement defined by parameter SQL - mysql

In SQL is there a way to grab the information in a table, but with the table name being specified by a function parameter?
Obviously the following doesn't work, but something along these lines maybe:
CREATE OR REPLACE FUNCTION select_table(table_name TEXT)
RETURNS TABLE (
"ID" TEXT
) AS
$$
SELECT * FROM uploads.<table_name>
$$
LANGUAGE SQL STABLE;
I'm a bit of a rookie when it comes to SQL, so would appreciate any guidance.

Any use of a variable in a query will be as if you had used a string literal, not an identifier.
To use a variable as an identifier, you would have to use dynamic SQL. That is, do string-concatenation of the table_name variable into a string which is your SELECT query, then PREPARE and EXECUTE that query.
But https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html says:
SQL syntax for prepared statements can be used within stored procedures, but not in stored functions or triggers.
This is because if a stored function is running, then by definition, your thread is already running a query. MySQL cannot do that.
You can write your function to do a large CASE statement to do a different fixed query depending on the input variable.
But as P.Salmon comments above, in MySQL you can't return a table from a stored function. Functions can only return a single scalar value, not a result set. So your SELECT would need to query one column and use INTO syntax to save it to a variable. Then return that variable.
Also current versions of MySQL have no "CREATE OR REPLACE FUNCTION" option. You can "CREATE FUNCTION."
DELIMITER //
CREATE FUNCTION select_table(table_name TEXT)
RETURNS TEXT READS SQL DATA
BEGIN
DECLARE result TEXT;
CASE table_name
WHEN 'mytable1' THEN SELECT col1 INTO result FROM mytable1;
WHEN 'mytable2' THEN SELECT col1 INTO result FROM mytable2;
WHEN 'mytable3' THEN SELECT col1 INTO result FROM mytable3;
END CASE;
RETURN result;
END//
DELIMITER ;

Related

stored function - syntax to format data of a column

Much appreciated if you can have a quick look on the below.
I've created the below stored function in order to format the datetime from a table to mysql format;
(%Y-%m-%d; %h:%i:%s);
Delimiter $$
create function formatdata(dataparameter varchar(20), hourparametru
varchar(20))
begin
DECLARE x time;
declare y date;
set x = (select STR_TO_DATE(Datăcolumn,'%h:%i:%s')from tabelname);
set y = (select STR_TO_DATE(oracolumn,'%Y-%m-%d')from tabelname);
select x,y;
if current_time > time(hourcolumn) then
select STR_TO_DATE(Datăcolumn,'%Y-%m-%d')into x from tabelname;
select STR_TO_DATE(oracolumn,'%h:%i:%s') into y from tabelname;
return(x,y);
end if;
end $$
Delimiter ;
What am I doing wrong here?
The error is You have an error in your sql syntax near first select_Str_to_date.
but I am kind of confused how local variables, IN parameters work together - so I am assuming that here is where I do wrong..
If you set a variable to a result of a scalar SELECT query, you put the query inside parentheses.
This:
set x = select STR_TO_DATE('07:47:20','%h:%i:%s');
Should be:
set x = (select STR_TO_DATE('07:47:20','%h:%i:%s'));
That explains the syntax error.
You also have a few other problems in this function.
Re your comment:
The line:
select x,y;
Would return a result set, but that's not allowed in a stored function (it is allowed in a stored procedure). I think you can just remove this line.
A stored function can only return a single scalar value. You should have a line RETURNS <datatype> before your BEGIN, and you should RETURN a single value somewhere in your function.
Another problem: your assignments are not valid if the table has more than one row. Setting a variable to a scalar SELECT query result is valid only if the query returns a single column and single row.
Another problem:
if current_time > time(hourcolumn) then
What is hourcolumn? It's not a function parameter or a local variable. But if it is a column of a table, there's no syntax to say which table you mean.
Another problem:
return(x,y);
You can't return a pair of variables from a stored function. Only one variable.
Another problem: The only RETURN is inside an IF block. What should the function return if the IF condition isn't true?

Alternatives to dynamic sql in stored function

I'm writing a stored function where I calculate the position of a cell, which value I need to select from a table. To do this, I decided to save this position in a variable, in order to use it as the offset of a LIMIT clause.
According to my research, the way of using values set into local variables with the LIMIT statement is through a prepared statement, but I also got that prepared statements (nor any dynamic SQL) are allowed in stored functions. Are there any alternatives to solve my problem?
A simplified example of my situation:
CREATE FUNCTION foo(a int) RETURNS decimal DETERMINISTIC
BEGIN
SET #var1 := (SELECT COUNT(*) FROM table);
SET #var2 := (ROUND(#var1 * a/5))
PREPARE STMT FROM 'RETURN (SELECT * FROM other_table LIMIT ?, ?)';
EXECUTE STMT USING #var2, #var1;
END
$$ DELIMITER ;
Ideally, this would get me the result I need, where I need it. But, of course, I get Error Code 1336 saying "Dynamic SQL is not allowed in stored function or trigger"
You don't need dynamic SQL for this stored function. You don't need to use dynamic SQL for a LIMIT clause. You just need to make sure the variables are INT type, not strings.
Here's a quick demo:
create function foo(a int) returns int reads sql data
begin
return (select x from test limit 1 offset a);
end
Notice several other things:
Use READS SQL DATA instead of DETERMINISTIC. Your function is not deterministic. You should read the manual page on create function to understand these options better.
Don't use SELECT *. A function can only return a single scalar value, not a set of columns. The table you are querying might in fact have one column, but it's a good habit to make queries be more clear.
Using LIMIT with no ORDER BY may surprise you later, because it doesn't guarantee which order it will use for determining the offset. It's best if you use ORDER BY explicitly.
When using LIMIT, I think it's more clear to use LIMIT <count> OFFSET <offset> instead of LIMIT <offset>, <count>. They do the same thing, but it's easier to remember which argument is which.
Your LIMIT query appears to be selecting many rows. You need the query to select exactly one column and one row, or else it's not valid to return from a stored function.

mysql stored function: how to select multiple results and process them

mysql stored function: how to select multiple results and process them. For example,
create function hello() return decimal(10,2) determistic begin
select value1, value2 from Foo;
// process multiple rows in result set here
for (....) {
}
end
https://dev.mysql.com/doc/refman/8.0/en/create-procedure.html says:
Statements that return a result set can be used within a stored procedure but not within a stored function.
You can't run select ... from Foo in a stored function as you would in a stored procedure, because that select will generate a result set with multiple columns and multiple values.
A stored function can only return a single scalar value. In your example, you are returning a decimal(10,2). So whatever you do with your queries, the result must end up in an expression in a RETURN statement.
If you need to run a select query, you can store the result into a variable and then return that variable.
...
begin
declare d decimal(10,2);
select <expr> into d from Foo limit 1;
return d;
end
Or you can run a cursor (as suggested by the link posted by #stickybit above in a comment), and process the result of the query row-by-row. See an example in that documentation page: https://dev.mysql.com/doc/refman/8.0/en/cursors.html
I can't go into more detail, because you have not described what you're trying to do with your function, and the example you show does not make it clear.

Subquery returns more than 1 row (Sql Functions)

I have this function that I want to run ... this function needs to return the job_ids that start with A only... I'm confused!
I'm getting this error!
any ideas... What I know that a function needs to have parameters, but I don't know what to pass...
23:47:05 select job_id() LIMIT 0, 1000 Error Code: 1242 Subquery returns more than 1 row
delimiter $
create function Job_id()
returns char
reads sql data
begin
return (select job_id
from job_history
where job_id like 'A%');
end$
delimiter ;
The MySQL documentation for functions says:
Statements that return a result set can be used within a stored
procedure but not within a stored function
If you need a result set then, as told by #Michael Berkowsky, use stored procedures or maybe a view will do the trick for your needs.

Limiting selected rows count with a stored procedure parameter in MySQL

I have a procedure SelectProc which contains a SELECT statement. I want to add a procedure param LimitRowsCount and use it as following:
CREATE PROCEDURE SelectProc (IN LimitRowsCount INTEGER UNSIGNED)
BEGIN
SELECT (...)
LIMIT LimitRowsCount;
END
but this approach doesn't work.
The SELECT itself contains nested subqueries so I can't create view from it. Is there a way more proper than dynamic SQL (prepared statements)?
CREATE PROCEDURE SelectProc (IN LimitRowsCount INT)
BEGIN
SET #LimitRowsCount1=LimitRowsCount;
PREPARE STMT FROM "SELECT (...) LIMIT ?";
EXECUTE STMT USING #LimitRowsCount1;
END
From the manual:
The LIMIT clause can be used to constrain the number of rows
returned by the SELECT statement. LIMIT takes one or two numeric
arguments, which must both be nonnegative integer constants
(except when using prepared statements).
MySQL Manual - 12.2.8. SELECT Syntax
So that's a no - you cannot.