select * from t limit #var - mysql

I am using multi-value option on grafana to select metrics and display them dynamically, this method works on graphs fine because I am not putting any limiter but I want to use Gauge to display the last entered data and the selected options to show the desired metric like this
.
And here i am stuck.
here is things i tried but naah didn't work,;
I tried to create a procedure for test;
CREATE PROCEDURE getData()
BEGIN
SET #itemlimit := JSON_LENGTH(JSON_ARRAY('conductivite0','conductivite1'));
SELECT UNIX_TIMESTAMP(datetime) as time_sec,
value as value,
label as metric
FROM valeur_capteur_SD
WHERE label in ('conductivite0','conductivite1')
ORDER BY id DESC LIMIT 0, #itemlimit;
END //
DELIMITER ;
and using a variable,
SET #var =
(
SELECT vars
FROM (
SELECT
JSON_LENGTH(
REPLACE(
CONCAT("[", "'conductivite0','conductivite1'", "]"),"'",'"'
)
) 'vars') as vars
);
SELECT
UNIX_TIMESTAMP(datetime) as time_sec,
value as value,
label as metric
FROM valeur_capteur_SD
WHERE label in ('conductivite0','conductivite1','debit0')
ORDER BY id DESC
LIMIT #var;

Well, after struggling for hours i found out a way to deal with it
DELIMITER //
CREATE PROCEDURE `getSelectedSensors`(IN param TEXT)
BEGIN
SET #query1 := CONCAT("
SELECT UNIX_TIMESTAMP(datetime) as time_sec,value as value, label as metric
FROM valeur_capteur_SD WHERE label in (",param,")
ORDER BY id DESC
LIMIT 0, ?");
PREPARE stmt1 FROM #query1;
SET #itemlimit = (LENGTH(param) - LENGTH(REPLACE(param, ',', ''))) +1;
EXECUTE stmt1 USING #itemlimit;
DEALLOCATE PREPARE stmt1;
END;

Related

Cannot use prepare statement on locally declared variable

In a procedure I want to select a value from a specific table in all databases. I developed a code and reached to this point:
BEGIN
DECLARE dynamic_query LONGTEXT;
SET SESSION group_concat_max_len = 100000000;
SET dynamic_query = (
SELECT
GROUP_CONCAT(
"SELECT option_name AS _key, option_value as _value from ",
TABLE_NAME,
" where option_name like '",
"something%'" SEPARATOR ' union ')
FROM
(
SELECT
CONCAT(`database_name`,'.',`table_prefix`,'options') as TABLE_NAME
FROM `tablename`
WHERE `database_name` <> '' AND `table_prefix` <> ''
) AS tmp
);
SELECT dynamic_query;
END
And I copy the output and execute it and it works fine. But when I add a prepare statement like below I get an error which is mentioned in this bug.
PREPARE result_query FROM dynamic_query;
EXECUTE result_query;
DEALLOCATE PREPARE result_query;
Is there any other way so I can get my desired output?
P.S.: I'm using SET SESSION group_concat_max_len = 100000000; to expand group_concat's limit but I prefer another way because the number of databases are growing.

Can't execute a MySQL SELECT statement when inside CONCAT

I have been trying to create a simple loop of SELECT statements in MySQL to reduce code. I have started this using CONCAT() however this causes the procedure to stop/fail. For example (where k is a loop counter):
CONCAT('SELECT (Child_', k, ' INTO #Age_Child_', k, ' FROM lookup_childage WHERE ModYear = ModYear_var LIMIT 1)');
To diagnose the issue, I simply tried to place the SELECT statement (without concatenated loop variables) inside a string to then be executed. While I could get this to work for simple statements it would not work for the following:
SET #queryString = CONCAT('SELECT Child_1 INTO #Age_Child_1 FROM lookup_childage WHERE ModYear = ModYear_var LIMIT 1');
PREPARE stmt FROM #queryString;
EXECUTE stmt;
Does anyone know why the #queryString containing the CONCAT() statement will not be executed/cause the procedure to fail?
tl;dr The statement you're trying to write has the form SELECT(rest of statement) LIMIT 1. It should have the form SELECT rest of statement LIMIT 1.
It looks like you want to create variable column names, ummm, because your lookup_childage table is denormalized. I guess that table has these columns.
Child_1 INT
Child_2 INT
Child_3 INT
Child_4 INT
It looks like you hope to get a #queryString value containing this sort of thing:
SELECT Child_4 INTO #Age_Child_4 FROM lookup_childage WHERE ModYear = ModYear_var LIMIT 1
Only the 4s are variable.
So to get that string you want
SELECT CONCAT('SELECT Child_', k,
' INTO #Age_Child_', k,
' FROM lookup_childage WHERE ModYear = ModYear_var LIMIT 1'
)
INTO #queryString;

using a variable mysql not working as expected?

It doesn't like the limit line below. How would I use the variable #row in this case to limit the result set?
SELECT #row := 5;
SELECT * FROM MyTable
limit #row
Error:
Unexpected '#row'
The LIMIT clause can be used to constrain the number of rows returned
by the SELECT statement. LIMIT takes one or two numeric arguments,
which must both be nonnegative integer constants https://dev.mysql.com/doc/refman/8.0/en/select.html
So,
SELECT * FROM MyTable
limit 5
You could use a prepared statement...
SET #row = 5;
SET #s = CONCAT('SELECT * FROM MyTable LIMIT ', #row);
PREPARE stmt FROM #s;
EXECUTE stmt;

MySQL OutFile to use data from table

I'm trying to generate an export that runs monthly which appends a value from one of the columns within a table to the OutFile name, is this even possible?
The table is mytable and the column is col1 which contains "201601" at the minute
I would like my OutFile to show "/tmp/Output_201601" where the 201601 on next run will have automatically changed to 201602 etc
You can try to do this with stored procedure.
Eg. when you call this procedure - it export data from table mytable to file with name D:/tmp/Output_ + top value from field Col1.
CREATE PROCEDURE `PrepareReport`()
BEGIN
SET #OutputFileName := 'D://tmp//Output_';
SELECT Col1 INTO #ReportNr FROM mytable ORDER BY Col1 DESC LIMIT 1;
SET #q1 := concat("SELECT * FROM mytable INTO OUTFILE '", #OutputFileName, #ReportNr, ".csv'");
PREPARE s1 FROM #q1;
EXECUTE s1;
DEALLOCATE PREPARE s1;
END

How can I assign a variable with a prepared statement in a stored procedure?

I've put together a simple stored procedure in which two parameters are passed through to make it more dynamic. I've done this with a prepared statement in the "First Two Digits and Count of Records" section.
What I'm not sure of is if I can make the SET vTotalFT section dynamic with a prepared statement as well.
At the moment I have to hard-code the table names and fields. I want my vTotalFT variable to be assigned based on a prepared dynamic SQL statement, but I'm not sure of the syntax. The idea is that when I call my procedure, I could tell it which table and which field to use for the analysis.
CREATE PROCEDURE `sp_benfords_ft_digits_analysis`(vTable varchar(255), vField varchar(255))
SQL SECURITY INVOKER
BEGIN
-- Variables
DECLARE vTotalFT int(11);
-- Removes existing table
DROP TABLE IF EXISTS analysis_benfords_ft_digits;
-- Builds base analysis table
CREATE TABLE analysis_benfords_ft_digits
(
ID int(11) NOT NULL AUTO_INCREMENT,
FT_Digits int(11),
Count_of_Records int(11),
Actual decimal(18,3),
Benfords decimal(18,3),
Difference Decimal(18,3),
AbsDiff decimal(18,3),
Zstat decimal(18,3),
PRIMARY KEY (ID),
KEY id_id (ID)
);
-- First Two Digits and Count of Records
SET #s = concat('INSERT INTO analysis_benfords_ft_digits
(FT_Digits,Count_of_Records)
select substring(cast(',vField,' as char(50)),1,2) as FT_Digits, count(*) as Count_of_Records
from ',vTable,'
where ',vField,' >= 10
group by 1');
prepare stmt from #s;
execute stmt;
deallocate prepare stmt;
SET vTotalFT = (select sum(Count_of_Records) from
(select substring(cast(Gross_Amount as char(50)),1,2) as FT_Digits, count(*) as Count_of_Records
from supplier_invoice_headers
where Gross_Amount >= 10
group by 1) a);
-- Actual
UPDATE analysis_benfords_ft_digits
SET Actual = Count_of_Records / vTotalFT;
-- Benfords
UPDATE analysis_benfords_ft_digits
SET Benfords = Log(1 + (1 / FT_Digits)) / Log(10);
-- Difference
UPDATE analysis_benfords_ft_digits
SET Difference = Actual - Benfords;
-- AbsDiff
UPDATE analysis_benfords_ft_digits
SET AbsDiff = abs(Difference);
-- ZStat
UPDATE analysis_benfords_ft_digits
SET ZStat = cast((ABS(Actual-Benfords)-IF((1/(2*vTotalFT))<ABS(Actual-Benfords),(1/(2*vTotalFT)),0))/(SQRT(Benfords*(1-Benfords)/vTotalFT)) as decimal(18,3));
First, to use dynamic table/column names, you'll need to use a string/Prepared Statement like your first query for #s. Next, to get the return-value from COUNT() inside of the query you'll need to use SELECT .. INTO #vTotalFT.
The following should be all you need:
SET #vTotalFTquery = CONCAT('(select sum(Count_of_Records) INTO #vTotalFT from
(select substring(cast(', vField, ' as char(50)),1,2) as FT_Digits, count(*) as Count_of_Records
from ', vTable, '
where ', vField, ' >= 10
group by 1) a);');
PREPARE stmt FROM #vTotalFTquery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Please note: the variable name has changed from vTotalFT to #vTotalFT. It doesn't seem to work without the #. And also, the variable #vTotalFT won't work when declared outside of/before the query, so if you encounter an error or empty results that could be a cause.
SELECT CONCAT (
'SELECT DATE(PunchDateTime) as day , '
,GROUP_CONCAT('GROUP_CONCAT(IF(PunchEvent=', QUOTE(PunchEvent), ',PunchDateTime,NULL))
AS `', REPLACE(PunchEvent, '`', '``'), '`')
,'
FROM tbl_punch
GROUP BY DATE(PunchDateTime)
ORDER BY PunchDateTime ASC
'
)
INTO #sql
FROM (
SELECT DISTINCT PunchEvent
FROM tbl_punch
) t;
PREPARE stmt
FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;