MySQL select in function - mysql

I'm trying to write a MySQL function with a select inside, but always get a NULL return
CREATE FUNCTION test (i CHAR)
RETURNS CHAR
NOT DETERMINISTIC
BEGIN
DECLARE select_var CHAR;
SET select_var = (SELECT name FROM table WHERE id = i);
RETURN select_var;
END$$
mysql> SELECT test('1')$$
+-----------------+
| test('1') |
+-----------------+
| NULL |
+-----------------+
1 row in set, 1 warning (0.00 sec)
mysql>
mysql>
mysql> SHOW WARNINGS
-> $$
+---------+------+----------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------+
| Warning | 1265 | Data truncated for column 'i' at row 1 |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

Does it works with this :
CREATE FUNCTION test (i CHAR)
RETURNS VARCHAR(SIZE)
NOT DETERMINISTIC
BEGIN
DECLARE select_var VARCHAR(SIZE);
SET select_var = (SELECT name FROM table WHERE id = i);
RETURN select_var;
END$$

try to specify the size of char return type. for example if name can be of 20 characters then try
RETURNS CHAR(20)

You have a error in your code, if you need only a result, you obtain it from a simple select an assign with the word INTO like this, remember, it return the last one.
CREATE FUNCTION test (i CHAR)
RETURNS VARCHAR(SIZE)
NOT DETERMINISTIC
BEGIN
DECLARE select_var VARCHAR(SIZE);
SELECT name INTO select_var FROM table WHERE id = i;
RETURN select_var;
END$$

DELIMITER $$
USE `mydatabase`$$
DROP FUNCTION IF EXISTS `fnGetActiveEventId`$$
CREATE DEFINER=`mydbuser`#`%` FUNCTION `fnGetActiveEventId`() RETURNS INT(11)
BEGIN
SET #eventId = (SELECT EventId FROM `Events` WHERE isActive=1 ORDER BY eventId DESC LIMIT 1);
RETURN #eventId;
END$$
DELIMITER ;

You have a table named table? Escape that name if that is really what it is:
(SELECT name FROM `table` WHERE id = i);
or put the table name in....it seems to be missing

Related

Error when creating Index for table Mysql

I'm working on create index for table with mysql.
I've 2 tables:
1. account
2. x_activity (x is the account_id related to "account" table, EX: 1_activity, 2_activity).
So i've created an "Index" for activity table:
Here are my code:
DROP PROCEDURE if exists update_index_for_table;
DELIMITER $$
CREATE PROCEDURE update_index_for_table()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE accountid INT;
--
-- GET ALL ACCOUNT ID
--
DECLARE accountids CURSOR FOR SELECT account_id FROM account;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
--
-- LOOP
--
OPEN accountids;
read_loop: LOOP
FETCH accountids INTO accountid;
IF done THEN
LEAVE read_loop;
END IF;
--
-- INDEX FOR ACTIVITY
--
SET #update_activity_table_1 = CONCAT("
IF (
SELECT COUNT(1) FROM INFORMATION_SCHEMA.STATISTICS
WHERE `TABLE_SCHEMA` = DATABASE() AND TABLE_NAME='",accountid,"_activity' AND
INDEX_NAME='IDX_",accountid,"_ACTIVITY_ACTIVITY_ID'
) != 1
THEN
ALTER TABLE ",accountid,"_activity
ADD KEY `IDX_",accountid,"_ACTIVITY_ACTIVITY_ID` (`activity_id`);
END IF;
");
PREPARE stmt from #update_activity_table_1;
EXECUTE stmt;
END LOOP;
CLOSE accountids;
END$$
DELIMITER ;
CALL update_index_for_table();
But then, for some php/mysql version (i think), its cause an error like this:
#1064 - 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 'IF (
SELECT COUNT(1) FROM INFORMATION_SCHEMA.STATISTICS
WHERE `TABLE_SCHEM' at line 1
I've tested this code and its work fine:
SELECT COUNT(1) FROM INFORMATION_SCHEMA.STATISTICS
WHERE `TABLE_SCHEMA` = DATABASE() AND TABLE_NAME='",accountid,"_activity' AND
INDEX_NAME='IDX_",accountid,"_ACTIVITY_ACTIVITY_ID'
Here are my php/sql version:
phpmyadmin: 4.8.5, php version: 7.2.7, mysql: 5.6.45
Please help, thanks.
There are a couple of constraints on what you are trying to do here 1) you cannot run an if statement outwith a stored program 2)if you pass a query to dynamic sql and the query does not find anything the continue handler will be invoked and the loop will terminate (unexpectedly) early. The approach then is to split the functionality to first check existence by amending the 'find' to insert a value to a user defined variable and at the same time ensure the handler is not hijacked by a not found by including a look up on a table which will definitely contain something (in this case information.schema_tables.
So given
DROP PROCEDURE if exists p;
DELIMITER $$
CREATE PROCEDURE p()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE accountid INT;
--
-- GET ALL ACCOUNT ID
--
DECLARE accountids CURSOR FOR SELECT account_id FROM account;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
--
-- LOOP
--
OPEN accountids;
read_loop: LOOP
FETCH accountids INTO accountid;
select accountid;
IF done = true THEN
select accountid, 'leaving';
LEAVE read_loop;
END IF;
--
-- INDEX FOR ACTIVITY
--
SET #test := 0;
SET #update_activity_table_1 :=
(concat('SELECT case when index_name is null then 1 else 0 end into #test FROM
information_schema.tables it
left join INFORMATION_SCHEMA.STATISTICS iss ',
' on iss.table_schema = it.table_schema and iss.table_name = it.table_name and ',
'INDEX_NAME=',char(39),'IDX_',accountid,'_ACTIVITY_ACTIVITY_ID',char(39),
' WHERE it.TABLE_SCHEMA = ', char(39),'test',char(39), ' AND ',
'it.TABLE_NAME=',char(39),accountid,'_activity', char(39),
';'
)
)
;
select #update_activity_table_1;
PREPARE stmt from #update_activity_table_1;
EXECUTE stmt;
deallocate prepare stmt;
if #test = 1 then
select 'Did not find index for ' , accountid, '_extract';
else
select 'Found index for ' , accountid, '_extract';
end if;
END LOOP;
CLOSE accountids;
END $$
DELIMITER ;
call p();
I'll leave you to build the alter statement and insert into the if statement.
given
use test;
drop table if exists account,`1_activity`,`2_activity`,`64_activity`;
create table account (account_id int);
create table `1_activity`(id int);
create table `2_activity`(id int);
create table `64_activity`(id int);
insert into account values (1),(2),(64);
MariaDB [test]> call p();
+-----------+
| accountid |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| #update_activity_table_1 |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| SELECT case when index_name is null then 1 else 0 end into #test FROM
information_schema.tables it
left join INFORMATION_SCHEMA.STATISTICS iss on iss.table_schema = it.table_schema and iss.table_name = it.table_name and INDEX_NAME='IDX_1_ACTIVITY_ACTIVITY_ID' WHERE it.TABLE_SCHEMA = 'test' AND it.TABLE_NAME='1_activity'; |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
+-------------------------+-----------+----------+
| Did not find index for | accountid | _extract |
+-------------------------+-----------+----------+
| Did not find index for | 1 | _extract |
+-------------------------+-----------+----------+
1 row in set (0.28 sec)
+-----------+
| accountid |
+-----------+
| 2 |
+-----------+
1 row in set (0.30 sec)
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| #update_activity_table_1 |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| SELECT case when index_name is null then 1 else 0 end into #test FROM
information_schema.tables it
left join INFORMATION_SCHEMA.STATISTICS iss on iss.table_schema = it.table_schema and iss.table_name = it.table_name and INDEX_NAME='IDX_2_ACTIVITY_ACTIVITY_ID' WHERE it.TABLE_SCHEMA = 'test' AND it.TABLE_NAME='2_activity'; |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.30 sec)
+-------------------------+-----------+----------+
| Did not find index for | accountid | _extract |
+-------------------------+-----------+----------+
| Did not find index for | 2 | _extract |
+-------------------------+-----------+----------+
1 row in set (0.47 sec)
+-----------+
| accountid |
+-----------+
| 64 |
+-----------+
1 row in set (0.49 sec)
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| #update_activity_table_1 |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| SELECT case when index_name is null then 1 else 0 end into #test FROM
information_schema.tables it
left join INFORMATION_SCHEMA.STATISTICS iss on iss.table_schema = it.table_schema and iss.table_name = it.table_name and INDEX_NAME='IDX_64_ACTIVITY_ACTIVITY_ID' WHERE it.TABLE_SCHEMA = 'test' AND it.TABLE_NAME='64_activity'; |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.50 sec)
+-------------------------+-----------+----------+
| Did not find index for | accountid | _extract |
+-------------------------+-----------+----------+
| Did not find index for | 64 | _extract |
+-------------------------+-----------+----------+
1 row in set (0.66 sec)
+-----------+
| accountid |
+-----------+
| 64 |
+-----------+
1 row in set (0.67 sec)
+-----------+---------+
| accountid | leaving |
+-----------+---------+
| 64 | leaving |
+-----------+---------+
1 row in set (0.67 sec)
Query OK, 0 rows affected (0.69 sec)
Firstly, i believe accound_id and activity_id are both your unique keys, but what am not sure if you are auto incrementing it, check to see if the auto increment is check.

mysql stored procedure issue: insert runs first and always whatever If condition I put

Need quick help, in below SQL insert is fired first then other select queries are fired. insert statement is executed whatever If condition I put.
I am testing this in phpMyAdmin.
I tried to also convert the insert statement in to separate stored procedure but then also result is same.
Thanks in Advance..
DELIMITER $$
DROP PROCEDURE IF EXISTS get_top$$
CREATE PROCEDURE get_top(
IN tolerance INT,
IN cred INT,
IN cgreen INT,
IN cblue INT,
IN userID INT,
IN mapID BIGINT
)
BEGIN
DECLARE topList VARCHAR(255) DEFAULT NULL;
DECLARE top1 VARCHAR(255) DEFAULT NULL;
DECLARE top2 VARCHAR(255) DEFAULT NULL;
DECLARE top3 VARCHAR(255) DEFAULT NULL;
DECLARE get_result VARCHAR(255) DEFAULT NULL;
DECLARE dev_notes VARCHAR(255) DEFAULT NULL;
SET sql_mode = 'NO_UNSIGNED_SUBTRACTION';
SELECT CONCAT(top_1, ';', top_2, ';', top_3) INTO topList
FROM Tops
WHERE red = cred AND green = cgreen AND blue = cblue
ORDER BY top_ID asc
LIMIT 0 , 1 ;
SELECT topList,cred,cgreen,cblue;
IF topList IS NULL THEN BEGIN
SELECT top_1, top_2, top_3
INTO top1, top2, top3
FROM Tops
WHERE top_1>0
LIMIT 0 , 1 ;
SELECT "in IF",top1,CHAR_LENGTH(top1);
IF (top1 IS NULL) THEN
SET get_result:= 'None';
ELSE
SET get_result:= 'Nearest';
END IF;
SET topList=top1+ ','+ top2+ ','+ top3;
SET dev_notes='result:'+get_result+' mapID:'+mapID+' User ID:'+userID+' date/time:'+NOW();
SELECT topList,get_result;
INSERT INTO Tops (red,green,blue,top_1,top_2,top_3,notes) VALUES (cred,cgreen,cblue,top1,top2,top3,dev_notes);
END;
ELSE BEGIN
SET get_result:= 'Exact';
SELECT "in else",topList,get_result,dev_notes;
END; END IF;
IF CHAR_LENGTH(mapID)>0 THEN
UPDATE Map SET toponym=toponymList, toponym_conf=get_result WHERE map_ID=mapID;
END IF;
END$$
DELIMITER ;
I have amended you code to write debug messages to a table so that I can illustrate what is happening.
DELIMITER $$
DROP PROCEDURE IF EXISTS get_top$$
CREATE PROCEDURE get_top(
IN tolerance INT,
IN cred INT,
IN cgreen INT,
IN cblue INT,
IN userID INT,
IN mapID BIGINT
)
BEGIN
DECLARE topList VARCHAR(255) DEFAULT NULL;
declare topsid int;
DECLARE top1 VARCHAR(255) DEFAULT null;
DECLARE top2 VARCHAR(255) DEFAULT null;
DECLARE top3 VARCHAR(255) DEFAULT null;
DECLARE get_result VARCHAR(255) DEFAULT NULL;
DECLARE dev_notes VARCHAR(255) DEFAULT NULL;
SET sql_mode = 'NO_UNSIGNED_SUBTRACTION';
SELECT top_id,CONCAT(top_1, ';', top_2, ';', top_3) INTO topsid,topList
FROM Tops
WHERE red = cred AND green = cgreen AND blue = cblue
ORDER BY top_ID asc
LIMIT 0 , 1 ;
insert into debug_table (msg) values (concat('Start topsid:', coalesce(topsid,'not found'),' toplist:',coalesce(topList,'null'),' cred:',cred,' cgreen:',cgreen,' cblue:',cblue));
IF topList IS NULL THEN
BEGIN
SELECT top_1, top_2, top_3
INTO top1, top2, top3
FROM Tops
WHERE top_1>0
LIMIT 0 , 1 ;
insert into debug_table (msg) values (concat("in IF",' top1:',coalesce(top1,'null'),' len top1:',if(top1 is not null,CHAR_LENGTH(top1),0)));
IF (top1 IS NULL) THEN
SET get_result:= 'None';
ELSE
SET get_result:= 'Nearest';
END IF;
SET topList=top1+ ','+ top2+ ','+ top3;
#SET dev_notes='result:'+get_result+' mapID:'+mapID+' User ID:'+userID+' date/time:'+NOW();
SET dev_notes=CONCAT('result:',get_result,' mapID:',mapID,' User ID:',userID,' date/time:',NOW());
insert into debug_table (msg) values (concat('about to insert toplist:',coalesce(topList,'null'),' get_result:',get_result,' dev_notes:',DEV_NOTES));
INSERT INTO Tops (red,green,blue,top_1,top_2,top_3,notes) VALUES (cred,cgreen,cblue,top1,top2,top3,dev_notes);
END;
ELSE BEGIN
SET get_result:= 'Exact';
insert into debug_table (msg) values (concat(' in else toplist:',coalesce(topList,'null'),' get_result:',get_result,' dev_notes:',DEV_NOTES));
END;
END IF;
#SELECT CHAR_LENGTH(MAPID);
#IF CHAR_LENGTH(mapID)>0 THEN
# UPDATE Map SET toponym=toponymList, toponym_conf=get_result WHERE map_ID=mapID;
#END IF;
END$$
DELIMITER ;
So if tops looks something like this
DROP TABLE IF EXISTS TOPS;
CREATE TABLE TOPS(TOP_ID INT AUTO_INCREMENT PRIMARY KEY,
red INT,green INT,blue INT,top_1 varchar(4),top_2 varchar(4),top_3 varchar(4),notes VARCHAR(100));
And I do this
ariaDB [sandbox]> TRUNCATE TABLE TOPS;
Query OK, 0 rows affected (0.16 sec)
MariaDB [sandbox]> truncate table debug_table;
Query OK, 0 rows affected (0.24 sec)
MariaDB [sandbox]> CALL GET_TOP(1,1,1,1,'1','1');
Query OK, 1 row affected (0.17 sec)
MariaDB [sandbox]> select * from tops;
+--------+------+-------+------+-------+-------+-------+-------------------------------------------------------------+
| TOP_ID | red | green | blue | top_1 | top_2 | top_3 | notes |
+--------+------+-------+------+-------+-------+-------+-------------------------------------------------------------+
| 1 | 1 | 1 | 1 | NULL | NULL | NULL | result:None mapID:1 User ID:1 date/time:2017-07-20 09:45:00 |
+--------+------+-------+------+-------+-------+-------+-------------------------------------------------------------+
1 row in set (0.00 sec)
MariaDB [sandbox]> CALL GET_TOP(1,1,1,1,'1','1');
Query OK, 1 row affected (0.10 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> SELECT * FROM debug_table;
+----+--------------------------------------------------------------------------------------------------------------------+
| id | msg |
+----+--------------------------------------------------------------------------------------------------------------------+
| 1 | Start topsid:not found toplist:null cred:1 cgreen:1 cblue:1 |
| 2 | in IF top1:null len top1:0 |
| 3 | about to insert toplist:null get_result:None dev_notes:result:None mapID:1 User ID:1 date/time:2017-07-20 09:45:00 |
| 4 | Start topsid:1 toplist:null cred:1 cgreen:1 cblue:1 |
| 5 | in IF top1:null len top1:0 |
| 6 | about to insert toplist:null get_result:None dev_notes:result:None mapID:1 User ID:1 date/time:2017-07-20 09:45:00 |
+----+--------------------------------------------------------------------------------------------------------------------+
6 rows in set (0.00 sec)
I would expect on the first call that no record will be found in tops and topslist will be null and this is proved by the first three records in the debug_table. On the second call a record is found in tops but since top_1,top_2 and top_3 are null then topslist is again null. The select in the if "fails" because there are no tops_1 records with a value > 0 so another record is inserted with null values to tops this is traceable in the debug_table records 4 -6. BTW checking a varchar field for a value > 0 is not a good idea.

Launch Trigger and Routine on Insert

Im attempting to have MySQL automatically insert data into another table after insert into one. I know to do this required Triggers and potentially Routines. I have a couple I've been trying to modify to do what I wish to accomplish but I appear to be hitting a dead end due to lack of experience, so help is greatly appreciated.
The table that has data inserted (db_tou_tracking):
tou_tracking_ID ICP_ID tou_tracking_start tou_tracking_units
----------------------------------------------------------------
2 2 2013-03-01 10.77
3 2 2013-03-01 11.00
There are a couple of other columns here, that separate out by time, but I'm interested by day, rather than time.
Table data should go into compounded. So as each of the above rows are inserted, it will either create a new row if the tou_tracking_start and ICP_ID do not exist, or update the existing row.
tou_tracking_daily_ID ICP_ID tou_tracking_start tou_tracking_units
------------------------------------------------------------------------------
1 2 2013-03-01 21.77
2 2 2013-03-02 25.36
Below is my Tigger (no errors when setup on MySQL, and it does appear to call when data is attempted to be inserted):
BEGIN
DECLARE presentcount INT;
SET presentcount = (SELECT count(*) FROM db_tou_tracking_daily WHERE tou_tracking_daily_day =
(SELECT tou_tracking_start FROM db_tou_tracking WHERE ICP_ID = db_tou_tracking_daily.ICP_ID ORDER BY tou_tracking_ID DESC)
);
IF (presentcount = 0) THEN
INSERT INTO db_tou_tracking_daily (ICP_ID, tou_tracking_daily_day, tou_tracking_start)
SELECT NEW.ICP_ID, NEW.tou_tracking_start, NEW.tou_tracking_units, calculate_units(NEW.ICP_ID, NEW.tou_tracking_start);
ELSE
UPDATE db_tou_tracking_daily SET tou_tracking_daily_units = calculate_units(NEW.ICP_ID, tou_tracking_daily_day)
WHERE ICP_ID = NEW.ICP_ID AND tou_tracking_daily_day = NEW.tou_tracking_start;
END IF;
END
and then the routine it calls to calculate units.
CREATE DEFINER=`root`#`localhost` FUNCTION `calculate_units`(ICP_ID INT, tou_tracking_daily_day DATE) RETURNS float
BEGIN
DECLARE units FLOAT;
DECLARE last_time DATE;
DECLARE last_watts INT;
DECLARE this_time DATETIME;
DECLARE this_watts INT;
DECLARE loop_done INT;
DECLARE curs CURSOR FOR
SELECT tou_tracking_timestart, tou_tracking_units FROM db_tou_tracking WHERE ICP_ID = ICP_ID AND tou_tracking_start = tou_tracking_daily_day ORDER BY tou_tracking_start DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET loop_done = 1;
SET last_time = (SELECT max(tou_tracking_start) FROM db_tou_tracking WHERE ICP_ID = ICP_ID AND tou_tracking_start < tou_tracking_daily_day);
SET last_watts = (SELECT tou_tracking_units FROM db_tou_tracking WHERE ICP_ID = ICP_ID AND tou_tracking_start = last_time);
SET last_time = CAST(tou_tracking_start AS DATETIME);
SET loop_done = 0;
SET units = 0;
OPEN curs;
REPEAT
FETCH curs INTO this_time, this_watts;
IF last_watts IS NOT NULL THEN
SET units = units + (last_watts + this_watts);
END IF;
SET last_watts = this_watts;
SET last_time = this_time;
UNTIL loop_done END REPEAT;
CLOSE curs;
END
The routine throws back an error on line 3 when I try to run the SQL to setup the routine, but I can't see anything obviously wrong, but I'm not exactly sure what I'd be looking for.
Any help with this is hugely appreciated and any pointers that can be given along the way. Thanks :)
Attempting to replicate your issue, I'm going to guess the error you get is probably because you're not using a DELIMITER.
Executing a similar function creation statement I get the same error, and a syntax parse suggests it's not expecting the delimiter ;.
The one that causes an error on line 3.
CREATE DEFINER = 'root'#'localhost' FUNCTION test_func(foo INT) RETURNS FLOAT
BEGIN
DECLARE bar FLOAT;
RETURN 1;
END
Fixing it using delimiters.
DELIMITER $$
CREATE DEFINER = 'root'#'localhost' FUNCTION test_func(foo INT) RETURNS FLOAT
BEGIN
DECLARE bar FLOAT;
RETURN 1;
END$$
DELIMITER ;
If this does not fix your problem, are you able to provide a self contained function that doesn't rely on any of your existing tables, that also produces the same error so it can be tested?
create table t1 ( start date not null, units decimal(5,2) not null );
create table t2 ( start date not null, units decimal(5,2) not null );
delimiter //
create trigger trg1
after insert on t1
for each row
begin
update t2
set units = units + new.units
where start = new.start;
if ROW_COUNT() = 0 then
insert into t2
(start, units)
values (new.start, new.units);
end if;
end //
delimiter ; //
mysql> select * from t1;
Empty set (0.01 sec)
mysql> select * from t2;
Empty set (0.00 sec)
mysql> insert into t1 (start, units) values ('2014-01-01',100.02);
Query OK, 1 row affected (0.01 sec)
mysql> select * from t1;
+------------+--------+
| start | units |
+------------+--------+
| 2014-01-01 | 100.02 |
+------------+--------+
1 row in set (0.00 sec)
mysql> select * from t2;
+------------+--------+
| start | units |
+------------+--------+
| 2014-01-01 | 100.02 |
+------------+--------+
1 row in set (0.00 sec)
mysql> insert into t1 (start, units) values ('2014-01-01',200.05);
Query OK, 1 row affected (0.01 sec)
mysql> select * from t1;
+------------+--------+
| start | units |
+------------+--------+
| 2014-01-01 | 100.02 |
| 2014-01-01 | 200.05 |
+------------+--------+
2 rows in set (0.01 sec)
mysql> select * from t2;
+------------+--------+
| start | units |
+------------+--------+
| 2014-01-01 | 300.07 |
+------------+--------+
1 row in set (0.01 sec)

mysql get ascii code dump for string

In MySQL, is there a way in a simple SELECT to obtain a sequence of ASCII code/code points for each character in a varchar value? I'm more familiar with Oracle, which has the DUMP function that can be used for this.
For example, select some_function('abcd') would return something like 96,97,98,99?
This is about the closest equivalent I'm aware of in MySQL:
mysql> select hex('abcd');
+-------------+
| hex('abcd') |
+-------------+
| 61626364 |
+-------------+
1 row in set (0.00 sec)
I don't know of a mysql_function that will do that, but you can take the string in php, convert to an array, then take the ordinal of the character.
$char_value_array = {};
foreach($mysql_fetched_str as $char)
array_push($char_value_array, ord($char)
You can create a function like this:
CREATE FUNCTION dump (s CHAR(20)) RETURNS CHAR(50) DETERMINISTIC
BEGIN
DECLARE result CHAR(50);
DECLARE i INT;
DECLARE l INT;
SET result = ASCII(SUBSTRING(s,1,1));
SET l = LENGTH(s);
SET i = 2;
WHILE (i <= l) DO
SET result = CONCAT(result, ',', ASCII(SUBSTRING(s,i,1)));
SET i = i + 1;
END WHILE;
RETURN result;
END;
And then use it in the SELECT:
SELECT dump('abcd') FROM test LIMIT 1
Increase CHAR(20) and CHAR(50) definitions if you need to use it with longer strings.

MySQL stored function, how to check for no rows and not generate a warning?

I've this function:
DROP FUNCTION IF EXISTS find_linkid;
DELIMITER //
CREATE FUNCTION `find_linkid`(pc1 VARCHAR(50)
RETURNS INT
BEGIN
DECLARE linkId int;
SELECT a.id INTO linkId FROM PC_A a WHERE a.pc=pc1;
ON
IF linkId IS NULL THEN
SELECT b.id INTO linkId FROM PC_B b WHERE b.pc=pc1;
END IF;
RETURN linkId;
END
//
Basically, run one query, if that doesn't return anything (the a.id is declared as NOT NULL), run another query and return the link id. If that isn't found either, linkId will be NULL, returning NULL if pc1 isn't found at all is OK.
This works, but gives warnings if the first query doesn't return anything:
select find_linkid('12BD');
+------------------------------+
| find_linkid('12BD') |
+------------------------------+
| 667 |
+------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+-----------------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------------+
| Warning | 1329 | No data - zero rows fetched, selected, or processed |
+---------+------+-----------------------------------------------------+
1 row in set (0.00 sec)
What's the proper way of running one query, if that doesn't return anything, run another query ?
You can use a CONTINUE HANDLER to catch the warning, and then set a variable if you want, or just ignore it by giving the CONTINUE HANDLER an empty body.
Here's an example to suppress the warning (I also fixed a missing parenthesis and removed the extraneous ON from your code):
DROP FUNCTION IF EXISTS find_linkid;
DELIMITER //
CREATE FUNCTION `find_linkid`(pc1 VARCHAR(50))
RETURNS INT
BEGIN
DECLARE linkId int;
DECLARE CONTINUE HANDLER FOR NOT FOUND BEGIN END;
SELECT a.id INTO linkId FROM PC_A a WHERE a.pc=pc1;
IF linkId IS NULL THEN
SELECT b.id INTO linkId FROM PC_B b WHERE b.pc=pc1;
END IF;
RETURN linkId;
END
//
Here's another possibility with less boilerplate:
DECLARE _found, _id integer;
SELECT count(*), sum(a.id) INTO _found, _id FROM PC_A AS a WHERE a.pc = pc1;
IF _found THEN RETURN _id; END IF;
SELECT b.id INTO _id FROM PC_B AS b WHERE b.pc = pc1;
RETURN _id;
Try this handler:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET linkId = NULL;