Selecting Into Lag (Window Function) in MySQL Stored Function - mysql

I am trying to automate mathematic formulas that I need to run many times over a dataset for a view page. I have used the SELECT INTO function to successfully create these values. Below is an example of code that has worked:
DELIMITER //
DROP FUNCTION IF EXISTS InvLevel;
CREATE FUNCTION InvLevel(
metric DECIMAL (65,4),
norm DECIMAL (65,10)
)
RETURNS DECIMAL(65,4)
BEGIN
SET #InvLevel = NULL;
SELECT
metric * norm
INTO #InvLevel;
RETURN #InvLevel;
END //
I then call this with:
CREATE VIEW Mainfile
SELECT
Clients, Users, Normalization, ID, Year
MNorm(Clients, Normalization) AS ClientsN,
MNorm(Users, Normalization) AS UsersN
FROM Dataset
Does everything I want! I'm happy.
However, one of the important functions I need to run is a lag function--i.e. I'm interested in how clients, users, etc. has changed over time. So I wrote the following stored function:
DELIMITER //
DROP FUNCTION IF EXISTS Pace;
CREATE FUNCTION Pace(
metric decimal(65,4),
id VARCHAR(20),
year INT
)
RETURNS DECIMAL(65,4)
BEGIN
SELECT
metric - (LAG(metric, 1) OVER (PARTITION BY id ORDER BY year))
INTO #paceco;
RETURN #paceco;
END //
That I then call as:
Pace(Clients,ID,Year) AS ClientsP
However, this operation only returns NULL values in ClientsP. I know it's not a question of the formula since if I directly write out the math in the create view function, I receive the correct values.
I know that I can just plug the original math into the view function but I have many metrics I will be repeating this formula on (for the next few years or so) so I would vastly prefer to automate it instead of have long, messy SQL files. Thanks in advance.

Related

How to create random numbers at set time interval in mysql?

I want to insert random numbers between 23 and 31 at every 5 seconds in a Mysql table.
I know that I have to use RAND() function. But i don't know how to use it for inserting random numbers at set time interval.
You can use the event scheduler for this:
create table foo (id int primary key auto_increment, value int);
create event insert_random_value_every_5_sec on schedule every 5 second do insert into foo (value) select floor(23+rand()*9) as value;
If the event scheduler is disabled, you will need to enable it:
set global event_scheduler=on;
You can specify start and or end times for the event in the create event statement or later in alter event.
This will give you random numbers FLOOR(RAND()*(31-23+1))+23 And this will give you data in every 5 second date MOD(SECOND(curdate()) ,5)=0. You can use this sql -
SELECT
FLOOR(RAND()*(31-23+1))+23
FROM table
WHERE MOD(SECOND(curdate()) ,5)=0
Alternatively, you can use PHP file and using script timeInterval with AJAX to insert the random value to the database. I will tell you step by step but without code.
Steps:
create PHP function to connect your database (you can Googling with keysearch mysqli_connect)
create PHP function to handle your AJAX request and save it in database (keysearch: mysqli_query)
create script function (ex: named ajax_query) to send AJAX request with RAND function to generate random number as you wish. (You can read this question)
create script interval function to call function "ajax_query"
PS: don't forget to include/use jQuery library in your file

Is there a way to change the default date input format

I have a source of data from where I extract some fields, among the fields there are some date fields and the source sends their values like this
#DD/MM/YYYY#
almost all the fields can be sent into the query with no modificaction, except this of course.
I have written a program the gets the data from an internet connection and sends it to the MySQL server and it's sending everything as it should, I am sure because I enabled general logging in the MySQL server and I can see all the queries are correct, except the ones with date fields.
I would like to avoid parsing the fields this way because it's a lot of work since it's all written in c, but if there is no way to do it, I understand and would accept that as an answer of course.
As an example suppose we had the following
INSERT INTO sometable VALUES ('#12/10/2015#', ... OTHER_VALUES ..., '#11/10/2015#');
in this case I send the whole thing as a query using mysql_query() from libmysqlclient.
In other cases I can split the parts of the message in something that is like an instruction and the parameters, something like this
iab A,B,C,#12/10/2015#,X,Y,#11/10/2015#
which could mean INSERT INTO table_a_something_b_whatever VALUES, and in this situation of course, I capture all the parameters and send a single query with a list of VALUES in it. Also in this situation, it's rather simple because I can handle the date like this
char date[] = "#11/10/2015#";
int day;
int month;
int year;
if (sscanf(date, "#%d/%d/%d#", &day, &month, &year) == 3)
{
/* it's fine, build a sane YYYY-MM-DD */
}
So the question is:
How can I tell the MySQL server in what format the date fields are?
Clarification to: Comment 1
Not necessarily INSERT, it's more complex than that. They are sometimes queries with all their parameters in it, sometimes they are just the parameters and I have to build the query. It's a huge mess but I can't do anything about it because it's a paid database and I must use it for the time being.
The real problem is when the query comes from the source and has to be sent as it is, because then there can be many occurrences. When I split the parameters one by one there is no real problem because parsing the above date format and generating the appropriate value of MySQL is quite simple.
You can use STR_TO_DATE() in MySQL:
SELECT STR_TO_DATE('#08/10/2015#','#%d/%m%Y#');
Use this as part of your INSERT process:
INSERT INTO yourtable (yourdatecolumn) VALUES (STR_TO_DATE('#08/10/2015#','#%d/%m%Y#'));
The only Thing I could imagine at the Moment would be to Change your Column-Type from DateTime to varchar and use a BEFORE INSERT Trigger to fix "wrong" Dates.
Something like this:
DELIMITER //
CREATE TRIGGER t1 BEFORE INSERT on myTable FOR EACH ROW
BEGIN
IF (NEW.myDate regexp '#[[:digit:]]+\/[[:digit:]]+\/[[:digit:]]+#') THEN
SET NEW.myDate = STR_TO_DATE(NEW.myDate,'#%d/%m/%Y#');
END IF;
END; //
DELIMITER ;
If you are just Need to run the Import in question once, use the Trigger to generate a "proper" dateTimeColumn out of the inserts - and drop the varchar-column afterwards:
('myDate' := varchar column to be dropped afterwards;`'myRealDate' := DateTime Column to Keep afterwards)
DELIMITER //
CREATE TRIGGER t1 BEFORE INSERT on myTable FOR EACH ROW
BEGIN
IF (NEW.myDate regexp '#[[:digit:]]+\/[[:digit:]]+\/[[:digit:]]+#') THEN
SET NEW.myRealDate = STR_TO_DATE(NEW.myDate,'#%d/%m/%Y#');
else
#assume a valid date representation
SET NEW.myRealDate = NEW.myDate;
END IF;
END; //
DELIMITER ;
Unfortunately you cannot use a Trigger to work on the datetime-column itself, because mysql will already mess up the NEW.myDate-Column.

How does UDF in MySQL work internally and the reason behind the time difference between the two methods available

There are two ways in creating an UDF
a) By using a CREATE FUNCTION syntax which directly creates a function in that particular database.
Eg:
http://www.sqlexamples.info/PHP/mysql_udf1.htm
b) By writing a C code, compiling it and using its .so library file and linking it to the mysql server and then creating a function in mysql
Eg:
http://blog.loftdigital.com/blog/how-to-write-mysql-functions-in-c
In the first method (a),
CREATE FUNCTION `func`(variable INT) RETURNS int(11)
DETERMINISTIC
BEGIN
RETURN variable
END
it takes about 12 seconds to return the data for a select query like
select fiscal(col1) from table;
where
select col1 from table;
takes only about 0.42 seconds!!
where as the same written in C code takes only around 0.64 seconds!
I wanted to know what is that that is causing this time difference for a simple return function with no processing done in it. Also wanted to know how mySql allocates memory to these two different methods.

Using a scalar valued find string function when searching multiple rows returned?

Given SQL Server 2008, I have written a simple find in string function as follows:
ALTER FUNCTION [dbo].[FindInString]
(
#FindText VARCHAR(255),
#TextSource VARCHAR(512)
)
RETURNS INT
AS
BEGIN
DECLARE #Result INT
SET #Result = 0
SELECT #Result = CHARINDEX(#FindText, #TextSource)
RETURN #Result
END
The complexity of the find function may change in the future, which is why I wanted to encapsulate it in a function.
Now, when I only have one matching record in a table, this works:
SELECT #FindCount = dbo.FindInString('somestring', (SELECT TableSearch FROM Segments WHERE CID=22793))
However, when the select statement returns more than one, it makes sense as to why an error is thrown.
like to know is what I need to do to still have this work as a simple call, as above?
I only need to know if there is one match (I just need to know if #FindCount > 0), and I'm guessing some sort of a loop may be required, but would like to keep this as simple as possible.
Thanks.
You can use aggregate functions and one select:
select
#FindCount = sum(dbo.FindInString('somestring', TableSearch))
from
Segment
where
CID = 22793
Just take care with this, as FindInString will fire for each row, which can significantly reduce query performance. In this case, it's the only way to solve your problem, but just beware of the troubles that could arise.

Stored Procedures with parameters

My question is : A Stored Procedure that receives a given flight and a given date as input, and displays a customer call list, which includes name, address and phone number as output.
The query is simple, I can get all the data from a single table but, I don’t know how to take an input while running the procedure and then comparing it with the values inside.
The query is:
select NAME, ADDRESS, PHONE
FROM SCH_FLIGHTS SF, PASSENGERS P
WHERE SF.DATE(input) = P.DATE
Would highly appreciate you helping me on the same....just need to convert that query into a stored procedure which takes 2 inputs, a date and a flight_no as mentioned in the question above.
Thanks.
To create the SP (don't know the exact datatypes so i am just guessing) :
delimiter //
CREATE PROCEDURE NameOfProcedure(input VARCHAR(32))
BEGIN
select NAME, ADDRESS, PHONE
FROM SCH_FLIGHTS SF, PASSENGERS P
WHERE SF.DATE(input) = P.DATE
END
//
your PHP code would look somthing like this (TODO replace $input by query parameter for security reasons):
$result = $db->query("call NameOfProcedure($input)");