MySQL stored function - append string - mysql

I have searched but been unable to find anything that does what I need.
I would like to create a stored function that will gather data from a secondary field and return a comma separated list of items as the return string. I can't seem to find any way to take a variable I create in the function and iterate through a record set and append each result to the variable so I can return it .. see below:
BEGIN
DECLARE searchCat INT;
DECLARE searchProd INT;
DECLARE metas CHAR;
SET searchCat = cat;
SET searchProd = prod;
SELECT * FROM offer_metas WHERE category = searchCat AND offer_id = searchProd
gatherMeta: LOOP
metas = metas + "," + meta_option;
ITERATE gatherMeta;
END LOOP gatherMeta;
RETURN metas;
END
The function won't save because my syntax on the "metas = metas + meta_option;".
What I am looking for is the command to append the current field falue of "meta_option" to the current variable "metas" so I can return a full list at the end.
Any idea?
UPDATE - SOLUTION
BEGIN
DECLARE metas VARCHAR (300);
SELECT GROUP_CONCAT(CONCAT(mn.title,'=',offer_metas.meta_option) ORDER BY mo.cat_seq ASC) INTO metas
FROM offer_metas
LEFT JOIN meta_options as mo ON mo.id = offer_metas.meta_option
LEFT JOIN meta_names AS mn ON mn.category = mo.category AND mn.seq = mo.cat_seq
WHERE offer_metas.category = searchCat
AND offer_metas.offer_id = searchProd
ORDER BY cat_seq ASC;
RETURN metas;
END
And then I just updated my SQL query to be as follows (1 is the offer category I have in my PHPand populate into the query):
SELECT offers.*, s.short_name AS sponsorName, s.logo AS sponsorLogo, getMetas(1,offers.id) AS metas
FROM offers
LEFT JOIN sponsors AS s ON s.id=offers.carrier
GROUP BY offers.id
ORDER BY end_date ASC

Why not just
SELECT GROUP_CONCAT(meta_option SEPARATOR ',')
FROM offer_metas
WHERE category = searchCat AND offer_id = searchProd;

Option 1) use Group_Concat
Option 2) use || instead of +
Option 3) use Concat()

Related

MySQL user-defined function returns incorrect value when used in a SELECT statement

I met a problem when calling a user-defined function in MySQL. The computation is very simple but can't grasp where it went wrong and why it went wrong. Here's the thing.
So I created this function:
DELIMITER //
CREATE FUNCTION fn_computeLoanAmortization (_empId INT, _typeId INT)
RETURNS DECIMAL(17, 2)
BEGIN
SET #loanDeduction = 0.00;
SELECT TotalAmount, PeriodicDeduction, TotalInstallments, DeductionFlag
INTO #totalAmount, #periodicDeduction, #totalInstallments, #deductionFlag
FROM loans_table
WHERE TypeId = _typeId AND EmpId = _empId;
IF (#deductionFlag = 1) THEN
SET #remaining = #totalAmount - #totalInstallments;
IF(#remaining < #periodicDeduction) THEN
SET #loanDeduction = #remaining;
ELSE
SET #loanDeduction = #periodicDeduction;
END IF;
END IF;
RETURN #loanDeduction;
END;//
DELIMITER ;
If I call it like this, it works fine:
SELECT fn_computeLoanAmortization(3, 4)
But if I call it inside a SELECT statement, the result becomes erroneous:
SELECT Id, fn_computeLoanAmortization(Id, 4) AS Amort FROM emp_table
There's only one entry in the loans_table and the above statement should only result with one row having value in the Amort column but there are lots of random rows with the same Amort value as the one with the matching entry, which should not be the case.
Have anyone met this kind of weird dilemma? Or I might have done something wrong from my end. Kindly enlighten me.
Thank you very much.
EDIT:
By erroneous, I meant it like this:
loans_table has one record
EmpId = 1
TypeId = 2
PeriodicDeduction = 100
TotalAmount = 1000
TotalInstallments = 200
DeductionFlag = 1
emp_table has several rows
EmpId = 1
Name = Paolo
EmpId = 2
Name = Nikko
...
EmpId = 5
Name = Ariel
when I query the following statements, I get the correct value:
SELECT fn_computeLoanAmortization(1, 2)
SELECT Id, fn_computeLoanAmortization(Id, 2) AS Amort FROM emp_table WHERE EmpId = 1
But when I query this statement, I get incorrect values:
SELECT Id, fn_computeLoanAmortization(Id, 2) AS Amort FROM emp_table
Resultset would be:
EmpId | Amort
--------------------
1 | 100
2 | 100 (this should be 0, but the query returns 100)
3 | 100 (same error here)
...
5 | 100 (same error here up to the last record)
Inside your function, the variables you use to retrieve the values from the loans_table table are not local variables local to the function but session variables. When the select inside the function does not find any row, those variables still have the same values as from the previous execution of the function.
Use real local variables instead. In order to do that, use the variables names without # as a prefix and declare the variables at the beginning of the function. See this answer for more details.
I suspect the problem is that the variables in the INTO are not re-set when there is no matching row.
Just set them before the INTO:
BEGIN
SET #loanDeduction = 0.00;
SET #totalAmount = 0;
SET #periodicDeduction = 0;
SET #totalInstallments = 0;
SET #deductionFlag = 0;
SELECT TotalAmount, PeriodicDeduction, TotalInstallments, DeductionFlag
. . .
You might just want to set them to NULL.
Or, switch your logic to use local variables:
SET v_loanDeduction = 0.00;
SET v_totalAmount = 0;
SET v_periodicDeduction = 0;
SET v_totalInstallments = 0;
SET v_deductionFlag = 0;
And so on.

Mysql assign a single column value to a declared value using Select case

I am stucked with following issue,
I ve delcared a varibale (DOUBLE) in a stored procedure, and i need to assign a value (item price) from a table (item) to this declared variable. however, i need to get this value from a select query which uses case inside, the item price could be in 2 columns based on a logic i have to find the correct item price. Please help me solve this as when i execute it gives me a error,
Here how is layered,
DECLARE no_more_users INT DEFAULT 0;
DECLARE user_id INT DEFAULT 0;
DECLARE cart_id INT DEFAULT 0;
DECLARE cart_item_id INT DEFAULT 0;
DECLARE user_gift_id INT DEFAULT 0;
DECLARE itemPrice DOUBLE DEFAULT 0.0;
SELECT
CASE
WHEN sale_price=0 OR sale_price IS NULL THEN (price - ( price * discount ))
ELSE sale_price
END
INTO itemPrice
FROM item WHERE item_id = p_item_id ;
DECLARE checked_in_users CURSOR FOR
SELECT DISTINCT ul.user_id
FROM user_location ul
LEFT JOIN location_section ls ON ul.location_section_id = ls.location_section_id
INNER JOIN user u ON ul.user_id = u.user_id
INNER JOIN user_profile up ON u.user_id = up.user_id
INNER JOIN location_event le ON ul.location_event_id = le.location_event_id
WHERE ul.location_id = p_location_id AND ul.location_event_id = p_event_id
AND ul.checked_out_on IS NULL AND (ul.checked_in_on BETWEEN le.start_time AND le.end_time )
AND u.status = 1 ;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_users = 1;
OPEN checked_in_users;
FETCH checked_in_users INTO user_id;
read_loop: LOOP
some more code...
please note, sale_price, price, and discount are coulmns of item table, The logic is if sale_price is null or value is 0, then i actual sale price should be obtained from price coulmn. Finally what i need is asign corect item price in to previously declared varibale.
Any help will be highly appriciated.
There are two foms to the CASE statement, one with expressions and one with values. You are mixing them up.
with values:
CASE variable
WHEN value_1 THEN foo
WHEN value_2 THEN bar
END
with expressions:
CASE
WHEN expression_1 THEN foo
WHEN expression_2 THEN bar
END
Try
CASE
WHEN sale_price=0 OR sale_price IS NULL THEN (price - ( price * discount ))
ELSE sale_price
END
Also, you do not need the "AS correct_price" when you are using an INTO
Your select query has some problems.
The version of CASE you are are using - ie CASE var WHEN val1 THEN - doesn't work when trying to match a NILL, because in SQL null is not equal to null.
Also, you can't combine values with conditions as you hAve.
Instead, use the version if CASS that simply conditions. There are other suntactic problems. Converting your broken query then gives:
SELECT
CASE
WHEN ifnull(sale_price, 0) = 0 THEN price - (price * discount)
ELSE sale_price
END
INTO itemPrice
FROM item
WHERE item_id = p_item_id;
Note: if your table has s column called itemPrice, you must choose another name from your variable. Mysql gets confused :/

PostgreSQL conditional use of function parameters

I'd like to know how to use a function parameter conditionaly. This is my function, and you can read the comment inside the query:
CREATE OR REPLACE FUNCTION mediabase.select_media(sysEnvironment character varying, statusId integer)
RETURNS refcursor AS
$BODY$
DECLARE
ref refcursor;
BEGIN
OPEN ref FOR
SELECT media.id, media.title, media.unique_filename, media.owner_id, media.status_id, media.location_name_id, media.upload_user_id, media.upload_ip, media.metadata_id, media.type_id, media.description, media.system_environment, media.upload_date, media.gps_location, media.language_id, media_publications.publication_id, media.limitations, media_categories.category_id, metadata.width, metadata.height, metadata.equipment, metadata.copyright, metadata.creation_time, metadata.file_format, metadata.resolution, metadata.resolution_unit, metadata.gps_longitude, metadata.gps_latitude, metadata.artist, metadata.color_space, metadata.gps_altitude, metadata.software_used, metadata.user_comment
FROM mediabase.media, mediabase.metadata, mediabase.media_categories, mediabase.media_publications
WHERE media.metadata_id = metadata.id
AND media.id = media_categories.media_id
AND media.id = media_publications.media_id
-- Problem: this CASE doesn't work of course
CASE statusId <> -1 THEN
AND media.status_Id = statusId
END
-- End problem
AND media.system_environment = sysEnvironment
ORDER BY media.upload_date DESC;
RETURN ref;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
I only need to use the 'statusId' parameter, if it's different from -1, otherwise I'll recieve no results as there of-course is no status -1. Later on, I'll need to add some more filters of that sort.
Try something like:
AND (media.status_Id = statusId OR statusId = -1)
It wont check media.status_Id = statusId if statusId = -1.

Assigning a value from another database and function - MySQL variable scope

I am using MySQL to make a report showing the number of hours billed for a particular date range and project. The complexity is that the date range is variable for each project (different start month and start day). This information is coming from a value in another database/table.
I have the following UDF in MySQL:
DELIMITER //
CREATE FUNCTION TimeLeft(startday INT, today INT) RETURNS INT
DETERMINISTIC
BEGIN
DECLARE s INT;
IF startday < today THEN SET s = 0;
ELSE SET s = 1;
END IF;
RETURN s;
END //
DELIMITER;
I use that function in the following query, which is supposed to take the value returned in the TimeLeft function to determine the values for the start month (month(curdate())-#xx) and start day (#yy) for each project to calculate the hours:
AND time_records.record_date >= concat('2012/', month(curdate())-#xx , '/' , #yy)
Here's how I am setting the values for #xx and #yy:
SET #xx = 0; #this is the value that we will use to manipulate the month for the date range
SET #yy = 0;
#yy:= SELECT start_day_of_month FROM dashboard.client; #this doesn't seem to work
SELECT #xx:= TimeLeft(#yy,dayofmonth(curdate()));
I am getting some issues:
#yy is not getting the value - possibly my syntax is wrong?
The variables are set at the top of the code, so they are not getting changed for each project as they should be (there should be a different #xx and #yy for each project since each one has a different start and end date).
Here's the full query:
#below is where I assign the variables
SET #xx = 0; #this is the value that we will use to manipulate the month for the date range
SET #yy = 0;
#yy:= SELECT start_day_of_month FROM dashboard.client; #this doesn't seem to work
SELECT #xx:= TimeLeft(#yy,dayofmonth(curdate()));
# below is the MySQL query that is meant to use the variables assigned above
SELECT X.expr1 AS 'Project Name', #monthly_hours - SUM(X.expr2) AS 'Hours Billed
FROM
(SELECT
projects.name AS expr1
, sum(time_records.value) AS expr2
FROM project_objects
INNER JOIN projects
ON projects.id = project_objects.project_id
INNER JOIN time_records
ON time_records.parent_id = project_objects.id
WHERE time_records.parent_type = 'Task'
AND time_records.record_date >= concat('2012/', month(curdate())-#xx , '/' , #yy)
AND time_records.record_date <= curdate()
GROUP BY projects.name
UNION
SELECT
projects.name AS expr1
, sum(time_records.value) as expr2
FROM projects
INNER JOIN time_records
ON projects.id = time_records.parent_id
WHERE time_records.parent_type = 'Project'
AND time_records.record_date >= concat('2012/', month(curdate())-#xx , '/' , #yy)
AND time_records.record_date <= curdate()
GROUP BY projects.name) X
GROUP BY X.expr1
I think there is some issue of where I am assigning the variables #xx and #yy. These should be done for each individual Project, so putting them up on the top is probably not the best idea. I'm also not sure if I am assigning the #yy value correctly. It's supposed to query the value of the field of a table that is in another database but it keeps throwing a syntax error on the #yy assignment to that field.
Assign value to #yy inside select:
SELECT #yy:= start_day_of_month FROM dashboard.client;

can't get select query to work

I want to use a Select query from mysql database in C:
mysql_query(conn,"SELECT SI AS SUBSCRIBER_ID ,TG2 AS TAG_ID, SUM(CTR) AS NBR FROM (SELECT H.SUBSCRIBER_ID AS SI, TG.TAG_ID AS TG1,T.TAG_ID AS TG2, COUNT(TG.TAG_ID) AS COUNTER,CASE WHEN (TG.TAG_ID = T.TAG_ID) THEN COUNT(TG.TAG_ID) ELSE 0 END AS CTR from content_hits H left join CONTENT_TAG TG ON TG.CONTENT_ID = H.CONTENT_ID LEFT JOIN TAG T ON 1= 1 GROUP BY H.SUBSCRIBER_ID, TG.TAG_ID,T.TAG_ID) AS TAB GROUP BY SI,TG2");
After that, I want to use 'NBR' to fill an array of one dimension.
I tried this:
result = mysql_store_result(conn);
while ((row = mysql_fetch_row(result)))
{
t[i]=*row['NBR'];
printf("%d",t[i]);
}
But it didn't work.
You cannot access the row columns by name like you have t[i]=*row['NBR'];. Use for example fields = mysql_fetch_fields(result); to get the column names and iterate through the fields array to find which column id 'NBR' has. This id can then be used in t[i]=row[id];. This is all in the mysql connectors doc http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-fields.html