How to disaggregate Stored Function Output phpmyadmin - mysql

I have created a stored function within phpmyadmin which calculates across several fields to derive an overall value. I'm using a function as the calculation needs to be used several times, across several scripts so to my knowledge, this is the most efficient way to do this to minimise code updates.
I've tested the function and it works in terms of providing an output, however when I combine it with my query, it provides an aggregated figure across the query results rather than a specific figure per row:
Function Code:
BEGIN
DECLARE Output_needed INT(7);
SET Output_needed = (select SUM(Col1+Col2+Col3) from table1);
RETURN (Output_needed);
END
SQL Query:
Select ID, function_name(), Col1, Col2, Col3 from table1
Required Query Output
ID Function Returns *Output_needed* Col1 Col2 Col3
1 100 *10* 4 4 2
2 100 *50* 10 20 20
3 100 *5* 1 2 2
4 100 *15* 10 2 3
5 100 *20* 6 3 1
Can someone advise where I am going wrong? I assume I've missed a step somewhere but cant seem to figure it out.
Thanks!

The function select query doesn't have the condition to get the single row result.So, I have just added the one field for conditional use.
Function:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `function_name`(pk_field INT) RETURNS int(11)
BEGIN
DECLARE output_needed INT;
SELECT SUM(Col1+Col2+Col3) INTO output_needed FROM table1 WHERE pk_field_name = pk_field;
RETURN output_needed;
END$$
DELIMITER ;
SELECT Query:
Select ID, function_name(pk_field_name), Col1, Col2, Col3 from table1

Related

SQL - MYSQL One query recieving set limit on different column values

Lets say i have a table with a set of different columns (offcourse),
Example :
Table
id
col1 INTEGER(1), // 0 || 1
col2 // --||--
col3 // --||--
col4 // --||--
Is it possible, in 1 query to select 4 rows where col1=1 and then select 4 rows where col2=1 and then select 4 rows where col3=1 etc etc. I think you understand what i mean.
What i have done so far is to make 4 different queries OR make one query and just do a (col1 = 1 OR col2=1 OR... etc).
This works but if i limit that result to lets say 16, then i might get 15 rows with col1=1 and maybe 1 row with col2=1 and then col3,col4 - no result.
So dear fellas; is there a way to do this in 1 query (i think not)
Select * from table where col1=1 limit 4
Union
Select * from table where col2=1 limit 4
Union
Select * from table where col3=1 limit 4
Union
Select * from table where col4=1 limit 4
This will get you one result with 16records max. If there are less then 4rows for a certin criteria, you'll get less rows. Duplicates will be removed, resulting in less then 16 rows. Not different rows.
If for a single row col1=1 and col2=1, then it might be returned twice if you use union all, but just union is slower with large datasets
I think you are looking for the UNION ALL construct. You may simply write
SELECT * FROM tab WHERE col1 = 1
UNION ALL
SELECT * FROM tab WHERE col2 = 2
UNION ALL
SELECT * FROM tab WHERE col3 = 3
and so on. Just be aware of a fact that the rows may be duplicated in the result (if they satisfy more criteria from the conditions).

Reorganizing mysql aggregate row into single piece rows

Consider the following mysql table:
ID WeightS AmountS WeightM AmountM WeightL AmountL Someothercolumnshere
1 6 3 10 2 18 2 ...
I need to reorganize this data into a pivot-friendly table, where each piece in the amount columns should be one result row. E.g. from the first two columns, WeightS and AmountS, the SELECT should produce 3 result rows, each having a weight of 2 kgs (=6 kgs total). So the full result table should be like this:
Weight Someothercolumnshere
2 ...
2 ...
2 ...
5 ...
5 ...
9 ...
9 ...
I don't even know if there's a SQL syntax which is able to do this kind of operation? I've never had a request like this before. Worst case scenario, I have to do it in php instead, but I think MYSQL is a lot more fun :p
I've built the schema on sqlfiddle, but I'm afraid that's all I've got.
You need a Tally table for the task like this. Create as much rows as needed in it.
Create table Tally(`N` int);
insert into Tally( `N`) values(1),(2),(3),(4),(5);
Then
(select `ID`, `WeightS`/`AmountS`, `Someothercolumnshere`
from Catches
join Tally on Catches.`AmountS` >= Tally.`N`
)
UNION ALL
(select `ID`, `WeightL`/`AmountL`, `Someothercolumnshere`
from Catches
join Tally on Catches.`AmountL` >= Tally.`N`
)
UNION ALL
(select `ID`, `WeightM`/`AmountM`, `Someothercolumnshere`
from Catches
join Tally on Catches.`AmountM` >= Tally.`N`
)

Different results for the same query but inside a function

I have a table with Pontuation(Pontuacao) and an unique number for Accomodation(Estadia) and i want to calculate the average pontuation of each accomodation.
This is the table:
Estadia | Pontuacao
-------------------
5 | 5
-------------------
5 | 5
So i made this funcion:
delimiter $$
create function mediapontuacao(estadia int)
returns float
begin
declare media float;
select sum(Pontuacao)/count(*) into media
from EstadiaUtilizador
where Estadia = estadia;
return media;
end $$
If i do this
select mediapontuacao(5); //calculate average pontuation of the accomodation which number is 5
This query gives me the value of 3.965.
But if i do this
select sum(Pontuacao)/count(*)
from EstadiaUtilizador
where Estadia = 5;
In other words calculate average pontuation of the accomodation which number is 5, the exact same thing the function i wrote should do and this query gives me the value of 5.00 which is the correct answer.
I am puzzled why i get different values when it should give the same value, i think.
The problem is here:
where Estadia = estadia
which is the same as, say,
where 1 = 1
Your parameter and column should have different names, so the DBMS knows what you are talking about.
You must use GROUP BYclause
select
Estadia,
sum(Pontuacao) / count(*) as mediapontuacao
from
EstadiaUtilizador
group by
Estadia
having Estadia = 5

insert data into one table from another table on specific condition

I have "table1" in which master data store like -
id name create_date validity expire_date
1 A 2015-08-01 3 2015-11-01
2 B 2015-09-01 12 2016-08-01
3 C 2015-09-15 1 2015-10-15
But now want to insert data in "table2" for expire_date according to validity period like without changing in front end. using trigger or procedure want to achieve this task.
id parent_id expire_date
1 1 2015-09-01
2 1 2015-10-01
3 1 2015-11-01
How can I achieve this using procedure or trigger.
It's hard to be specific because your question is not specific.
In general, here's the procedure to follow to design a query to insert stuff from one table into another.
First, write a SELECT query yielding a resultset containing the rows and columns you want inserted into your table. Use a list of columns to get the right columns, and appropriate WHERE clauses to get the right rows. Eyeball that query and that resultset to make sure it contains the correct information.
Second, prepend that debugged SELECT query with
INSERT INTO target_tablename (col, col, col)
Test this to make sure the correct rows are being inserted into your target table.
Third, create yourself an EVENT in your MySQL server to run the query you have just written. The event will, at the appropriate times of day, run your query.
If you take these steps out of order, you'll probably be very confused.
Can achieve the task using Store Procedure -
CREATE DEFINER=`root`#`localhost` PROCEDURE `addexpire`(IN uname varchar(50), IN cdate date, IN vm int)
BEGIN
insert into table1 (name,create_date,validity) values (uname,cdate,vm);
BEGIN
declare uparent_id INT;
declare v_val int default 0;
SET uparent_id = LAST_INSERT_ID();
while v_val < vm do
BEGIN
declare expire_date date;
SET expire_date = DATE_ADD(cdate,INTERVAL v_val+1 MONTH);
insert into table2 (parent_id,expire_date) values (uparent_id,expire_date);
set v_val=v_val+1;
END;
end while;
END;
END

MySql, Without loop filling a table with semi/random data

How to have this code/output in MySql:
Had a recursive cte in MSSQL to fill a table with random data without loop e.g begin/end. Searched for similar logic in MySql but most or all solutions were using begin/end or for loops. Wonder if you could suggest a solution without loop in MySql.
Thanks
--MSSQL cte:------------------------------------
with t1( idi,val ) as
(
select
idi=1
,val=cast( 1 as real)
union all
select
idi=idi+1
,val=cast(val+rand() as real)
from t1
where idi<5
)
select idi,val from t1
-----------------------------------------------
Output in MSSQL:( semi random values)
idi | val
-------------
1 | 1
2 | 1.11
3 | 1.23
4 | 1.35
5 | 1.46
Edit:
Regarding discussions which considers set based codes as loop based codes indeed, I could understand this but just out of interest gave it a try in MSSQL 2008r2, here is the result:
1- above code with 32000 recursion took 2.812 sec
2- above output created with WHILE BEGIN END loop for 32000 took 53.640 sec
Obviously this is a big difference in execution time.
Here is the loop based code:
insert into #t1(idi,val)
select
idi=1
,val=1
declare #ii int = 2
while #ii<32000
begin
insert into #t1(idi,val)
select
idi=idi+1
,val=val+rand()
from #t1
where idi=#ii-1
set #ii=#ii+1
end
select * from #t1
MySql doesn't support CTE.
You need a procedure or some tricky queries like this one:
set #id=0;
set #val=0;
SELECT #id:=#id+1 As id,
#val:=#val+rand() As val
FROM information_schema.tables x
CROSS JOIN information_schema.tables y
LIMIT 10