Srtange result from mysql function - mysql

I create a function that returns a value, selected in a periods table like this:
CREATE TABLE `periods` (
`period` DATE NOT NULL,
`threshold` DOUBLE NOT NULL,
PRIMARY KEY (`period`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;
+------------------------+
| periods |
+------------+-----------+
| period | threshold |
+------------+-----------+
| 2013-11-01 | 5 |
+------------+-----------+
| 2013-12-01 | 1 |
+------------+-----------+
| 2014-01-01 | 5 |
+------------+-----------+
| 2014-02-01 | 5 |
+------------+-----------+
And function create:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `GET_THRESHOLD`(`PERIOD` VARCHAR(10))
RETURNS double
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
SQL SECURITY DEFINER
COMMENT 'RETURN THRESHOLD'
BEGIN
DECLARE RESULT DOUBLE;
SELECT threshold INTO RESULT FROM periods WHERE period = PERIOD LIMIT 1;
RETURN RESULT;
END
$$
DELIMITER ;
but the function returns a value the Wrong
mysql>SELECT GET_THRESHOLD('2013-12-01')
-> 5
someone can help me?

You parameter has the same name as a column. That's a no-no. Try this:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `GET_THRESHOLD`(`V_PERIOD` VARCHAR(10))
RETURNS double
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
SQL SECURITY DEFINER
COMMENT 'RETURN THRESHOLD'
BEGIN
DECLARE RESULT DOUBLE;
SELECT threshold INTO RESULT FROM periods WHERE period = V_PERIOD LIMIT 1;
RETURN RESULT;
END
$$
DELIMITER
The statement:
WHERE period = PERIOD
is comparing the column value to itself. So, it chooses all rows that have a non-NULL column value. Not very interesting.
It is good practice to always prefix variables and arguments with something to distinguish them from columns in tables.

Related

Tokenize a delimited string in MySQL

I wrote a function in MySQL to split a delimited string into tokens, but right now, it only returns the first token it encounters after the start position (pos). Is there a way to get it to return tokens as a result set with one column containing all of the parsed tokens?
Here is my current function code:
CREATE DEFINER=`root`#`localhost` FUNCTION `split_string_multi_byte`(
source_string VARCHAR(255),
delim VARCHAR(12),
pos INT) RETURNS varchar(255) CHARSET latin1
BEGIN
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(source_string, delim, pos),
CHAR_LENGTH(SUBSTRING_INDEX(source_string, delim, pos -1)) + 1),
delim, "");
END
Here are some parameters that I entered in my Navicat database development and admin client:
That returns the following results:
See how only "1" is returned. I would like to see all of the tokens if possible. However, I'm not sure how to do that.
Any help would be appreciated.
Thanks!
Rob
CREATE DEFINER=`root`#`%` FUNCTION `SPLIT`(s varchar(200), c char, i integer) RETURNS varchar(200) CHARSET utf8mb4
DETERMINISTIC
BEGIN
DECLARE retval varchar(200);
WITH RECURSIVE split as (
select 1 as x,substring_index(substring_index(s,c,1),c,-1) as y, s
union all
select x+1,substring_index(substring_index(s,c,x+1),c,-1),s from split where x<= (LENGTH(s) - LENGTH(REPLACE(s,c,'')))
)
SELECT y INTO retval FROM split WHERE x=i ;
return retval;
END
SELECT SPLIT('a,b,c,d,e,f',',',3); results in 'c'
Because you cannot return a table from a function (in MySQL), you could do something like this if you want results in a table:
SET #tekst = 'aap,noot,mies,wim,zus,jet';
WITH RECURSIVE abc as (
SELECT 1 as c
UNION ALL
SELECT c+1
FROM abc WHERE c<=15)
select c,split(#tekst,',',c) as t
from abc
where not split(#tekst,',',c) is null;
output:
+------+------+
| c | t |
+------+------+
| 1 | aap |
| 2 | noot |
| 3 | mies |
| 4 | wim |
| 5 | zus |
| 6 | jet |
+------+------+

Mysql, check if all rows of each column have the same value

A friend of mine wants to check if all the rows, of each of the columns of a table, have the same value.
If they do, then print the value.
Else just print an empty string or null or something.
Imagine this table for example:
+--------+----------+-----+
| Name | Lastname | Age |
+--------+----------+-----+
| Peter | White | 30 |
| Marry | Jane | 30 |
| John | Doe | 30 |
+--------+----------+-----+
The result of the wanted query would output the following:
+--------+----------+-----+
| Name | Lastname | Age |
+--------+----------+-----+
| NULL | NULL | 30 |
+--------+----------+-----+
I tried to create a function where I would get the columns of a given table, loop through each column name and execute a query. But since I am not familiar with Mysql I obviously miss something out and I can't figure out how to achieve what I'm trying to do here.
DROP PROCEDURE IF EXISTS test;
DELIMITER //
create procedure test()
begin
declare i int(11);
declare col_name varchar(50);
declare num_rows int(11);
DECLARE col_names CURSOR FOR
SELECT column_name
FROM information_schema.columns
WHERE table_name='name_of_my_table' and table_schema='name_of_db';
select FOUND_ROWS() as num_rows;
set i = 1;
open col_names;
the_loop: LOOP
IF i > num_rows THEN
CLOSE col_names;
LEAVE the_loop;
END IF;
FETCH col_names
INTO col_name;
-- Here I would like to perform a query for each column
select count(*), col_name from name_of_my_table group by col_name;
-- Then I was thinking of making an if/ else condition to check
-- if I get more than 1 result per column, implying that
-- not all rows have the same value for this column.
SET i = i + 1;
END LOOP the_loop;
CLOSE col_names;
END//
DELIMITER ;
call test;
What this outputs is the count and the column name of the last column found, which does make sense.
I am not sure if what I am trying to do is possible with Mysql only, I can easily do that in PHP but I am wondering if I can do that with a single query as well.
Try the below query.
select if(count(distinct(Name))=1,Name,null), if(count(distinct(Lastname))=1,Lastname,null), if(count(distinct(Age))=1,Age,null)
from your_table;

Debuggin mySQL syntax error in stored procedure

I am redirecting this file into mysql promt to add a stored procedure:
DROP PROCEDURE IF EXISTS make_transaction;
DELIMITER //
CREATE PROCEDURE make_transaction(IN v_quote_id INT, IN v_your_id INT)
BEGIN
DECLARE v_is_seller BOOLEAN;
DECLARE v_option_type BOOLEAN;
DECLARE v_trader_id INT;
DECLARE v_premium DOUBLE(18, 4);
DECLARE v_offer_expires DATETIME;
DECLARE v_instrument_id INT;
DECLARE v_pretend_now DATETIME;
DECLARE v_buyer_id INT;
DECLARE v_seller_id INT;
DECLARE v_buyer_total_balance DOUBLE(18, 4);
SELECT
instrument_id,
trader_type,
option_type,
trader_id,
premium,
offer_expires
INTO
v_instrument_id,
v_is_seller,
v_option_type,
v_trader_id,
v_premium,
v_offer_expires
FROM
option_quotes
WHERE
quote_id = v_quote_id;
IF v_is_seller THEN
SET v_seller_id = v_trader_id;
SET v_buyer_id = v_your_id;
ELSE
SET v_buyer_id = v_trader_id;
SET v_seller_id = v_your_id;
END IF;
-- Last STOCK_TRADE time is assumed to be the current time
SELECT DATE_TIME
INTO v_pretend_now
FROM STOCK_TRADE
WHERE INSTRUMENT_ID=v_instrument_id
ORDER BY DATE_TIME DESC
LIMIT 1;
SELECT total_balance
INTO v_buyer_total_balance
FROM traders
WHERE trader_id=v_buyer_id;
IF offer_expires <= v_pretend_now THEN
SELECT 'That offer has expired';
ELSE IF v_buyer_total_balance < v_premium THEN
SELECT 'You do not have enough money to transact on this offering';
ELSE
INSERT INTO option_transactions
(
transaction_time,
quote_id,
buyer_id,
seller_id,
buyer_gain,
seller_gain
)
VALUES
(
v_pretend_now,
v_quote_id,
v_buyer_id,
v_seller_id,
NULL, -- line 85
NULL
);
END IF;
END //
DELIMITER ;
The error I am receiving trying to enter the stored procedure into db:
ERROR 1064 (42000) at line 5: 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 '' at line 85
The option_transactions table looks like this:
+------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+-------+
| quote_id | int(11) | NO | MUL | NULL | |
| buyer_id | int(11) | NO | MUL | NULL | |
| seller_id | int(11) | NO | MUL | NULL | |
| transaction_time | datetime | NO | | NULL | |
| buyer_gain | double(18,4) | YES | | NULL | |
| seller_gain | double(18,4) | YES | | NULL | |
+------------------+--------------+------+-----+---------+-------+
I am new at mySQL, but the insert into command near line 85 appears correct in syntax to me, I am not sure where the problem is. How may I fix this?
(mysql server version 5.5.42)
Line 85 is not in the middle of your INSERT statement, it's at the end of the CREATE PROCEDURE statement. If I paste your code into vim and :se nu to show line numbers, and then I delete the initial lines before CREATE PROCEDURE, the last line is line 85:
84 END IF;
85 END //
86
87 DELIMITER ;
So the line numbers in the error start counting from the first line of the statement, not the first line of the SQL script file.
Then I went looking and found an imbalanced blocks:
IF offer_expires <= v_pretend_now THEN
ELSE IF v_buyer_total_balance < v_premium THEN
ELSE
END IF;
You used a nested IF/THEN/ELSE/END IF inside an ELSE. So you actually have two IF statements, but only one END IF.
To fix this, you have two options:
Make it one IF statement with an ELSIF:
IF offer_expires <= v_pretend_now THEN
ELSEIF v_buyer_total_balance < v_premium THEN
ELSE
END IF;
See https://dev.mysql.com/doc/refman/5.7/en/if.html for docs on the syntax of IF/THEN/ELSIF/ELSE/END IF.
Finish both IF statements:
IF offer_expires <= v_pretend_now THEN
ELSE
IF v_buyer_total_balance < v_premium THEN
ELSE
END IF;
END IF;

how to call a stored procedure using table data?

i want to create a stored procedure by using below requirement.
i tried and written a stored procedure it is working fine with the static values.
how a stored procedure will work with the dynamic values.
Please find my requirement here.
Create a stored proc “skillsparse” that accepts a string of text and and breaks it up into 1,2,3 word phrases.
a. For example: I love java because it’s fun should have these 15 phrases
i. I
ii. I love
iii. I love java
iv. Love
v. Love java
vi. Love java because
vii. Java
viii. Java because
ix. Java because it’s
x. Because
xi. Because it’s
xii. Because it’s fun
xiii. It’s
xiv. It’s fun
xv. fun
3. Store these phrases in a new table called: github_skills_phrases with fields: ID, userid, skills_id (from github_skills_source) and skills_phrase
4. Create a storedproc that compares the skills_phrases against the skills table (ref Table) and store the values into the github_skills table for each user. If possible, please maintain the source of where the skills came from (repodesc, repolang, starred, bio)
5. NOTE: Aside from the info in the new table Kishore is creating, you will also need to run the github_users.bio field against the Skillsparse procedure. You can start this first (for testing logic, etc) since the github_users.bio already exists and has data.
We don’t need to go this for users who have not yet been processed for skills
How i written is:
++++++++++++++++++++++++++++++++++++++++++++++++++++++
DELIMITER $$
CREATE procedure testing(IN id varchar(20),IN usr_id varchar(20),IN str varchar(200))
begin
DECLARE wordCnt varchar(20);
DECLARE wordCnt1 varchar(20);
DECLARE idx INT DEFAULT 1;
DECLARE splt varchar(200);
declare strng varchar(200);
create temporary table tmp.hello1(id varchar(200),usr_id varchar(200),st varchar(200));
set strng = str;
set wordCnt = LENGTH(trim(strng)) - LENGTH(REPLACE(trim(strng), ' ', ''))+1;
set wordCnt1 = LENGTH(trim(strng)) - LENGTH(REPLACE(trim(strng), ' ', ''))+1;
myloop: WHILE idx <= wordCnt DO
set splt = substring_index(trim(strng),' ',idx);
insert into tmp.hello1 values (id,usr_id,splt);
set idx=idx+1;
IF idx = 4 THEN
set strng = substring(trim(strng),length(substring_index(trim(strng),' ',1))+1);
set idx = 1;
set wordCnt = wordCnt -1;
END IF;
end while ;
insert into tmp.hello1 values (id,usr_id,trim(substring(trim(str),length(substring_index(trim(str),' ',wordCnt1-1))+1)));
end $$
Out put ::
mysql> call testing('10','200','I am the my fine the kks hhh nanj kell');
Query OK, 1 row affected (0.77 sec)
mysql> select * from hello1;
+------+--------+---------------+
| id | usr_id | st |
+------+--------+---------------+
| 10 | 200 | I |
| 10 | 200 | I am |
| 10 | 200 | I am the |
| 10 | 200 | am |
| 10 | 200 | am the |
| 10 | 200 | am the my |
| 10 | 200 | the |
| 10 | 200 | the my |
| 10 | 200 | the my fine |
........
..........
| 10 | 200 | kell |
+------+--------+---------------+
27 rows in set (0.00 sec)
my stored procedure is working fine with static values .how to call dynamically a stored procdure by using table data.
Please help me to write a stored procedure to calling with the table data.
If you means you need to call this stored procedure inside select statement on certain data table, this is not available.
You have two options:
1- transfer your procedure to function and then you can call it easily from inside the select statement.
2- write plsql code to call this procedure and you can check the below link about this point
oracle call stored procedure inside select

Mysql:Query for the table as below

I have the following table:
|-------------------|
| id | Homephone |
|-------------------|
| 1 | 454454125 |
| 2 | 47872154587 |
| 3 | 128795423 |
| 4 | 148784474 |
|-------------------|
I have around 40.000 rows in the table.
I want to format Homephone values as following:
454-454-125
478-721-545-87
128-795-423
148-784-474
i.e. after every 3 numbers I want - (hyphen).
How to achieve this using MySQL?
You need to wite a udf for this
Basically, you need to create your own function (so called UDF - User Defined Function) and run it on the table.
There is a nice function by Andrew Hanna posted in String Functions chapter of the MySQL Reference Manual. I fixed a small mistake there (replaced WHILE (i < str_len) DO by WHILE (i <= str_len) DO.
There are two steps (two SQL queries):
Create the function. It has three parameters: str - the string to be modified, pos - position of the character being inserted into the string, delimit - character(s) to be inserted:
DELIMITER //
CREATE FUNCTION insert_characters(str text, pos int, delimit varchar(124))
RETURNS text
DETERMINISTIC
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE str_len INT;
DECLARE out_str text default '';
SET str_len = length(str);
WHILE (i <= str_len) DO
SET out_str = CONCAT(out_str, SUBSTR(str, i, pos), delimit);
SET i = i + pos;
END WHILE;
-- trim delimiter from end of string
SET out_str = TRIM(trailing delimit from out_str);
RETURN(out_str);
END//
DELIMITER ;
Run the function...
...for testing purpose (select, no update):
SELECT insert_characters(Homephone, 3, "-") AS new_phone FROM my_table;
...to update the records:
UPDATE my_table SET Homephone = insert_characters(Homephone, 3, "-");
Please try to analyze the function line by line. This example may help you to understand the subject.