I have a problem with setting the #temp variable.
The if statement below fails. I have tried various combinations with quotes, using the SELECT command, but I can't get it to work.
Thanks!
Mike
SET #Stime := '6:30PM';
IF ( CHAR_LENGTH(#Stime) = 6, SET #temp := 'one', SET #temp := 'two');
Assuming it's mySQL
The IF() function returns a value if a condition is TRUE, or another value if a condition is FALSE.
In your case this code will update temp with one or two depends on the length.
SET #Stime := '6:30PM';
SET #temp = IF(CHAR_LENGTH(#Stime) = 6,'one','two');
Related
How to declare a variable in mysql, so that my second query can use it?
I would like to write something like:
SET start = 1;
SET finish = 10;
SELECT * FROM places WHERE place BETWEEN start AND finish;
There are mainly three types of variables in MySQL:
User-defined variables (prefixed with #):
You can access any user-defined variable without declaring it or
initializing it. If you refer to a variable that has not been
initialized, it has a value of NULL and a type of string.
SELECT #var_any_var_name
You can initialize a variable using SET or SELECT statement:
SET #start = 1, #finish = 10;
or
SELECT #start := 1, #finish := 10;
SELECT * FROM places WHERE place BETWEEN #start AND #finish;
User variables can be assigned a value from a limited set of data
types: integer, decimal, floating-point, binary or nonbinary string,
or NULL value.
User-defined variables are session-specific. That is, a user
variable defined by one client cannot be seen or used by other
clients.
They can be used in SELECT queries using Advanced MySQL user variable techniques.
Local Variables (no prefix) :
Local variables needs to be declared using DECLARE before
accessing it.
They can be used as local variables and the input parameters
inside a stored procedure:
DELIMITER //
CREATE PROCEDURE sp_test(var1 INT)
BEGIN
DECLARE start INT unsigned DEFAULT 1;
DECLARE finish INT unsigned DEFAULT 10;
SELECT var1, start, finish;
SELECT * FROM places WHERE place BETWEEN start AND finish;
END; //
DELIMITER ;
CALL sp_test(5);
If the DEFAULT clause is missing, the initial value is NULL.
The scope of a local variable is the BEGIN ... END block within
which it is declared.
Server System Variables (prefixed with ##):
The MySQL server maintains many system variables configured to a default value.
They can be of type GLOBAL, SESSION or BOTH.
Global variables affect the overall operation of the server whereas session variables affect its operation for individual client connections.
To see the current values used by a running server, use the SHOW VARIABLES statement or SELECT ##var_name.
SHOW VARIABLES LIKE '%wait_timeout%';
SELECT ##sort_buffer_size;
They can be set at server startup using options on the command line or in an option file.
Most of them can be changed dynamically while the server is running using SET GLOBAL or SET SESSION:
-- Syntax to Set value to a Global variable:
SET GLOBAL sort_buffer_size=1000000;
SET ##global.sort_buffer_size=1000000;
-- Syntax to Set value to a Session variable:
SET sort_buffer_size=1000000;
SET SESSION sort_buffer_size=1000000;
SET ##sort_buffer_size=1000000;
SET ##local.sort_buffer_size=10000;
SET
SET #var_name = value; /* or */ SET #var_name := value;
both operators = and := are accepted
SELECT
SELECT col1, #var_name := col2 from tb_name WHERE "condition";
if multiple record sets found only the last value in col2 is kept (override);
SELECT col1, col2 INTO #var_name, col3 FROM ...
in this case the result of Select is not containing col2 values
Ex both methods used
-- TRIGGER_BEFORE_INSERT --- setting a column value from calculations
...
SELECT count(*) INTO #NR FROM a_table WHERE a_condition;
SET NEW.ord_col = IFNULL( #NR, 0 ) + 1;
...
Use set or select
SET #counter := 100;
SELECT #variable_name := value;
example :
SELECT #price := MAX(product.price)
FROM product
Different types of variable:
local variables (which are not prefixed by #) are strongly typed and scoped to the stored program block in which they are declared. Note that, as documented under DECLARE Syntax:
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other statements.
User variables (which are prefixed by #) are loosely typed and scoped to the session. Note that they neither need nor can be declared—just use them directly.
Therefore, if you are defining a stored program and actually do want a "local variable", you will need to drop the # character and ensure that your DECLARE statement is at the start of your program block. Otherwise, to use a "user variable", drop the DECLARE statement.
Furthermore, you will either need to surround your query in parentheses in order to execute it as a subquery:
SET #countTotal = (SELECT COUNT(*) FROM nGrams);
Or else, you could use SELECT ... INTO:
SELECT COUNT(*) INTO #countTotal FROM nGrams;
Declare:
SET #a = 1;
Usage:
INSERT INTO `t` (`c`) VALUES (#a);
For any person using #variable in concat_ws function to get concatenated values, don't forget to reinitialize it with empty value. Otherwise it can use old value for same session.
Set #Ids = '';
select
#Ids := concat_ws(',',#Ids,tbl.Id),
tbl.Col1,
...
from mytable tbl;
I would like to give my awnswer here so people can try, solution for MySql that i think is easyer to understand:
set #countVal = (select count(*) from STATION);
/**
499/2 = 249,5 -> 250 -- ceil
499/2 = 249,5 + 1 = 250,5 -- floor 250
500/2 = 250 -- ceil 250
= 250 + 1 = 251 -- flor 251
**/
set #ceilVal = ceil(#countVal/2);
set #floorVal = floor( (#countVal/2) + 1);
SELECT ROUND(AVG( latitude ),4) FROM
(SELECT #lineNum:= #lineNum + 1 as id,
lat_n as latitude
FROM STATION s, ( SELECT #lineNum :=0 ) pivot
ORDER BY lat_n) as a
WHERE id IN ( #ceilVal, #floorVal );
SET Value
declare #Regione int;
set #Regione=(select id from users
where id=1) ;
select #Regione ;
In the code below, I'm trying go through the results of endDateTable row by row, comparing the current row's endDate to the previous row's endDate. If there has been any change since the previous, we increment #revisionNum. However, upon populating the new table, all of the #revisionNum entries are 0. What am I doing wrong?
NOTE: I'm using prepared statements in this manner since doing a straightforward SELECT into a variable gives a syntax error due to the LIMIT clause not allowing a variable in our version of MySQL.
BEGIN
DECLARE _currentEndDate DATETIME DEFAULT now();
DECLARE _priorEndDate DATETIME DEFAULT now();
SET #ResultsCount = (SELECT COUNT(*) FROM mainTable);
SET #j = 0;
WHILE #j < #ResultsCount DO
SET #revisionNum = 0;
/*CURRENT END DATE*/
SET #appResultQueryCurrent = CONCAT('
SELECT
end_date
INTO _currentEndDate
FROM endDateTable
LIMIT ', #j, ', 1'
);
PREPARE currentQueryStmt FROM #appResultQueryCurrent;
EXECUTE currentQueryStmt;
/*PREVIOUS END DATE*/
SET #appResultQueryPrior = CONCAT('
SELECT
end_date
INTO _priorAppEndDate
FROM endDateTable
LIMIT ', IF(#j = 0, 0, #j - 1), ', 1'
);
PREPARE priorQueryStmt FROM #appResultQueryPrior;
EXECUTE priorQueryStmt;
SET #revisionNum = IF(
#j = 0 OR (_currentEndDate = _priorEndDate),
#revisionNum,
IF(
_currentEndDate != _priorEndDate,
#revisionNum + 1,
#revisionNum
)
);
INSERT INTO finalTable (RevisionNum)
SELECT
#revisionNum AS RevisionNum
FROM endDateTable;
SET #j = #j +1;
END WHILE;
END $$
You don't need a loop, you can use INSERT INTO ... SELECT ..., incrementing the variable in the select query.
You also need an ORDER BY criteria to specify how to order the rows when comparing one row to the previous row.
INSERT INTO finalTable (RevisionNum, otherColumn)
SELECT revision, otherColumn
FROM (
SELECT IF(end_date = #prev_end_date, #revision, #revision := #revision + 1) AS revision,
#prev_end_date := end_date,
otherColumn
FROM endDateTable
CROSS JOIN (SELECT #prev_end_date := NULL, #revision := -1) AS vars
ORDER BY id) AS x
DEMO
The offset value in the LIMIT clause is tenuous without an ORDER BY.
Without an ORDER BY clause, MySQL is free to return results in any sequence.
There is no guarantee that LIMIT 41,1 will return the row before LIMIT 42,1, or that it won't return the exact same row as LIMIT 13,1 did.
(A table in a relational database represents an unordered set of tuples, there is no guaranteed "order" or rows in a table.)
But just adding ORDER BY to the queries isn't enough to fix the Rube-Goldberg-esque rigmarole.
In the code shown, it looks like each time through the loop, we're inserting a copy of endDateTable into finalTable. If that's 1,000 rows in endDateTable, we're going to get 1,000,000 rows (1,000 x 1,000) inserted into finalTable. Not at all clear why we need so many copies.
Given the code shown, it's not clear what the objective is. Looks like we are conditionally incrementing revisionNum, the end result of which is the highest revision num. Just guessing here.
If there is some kind of requirement to do this in a LOOP construct, within a procedure, I'd think we'd do a cursor loop. And we can use procedure variables vs user-defined variables.
Something along these lines:
BEGIN
DECLARE ld_current_end_date DATETIME;
DECLARE ld_prior_end_date DATETIME;
DECLARE li_done INT;
DECLARE li_revision_num INT;
DECLARE lcsr_end_date CURSOR FOR SELECT t.end_date FROM `endDateTable` t ORDER BY NULL;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET li_done = TRUE;
SET li_done = FALSE;
SET li_revision_num = 0;
OPEN lcsr_end_date;
FETCH lcsr_end_date INTO ld_current_end_date;
SET ld_prior_end_date = ld_current_end_date;
WHILE NOT li_done DO
SET li_revision_num = li_revision_num + IF( ld_current_end_date <=> ld_prior_end_date ,0,1);
SET ld_prior_end_date := ld_current_end_date;
FETCH lcsr_end_date INTO ld_current_end_date;
END WHILE;
CLOSE lcsr_end_date;
INSERT INTO `finalTable` (revisionnum) VALUES (li_revision_num);
END $$
Note the "order by" clause on the SELECT, its not clear what the rows should be ordered on, so we're using a literal as a placeholder.
As the end result, we insert a single row into finalTable.
Again, it's not clear what the code in the question is supposed to achieve, but doing a cursor loop across ordered rows would be much more efficient than a bazillion dynamic SQL executions fetching individual rows.
How to declare a variable in mysql, so that my second query can use it?
I would like to write something like:
SET start = 1;
SET finish = 10;
SELECT * FROM places WHERE place BETWEEN start AND finish;
There are mainly three types of variables in MySQL:
User-defined variables (prefixed with #):
You can access any user-defined variable without declaring it or
initializing it. If you refer to a variable that has not been
initialized, it has a value of NULL and a type of string.
SELECT #var_any_var_name
You can initialize a variable using SET or SELECT statement:
SET #start = 1, #finish = 10;
or
SELECT #start := 1, #finish := 10;
SELECT * FROM places WHERE place BETWEEN #start AND #finish;
User variables can be assigned a value from a limited set of data
types: integer, decimal, floating-point, binary or nonbinary string,
or NULL value.
User-defined variables are session-specific. That is, a user
variable defined by one client cannot be seen or used by other
clients.
They can be used in SELECT queries using Advanced MySQL user variable techniques.
Local Variables (no prefix) :
Local variables needs to be declared using DECLARE before
accessing it.
They can be used as local variables and the input parameters
inside a stored procedure:
DELIMITER //
CREATE PROCEDURE sp_test(var1 INT)
BEGIN
DECLARE start INT unsigned DEFAULT 1;
DECLARE finish INT unsigned DEFAULT 10;
SELECT var1, start, finish;
SELECT * FROM places WHERE place BETWEEN start AND finish;
END; //
DELIMITER ;
CALL sp_test(5);
If the DEFAULT clause is missing, the initial value is NULL.
The scope of a local variable is the BEGIN ... END block within
which it is declared.
Server System Variables (prefixed with ##):
The MySQL server maintains many system variables configured to a default value.
They can be of type GLOBAL, SESSION or BOTH.
Global variables affect the overall operation of the server whereas session variables affect its operation for individual client connections.
To see the current values used by a running server, use the SHOW VARIABLES statement or SELECT ##var_name.
SHOW VARIABLES LIKE '%wait_timeout%';
SELECT ##sort_buffer_size;
They can be set at server startup using options on the command line or in an option file.
Most of them can be changed dynamically while the server is running using SET GLOBAL or SET SESSION:
-- Syntax to Set value to a Global variable:
SET GLOBAL sort_buffer_size=1000000;
SET ##global.sort_buffer_size=1000000;
-- Syntax to Set value to a Session variable:
SET sort_buffer_size=1000000;
SET SESSION sort_buffer_size=1000000;
SET ##sort_buffer_size=1000000;
SET ##local.sort_buffer_size=10000;
SET
SET #var_name = value; /* or */ SET #var_name := value;
both operators = and := are accepted
SELECT
SELECT col1, #var_name := col2 from tb_name WHERE "condition";
if multiple record sets found only the last value in col2 is kept (override);
SELECT col1, col2 INTO #var_name, col3 FROM ...
in this case the result of Select is not containing col2 values
Ex both methods used
-- TRIGGER_BEFORE_INSERT --- setting a column value from calculations
...
SELECT count(*) INTO #NR FROM a_table WHERE a_condition;
SET NEW.ord_col = IFNULL( #NR, 0 ) + 1;
...
Use set or select
SET #counter := 100;
SELECT #variable_name := value;
example :
SELECT #price := MAX(product.price)
FROM product
Different types of variable:
local variables (which are not prefixed by #) are strongly typed and scoped to the stored program block in which they are declared. Note that, as documented under DECLARE Syntax:
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other statements.
User variables (which are prefixed by #) are loosely typed and scoped to the session. Note that they neither need nor can be declared—just use them directly.
Therefore, if you are defining a stored program and actually do want a "local variable", you will need to drop the # character and ensure that your DECLARE statement is at the start of your program block. Otherwise, to use a "user variable", drop the DECLARE statement.
Furthermore, you will either need to surround your query in parentheses in order to execute it as a subquery:
SET #countTotal = (SELECT COUNT(*) FROM nGrams);
Or else, you could use SELECT ... INTO:
SELECT COUNT(*) INTO #countTotal FROM nGrams;
Declare:
SET #a = 1;
Usage:
INSERT INTO `t` (`c`) VALUES (#a);
For any person using #variable in concat_ws function to get concatenated values, don't forget to reinitialize it with empty value. Otherwise it can use old value for same session.
Set #Ids = '';
select
#Ids := concat_ws(',',#Ids,tbl.Id),
tbl.Col1,
...
from mytable tbl;
I would like to give my awnswer here so people can try, solution for MySql that i think is easyer to understand:
set #countVal = (select count(*) from STATION);
/**
499/2 = 249,5 -> 250 -- ceil
499/2 = 249,5 + 1 = 250,5 -- floor 250
500/2 = 250 -- ceil 250
= 250 + 1 = 251 -- flor 251
**/
set #ceilVal = ceil(#countVal/2);
set #floorVal = floor( (#countVal/2) + 1);
SELECT ROUND(AVG( latitude ),4) FROM
(SELECT #lineNum:= #lineNum + 1 as id,
lat_n as latitude
FROM STATION s, ( SELECT #lineNum :=0 ) pivot
ORDER BY lat_n) as a
WHERE id IN ( #ceilVal, #floorVal );
SET Value
declare #Regione int;
set #Regione=(select id from users
where id=1) ;
select #Regione ;
There is a similar question
Insert sequential number in MySQL
I want to insert sequential numbers to the table, but based on another field. I have two columns page_numner and parent, so the rows with same parent should have page_number as consequtive numbers. If parent changes, the page should start from 1 again and increase by one.
I was thinking to use smth like this
SELECT #i:=0;
SELECT #p:=0;
UPDATE my_table AS t SET page_number = CASE
WHEN #p = t.`parent` THEN #i:=#i+1
ELSE 1 -- assign current parent to #p ??
END
but, it cant figure out how to assign the new parent into #p for the else case.
Please note, that I am trying to achieve this with pure mysql (if possible of course)
Thanks
You can do what you want with this code:
set #p := -1;
set #i := 0;
UPDATE my_table t
SET page_number = (CASE WHEN #p = t.`parent` THEN #i := #i+ 1
WHEN (#p := t.parent) = NULL THEN NULL -- never happens
ELSE #i := 1
END)
ORDER BY t.parent;
Unfortunately, MySQL doesn't allow both ORDER BY and JOIN in the same UPDATE query. If it did, you could initialize the variables in the query.
Note the second condition just does the assignment. = NULL never returns TRUE.
I'm looking for a way to extract the value from a SQL variable and save this value in a new variable. For example, if I have the variable #myVar, which is storing the value 25, and I want to save this value to a new variable #myVar1 before updating the value stored in #myVarto 30. I've found that simply setting #myVar1:= #myVar does not work as once I change the value stored in #myVarto 30 the #myVar1 variable will automatically update itself to 30 as well.
I am using these variables in a SELECT statement in order to keep track of and compare values in a previous row to values in the current row.
The relevant code snippet is:
SELECT
CASE
When (#r is not null) then #myVar1:= #myVar
END,
#myVar:= #myVar + 1
As you can see, #myVar is set to a new value every row, while #myVar1 should only be set to the current value of #myVar if the condition is met, and remain storing that value until the condition is met again, regardless of any changes to the value #myVar is storing. So if #myVar = 7 and #r is not null then #myVar1 = 7, but when #myVar will then be set to 8, #myVar1 will also be set to 8 instead of remaining at 7 until the condition is met again.
Maybe you should do something like this:
#x_old := x;
#x := case when #r is not null then #y else #x end;
(If this is in a procedure, you can leave the ; right where they are; if this is inside a query, replace them with ,)
This way you will preserve the value of #x if the condition is not fulfilled