I need to create a function in Mysql that should do the following things:
select 3 columns value from a table in the following way:
SELECT column1, column2, column3 FROM table WHERE id = value;
sort values of these columns, in order to know the greatest, the middle and the least.
return the value: (greatest+middle-least)/3
My question is doublefold:
1) is there a way to obtain the middle value, as there are GREATEST() and LEAST()?
2) why the following function return always the following error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '2); END $$ DELIMITER' at line 27
DELIMITER $$
CREATE FUNCTION abc_value(partita INT)
RETURNS DOUBLE DETERMINISTIC
BEGIN
DECLARE a, b, c, column1, column2, column3 DOUBLE;
DECLARE a CURSOR FOR SELECT GREATEST(column1, column2, column3) FROM table where id = value;
DECLARE c CURSOR FOR SELECT LEAST(column1, column2, column3) FROM table where id = value;
DECLARE column1 CURSOR FOR SELECT column1 FROM table where id = value;
DECLARE quotax CURSOR FOR SELECT column2 FROM table where id = value;
DECLARE quota2 CURSOR FOR SELECT column3 FROM table where id = value;
IF column1<> a THEN
IF column1<> b THEN
SET c = column1;
END IF;
END IF;
IF column2<> a THEN
IF column2<> b THEN
SET c = column2;
END IF;
END IF;
IF column3<> a THEN
IF column3<> b THEN
SET c = column3;
END IF;
END IF;
RETURN ROUND((a+b-c)/3),2);
END$$
DELIMITER;
1) If you have 3 items and want to chose the middle one do something like this:
SELECT
value
FROM
table
ORDER BY
value
LIMIT 1,1 --index, amount (index starts from 0, so 1 is the second record)
Related
This question already has answers here:
MySQL find_in_set with multiple search string
(7 answers)
Closed 7 months ago.
I want to search multiple values from database field. below is my query.
SELECT * FROM `tablename`
WHERE FIND_IN_SET('12,13,15,15',category_id)
How i search its not working for me.
FIND_IN_SET() can only be used to search for a single value in a comma-separated list, it doesn't work with two lists.
You'll need to call it separately for each value.
SELECT * FROM tablename
WHERE FIND_IN_SET('12', category_id) OR FIND_IN_SET('13', category_id) OR FIND_IN_SET('15', category_id)
It would be better if you normalized your schema instead of using comma-separated lists. If you create a many-to-many table with the category IDs, you could do:
SELECT t1.*
FROM tablename AS t1
JOIN item_categories AS c ON t1.id = c.table_id
WHERE c.category_id IN (12, 13, 15)
FIND_IN_SET is not the solution.
Try to use REGEXP:
SELECT * FROM `tablename`
WHERE CONCAT(',', `category_id`, ',') REGEXP ',(12|13|15),';
But even if it's less pretty, it's better to use LIKE for performance reasons :
SELECT * FROM `tablename`
WHERE CONCAT(',', `category_id`, ',') LIKE '%,12,%' OR CONCAT(',', `category_id`, ',') LIKE '%,13,%' OR CONCAT(',', `category_id`, ',') LIKE '%,15,%';
I had a similar need. To solve this I created a couple of stored functions:
The first one is all_in_set(a,b), and checks if all items in a are in b:
delimiter $$
drop function if exists all_in_set;
CREATE FUNCTION all_in_set(set1 varchar(1024),set2 varchar(1024)) RETURNS boolean
NO SQL
DETERMINISTIC
COMMENT 'verify if all of the items in set1 are in set2'
BEGIN
declare i int default 0;
declare c varchar(128);
declare campos1 int;
set campos1=length(set1) - length(replace(set1, ',', '')) + 1;
set i=1;
while i<=campos1 do
set c=SUBSTRING_INDEX(SUBSTRING_INDEX(set1, ',', i), ',', -1);
if find_in_set(c,set2)=0 then
return false;
end if;
set i=i+1;
end while;
return true;
END$$
delimiter ;
for testing you can use:
> select all_in_set('a,b,c','a,b,c,d,e,f'),all_in_set('a,x,c','a,b,c,d,e,f');
+-----------------------------------+-----------------------------------+
| all_in_set('a,b,c','a,b,c,d,e,f') | all_in_set('a,x,c','a,b,c,d,e,f') |
+-----------------------------------+-----------------------------------+
| 1 | 0 |
+-----------------------------------+-----------------------------------+
The second ne is any_in_set(a,b) which returns true if at least one of the items in a is included in b.
delimiter $$
drop function if exists any_in_set;
CREATE FUNCTION any_in_set(set1 varchar(1024),set2 varchar(1024)) RETURNS boolean
NO SQL
DETERMINISTIC
COMMENT 'verify if at least one of the items in set1 is in set 2'
BEGIN
declare i int default 0;
declare c varchar(128);
declare campos1 int;
set campos1=length(set1) - length(replace(set1, ',', '')) + 1;
set i=1;
while i<=campos1 do
set c=SUBSTRING_INDEX(SUBSTRING_INDEX(set1, ',', i), ',', -1);
if find_in_set(c,set2)<>0 then
return true;
end if;
set i=i+1;
end while;
return false;
END$$
delimiter ;
for testing you can use:
> select any_in_set('x,y,c','a,b,c,d,e,f'),any_in_set('x,y,z','a,b,c,d,e,f');
+-----------------------------------+-----------------------------------+
| any_in_set('x,y,c','a,b,c,d,e,f') | any_in_set('x,y,z','a,b,c,d,e,f') |
+-----------------------------------+-----------------------------------+
| 1 | 0 |
+-----------------------------------+-----------------------------------+
1 row in set (0.018 sec)
This question already has answers here:
MySQL find_in_set with multiple search string
(7 answers)
Closed 7 months ago.
I want to search multiple values from database field. below is my query.
SELECT * FROM `tablename`
WHERE FIND_IN_SET('12,13,15,15',category_id)
How i search its not working for me.
FIND_IN_SET() can only be used to search for a single value in a comma-separated list, it doesn't work with two lists.
You'll need to call it separately for each value.
SELECT * FROM tablename
WHERE FIND_IN_SET('12', category_id) OR FIND_IN_SET('13', category_id) OR FIND_IN_SET('15', category_id)
It would be better if you normalized your schema instead of using comma-separated lists. If you create a many-to-many table with the category IDs, you could do:
SELECT t1.*
FROM tablename AS t1
JOIN item_categories AS c ON t1.id = c.table_id
WHERE c.category_id IN (12, 13, 15)
FIND_IN_SET is not the solution.
Try to use REGEXP:
SELECT * FROM `tablename`
WHERE CONCAT(',', `category_id`, ',') REGEXP ',(12|13|15),';
But even if it's less pretty, it's better to use LIKE for performance reasons :
SELECT * FROM `tablename`
WHERE CONCAT(',', `category_id`, ',') LIKE '%,12,%' OR CONCAT(',', `category_id`, ',') LIKE '%,13,%' OR CONCAT(',', `category_id`, ',') LIKE '%,15,%';
I had a similar need. To solve this I created a couple of stored functions:
The first one is all_in_set(a,b), and checks if all items in a are in b:
delimiter $$
drop function if exists all_in_set;
CREATE FUNCTION all_in_set(set1 varchar(1024),set2 varchar(1024)) RETURNS boolean
NO SQL
DETERMINISTIC
COMMENT 'verify if all of the items in set1 are in set2'
BEGIN
declare i int default 0;
declare c varchar(128);
declare campos1 int;
set campos1=length(set1) - length(replace(set1, ',', '')) + 1;
set i=1;
while i<=campos1 do
set c=SUBSTRING_INDEX(SUBSTRING_INDEX(set1, ',', i), ',', -1);
if find_in_set(c,set2)=0 then
return false;
end if;
set i=i+1;
end while;
return true;
END$$
delimiter ;
for testing you can use:
> select all_in_set('a,b,c','a,b,c,d,e,f'),all_in_set('a,x,c','a,b,c,d,e,f');
+-----------------------------------+-----------------------------------+
| all_in_set('a,b,c','a,b,c,d,e,f') | all_in_set('a,x,c','a,b,c,d,e,f') |
+-----------------------------------+-----------------------------------+
| 1 | 0 |
+-----------------------------------+-----------------------------------+
The second ne is any_in_set(a,b) which returns true if at least one of the items in a is included in b.
delimiter $$
drop function if exists any_in_set;
CREATE FUNCTION any_in_set(set1 varchar(1024),set2 varchar(1024)) RETURNS boolean
NO SQL
DETERMINISTIC
COMMENT 'verify if at least one of the items in set1 is in set 2'
BEGIN
declare i int default 0;
declare c varchar(128);
declare campos1 int;
set campos1=length(set1) - length(replace(set1, ',', '')) + 1;
set i=1;
while i<=campos1 do
set c=SUBSTRING_INDEX(SUBSTRING_INDEX(set1, ',', i), ',', -1);
if find_in_set(c,set2)<>0 then
return true;
end if;
set i=i+1;
end while;
return false;
END$$
delimiter ;
for testing you can use:
> select any_in_set('x,y,c','a,b,c,d,e,f'),any_in_set('x,y,z','a,b,c,d,e,f');
+-----------------------------------+-----------------------------------+
| any_in_set('x,y,c','a,b,c,d,e,f') | any_in_set('x,y,z','a,b,c,d,e,f') |
+-----------------------------------+-----------------------------------+
| 1 | 0 |
+-----------------------------------+-----------------------------------+
1 row in set (0.018 sec)
I want display selected table with quantity adding using stored procedure in php
here is my code
DELIMITER $$ CREATE DEFINER=`root`#`localhost` PROCEDURE `GetCustomerLevel`(IN p_barcode INT, OUT q_value INT) BEGIN
DECLARE q1 int; DECLARE q2 int;
DECLARE q3 int; DECLARE total int;
SET total :=0;
SELECT coalesce(sum(adjustment_quantity), 0) INTO q1 FROM adjustment_inventory WHERE item_barcode = p_barcode; SELECT coalesce(sum(opening_stock), 0) INTO q2 FROM openingstock WHERE item_barcode = p_barcode; SELECT coalesce(sum(inwardquantity), 0) INTO q3 FROM inwardmaster WHERE item_barcode = p_barcode; set total = q1+q2+q3; set q_value = total;
END$$ DELIMITER ;
When i call the particular data display but i want display selected table and if adding quantity display only positive and 0 not minus value show in php
I have this stored procedure that inserts data into the event table. The problem is that the value returned to PHP in select lastNum; is 1 lower (inserted as 2 but will return 1) than when it is used in the previous insert statement. This doesn't make any sense to me as the value is not changed in between the 2 lines.
DROP PROCEDURE IF EXISTS `insertEvent`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `insertEvent`(ptitle varchar(500), pdescription varchar(500), pxcoord int(4), pycoord int(4), ptype char(1), pnumber int(11))
begin
declare numExists int(1);
declare lastNum int(9);
select count(*) from event where `number`=pnumber;
select insAndIncEventId() into lastNum from dual;
if numExists > 0 then
update event set `number`=`number`+1 where `number`>=pnumber;
end if;
insert into event (id, title, description, xcoord, ycoord, `type`, `number`) values (lastNum, ptitle, pdescription, pxcoord, pycoord, ptype, pnumber);
select lastNum;
end$$
drop function if exists `insAndIncEventId`$$
create function `insAndIncEventId`() returns int(9)
begin
declare event_id int(9);
select nextId into event_id from eventid;
update eventid set nextid=nextid+1;
return event_id;
end$$
The PHP is as follows:
$eventid=$eventidstmt->fetch(PDO::FETCH_BOTH);
fb("event id count from sql:".count($eventid));
fb("event id from sql:".$eventid[0]);
i am trying to run an SQL Query to select all rows from a table and then display the column with the lowest value for each row.
for example, lets start with row1...
columns1, column2, column3, column4
the lowest value for this row is in column3 so i need to echo the column3 value then on row2, column4 has the lowest value so column4 should be displayed for this row.
i did try this code:
$sql="SELECT * from callplanmeta ";
$rs=mysql_query($sql,$conn) or die(mysql_error());
while($result=mysql_fetch_array($rs))
{
$sql2="SELECT *, MIN(NULLIF(".$result["callplanname"].",0)) as number2 from callplandata ";
echo $sql2;
$rs2=mysql_query($sql2,$conn) or die(mysql_error());
while($result2=mysql_fetch_array($rs2))
{
echo $result2["description"].' - '.number_format($result2["number2"],2).'<br><br>';
}
}
however i then realised that it was doing it the wrong way round and only showing the lowest value for 1 row
the column names in the callplandata table match the column callplanname in the callplanmeta table
the columns in the callplandata table are dynamic so they are changing all the time and more are constantly being added
you can also get result with this
SELECT Id,
CASE WHEN COLUMN1 <= COLUMN2 and COLUMN1 <= COLUMN3 THEN COLUMN1
WHEN COLUMN2 <= COLUMN1 and COLUMN2 <= COLUMN3 THEN COLUMN2
ELSE COLUMN3 END AS smallest
FROM table_name
you can get result for any number of columns.
First you will use this
SELECT
GROUP_CONCAT(COLUMN_NAME)
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
table_name = 'mytable'
AND
ORDINAL_POSITION>2
To retrieve all columns, form it as a string in PHP and then run the following (col1,col2,col3) needs to be replaced with the column_name string that you can form using the previous query.
PHP Code added
From your code I understand two things, first you dont need a while loop for the first query because it would return only one record and you need a while loop for the second query because it would return multiple rows, let me try to make up the code accordingly
<?php
$field_string= $mysqli->query("SELECT GROUP_CONCAT(COLUMN_NAME) AS field_string
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = `callplandata`
AND ORDINAL_POSITION>2")->fetch_object()->field_string;
(The >2 above means this will ignore the first two columns, which in your case seems to be number, description. IF you have more or less fields to be ignored then you can modify this number accordingly)
You can then use this field_string value into your other query that needs to find the least
$sql2="SELECT LEAST(".$field_string.") AS number FROM `callplandata`";
$rs2=mysql_query($sql2,$conn);
while($result2=mysql_fetch_array($rs2))
{
echo $result2["number"].'<br>';
}
?>
This will give you the lowest among all the columns other than the first two columns for all the rows and echo it on screen. I am not a PHP programmer, so just about made up the code in PHP, there could be minor errors.
You can solve this puzzle this approach:
SELECT
(SELECT columns1 from myTable) as myField
UNION
(SELECT column2 from myTable)
UNION
(SELECT column3 from myTable)
order by myField ASC LIMIT 1