MySql quick user select - mysql

I have a Users table and I'm getting user details (usual way) with id.
This is how I'm getting user details;
select id,kullaniciadi,FotoGet(K.Foto,K.Gender) from kullanicilar K where id=1;
FotoGet function always returning string value like 'Photos/ssss.jpg'
So far I have not trouble to use this way but I'm wondering how can I do this with a single function?
Like
set #uid=1;
Select UserGet(#uid);
I will put the id inside parentheses and the function will run my select query and return all user detail columns. id, kullaniciadi, FotoGet(K.id,K.Foto,K.Gender)
Can I use this way to get details?

A MySQL stored function cannot return multiple columns, it can only return a single scalar value.
But you could design a stored procedure that returns a result set:
CREATE PROCEDURE UserGet(uid INT)
SELECT id, kullaniciadi, FotoGet(K.Foto,K.Gender) FROM kullanicilar K WHERE id=uid;
Then call it like so:
CALL UserGet(1234);
It returns a result set just like a SELECT query would.
DELIMITER //
CREATE PROCEDURE UserGet(IN uid INT, IN column_name VARCHAR(64))
BEGIN
SET #sql = CONCAT('SELECT id, ', column_name, ' FROM kullanicilar K WHERE id=?');
PREPARE stmt FROM #sql;
SET #uid = uid;
EXECUTE stmt USING #uid;
END//
DELIMITER ;
Call it like so:
CALL UserGet(1234, 'kullaniciadi');
Remember that it's your responsibility to write code to pass a valid column name as the procedure argument. If you allow untrustworthy content to be passed, then it might be an SQL injection vulnerability.
Re your additional comment:
This should work fine:
CALL UserGet(1234, 'FotoGet(Foto,Gender)');

Related

Can't execute a MySQL SELECT statement when inside CONCAT

I have been trying to create a simple loop of SELECT statements in MySQL to reduce code. I have started this using CONCAT() however this causes the procedure to stop/fail. For example (where k is a loop counter):
CONCAT('SELECT (Child_', k, ' INTO #Age_Child_', k, ' FROM lookup_childage WHERE ModYear = ModYear_var LIMIT 1)');
To diagnose the issue, I simply tried to place the SELECT statement (without concatenated loop variables) inside a string to then be executed. While I could get this to work for simple statements it would not work for the following:
SET #queryString = CONCAT('SELECT Child_1 INTO #Age_Child_1 FROM lookup_childage WHERE ModYear = ModYear_var LIMIT 1');
PREPARE stmt FROM #queryString;
EXECUTE stmt;
Does anyone know why the #queryString containing the CONCAT() statement will not be executed/cause the procedure to fail?
tl;dr The statement you're trying to write has the form SELECT(rest of statement) LIMIT 1. It should have the form SELECT rest of statement LIMIT 1.
It looks like you want to create variable column names, ummm, because your lookup_childage table is denormalized. I guess that table has these columns.
Child_1 INT
Child_2 INT
Child_3 INT
Child_4 INT
It looks like you hope to get a #queryString value containing this sort of thing:
SELECT Child_4 INTO #Age_Child_4 FROM lookup_childage WHERE ModYear = ModYear_var LIMIT 1
Only the 4s are variable.
So to get that string you want
SELECT CONCAT('SELECT Child_', k,
' INTO #Age_Child_', k,
' FROM lookup_childage WHERE ModYear = ModYear_var LIMIT 1'
)
INTO #queryString;

MySQL Use table name for function

When we use a statement like select count(*) from TABLE, the function count() automatically knows which table it is counting. Is it possible to grab the table and use it in a user defined function.
drop function if exists related_count;
create function related_count(parent int(11)) returns int(11) deterministic
begin
declare count int(11) default 0;
set count=(select count(*) from TABLENAME where id=parent);
return count;
end;
So that I can use it like this:
select count(*),related_count(id) from TABLENAME
So that I can use the same function regardless of table instead of defining multiple functions because of multiple tables.
Is there a way to switch between select count(*) from TABLENAME1 where id=parent or select count(*) from TABLENAME2 where id=parent dependent on a variable related_count('TABLE1',id)
The comment above from #RajeevRanjan mentions using dynamic SQL. This won't work, but if it did it would look like this:
create function related_count(tablename varchar(64), parent int) returns int reads sql data
begin
declare count int default 0;
set #sql = concat('select count(*) into count from `', tablename, '` where id = ', parent);
prepare stmt from #sql;
execute stmt;
return count;
end
However, this is not allowed:
ERROR 1336 (0A000): Dynamic SQL is not allowed in stored function or trigger
The reason it doesn't work is that your stored function could be called by an expression in an SQL statement that is itself a dynamic SQL execution. I guess MySQL only allows one level "deep" of prepare/execute. You can't make a prepared query run another prepared query.
To do this, you'd have to hard-code each table name like the following:
create function related_count(tablename varchar(64), parent int) returns int reads sql data
begin
declare count int default null;
if tablename = 'foo' then set count = (select count(*) from foo where id = parent);
elseif tablename = 'bar' then set count = (select count(*) from bar where id = parent);
elseif tablename = 'baz' then set count = (select count(*) from baz where id = parent);
end if;
return count;
end
This also has an advantage that it isn't an SQL injection vulnerability, whereas the PREPARE/EXECUTE solution (if it had worked) would be.
PS: A function that reads from other tables is not deterministic.

Dynamically generating query using function

I just started learning use defined functions in MYSQL and I tried few basic examples, but when I tried a function which returns varchar, which actually returns a portion of a select query, it gives me something unexpected.
There are lot of tables in database with columns as id and name, so whenever people want to fetch id for a particular name or vice versa they go into the table and manually fetch the data. So I was trying to create a function that would smoothen the process.
This is my function
create function getTableDetails(table_name varchar(20), id int(5), name varchar(20))
returns varchar(50)
begin
return " * from " + table_name + " where id = " + id +
" or name like '%" + name + "%'";
end
As you can see I'm trying to generalize the query for all tables and it returns everything other than the select keyword.
Now my query will be like select getTableDetails('classes', 2, 'a')
Assuming that the return of the function will fill the rest of the query and give me the table data, but the result set what I'm getting is
getTableDetails('classes'; 2; 'a')
2
getTableDetails('classes'; 2; 'a') is the header.
Where I'm getting wrong?
You can't dynamically generate and execute query like that, from command line. You need to use preparedstatement and that too, from stored procedure, e.g.:
SET #query = CONCAT('select', getTableDetails('classes', 2, 'a'));
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

MySQL: I want to pass an array to a function and see it iterate through each element of the array

I have the following code so far:
delimiter //
CREATE FUNCTION Iteration(InputArray CHAR)
RETURNS DECIMAL
BEGIN
RETURN
SELECT Max(IF(Stock = InputArray, ValueFrom, NULL)) AS Stock FROM DatabaseName.TableName LIMIT 1;
END
delimiter ;
SET #Stocks = (SELECT ColumnName FROM DatabaseName.TableName LIMIT 1);
SELECT Iteration(#Stocks)FROM DatabaseName.TableName;
What I'm interested in doing is passing an array to the Iteration function, which would then be operated on by looking up the corresponding value in the DatabaseName database, spitting back out a corresponding decimal for each value in the input array-- in other words, one array in, another array out.
I think I instantiated everything correctly, but I keep getting the following error:
Error Code: 1305. FUNCTION applications.Iteration does not exist
For example, I have the variables AAA, BBB, CCC, etc, which are stock inventory codes. I want to pass an array of these variables to the procedure/function, and then go onto get back an array as well. In this case, it would be 1.7, 1.3, and 1.8.
There's a few questions I have:
Does this make sense-- that is, can I pass an array to a function like this?
If 1. is yes, am I passing the array to the function properly?
Why am I getting this error?
First, we need to nail down the logic you actually want for the SQL query. You want to take the MAX value of the ValueFrom column, but only for those records where the Stock is contained in the input array. This can be accomplished by doing a simple SELECT, along with a WHERE clause which filters out the non matching records, e.g.
SELECT ValueFrom
FROM DatabaseName.TableName
WHERE Stock IN ('stock1', 'stock2', 'stock3')
Of course, we will need to replace the list of stocks with the input array. I would use a stored procedure here:
CREATE PROCEDURE Iteration(IN inputArray VARCHAR(255))
BEGIN
SET #sql = CONCAT('SELECT ValueFrom FROM DatabaseName.TableName WHERE Stock IN (', inputArray, ')');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
$$
DELIMITER ;
Usage:
SET #inputArray = '\'stock1\',\'stock2\',\'stock3\'';
CALL Iteration(#inputArray);

Remove "\N"s when doing SELECT INTO OUTFILE

I'm doing a SELECT INTO OUTFILE and it's showing a "\N" for every NULL value. Is there any way for me to make it just be blank instead?
I'm on MySQL.
You can use the COALESCE function something like this:
COALESCE(yourfield, '')
Good question, and as relevant today as it was in 2011. I use a stored procedure for this, wich takes the name of a table as argument. Subsequently, it converts all null-values to empty strings (''), using a prepaired statement and no cursors, for cursors are so non-SQL. I've tested it with a table with some 200 columns and a resulting prepaired statement that's about 15,000 characters long:
CREATE DEFINER=`root`#`localhost` PROCEDURE `ExportFixNull`(
in tblname tinytext)
BEGIN
set #string=concat(
"Update ",#tblname," set ",
(
select group_concat(column_name,"=ifnull(",column_name,",'')")
from information_schema.columns
where table_name=#tblname
)
,";"
);
prepare s1 from #string;
execute s1;
drop prepare s1;
In the main SQL-file, there is a statement
SET ##group_concat_max_len = 60000;
that might be crucial.
More details (in Dutch): http://wiki.devliegendebrigade.nl/SELECT_INTO_OUTFILE_%28MySQL%29
Regards,
Jeroen Strompf