I just cant get this to work within a procedure (as a simple query this works fine):
SET #c:=0;
SELECT
(#c := #c + 1) AS Cumulative,
FROM
NumberTable,
Table
...
I think it hast something to to with the "counter"-variable. For the procedure I tried:
DECLARE c int(4) DEFAULT 0;
BEGIN
SELECT
(c = c + 1) AS Cumulative,
FROM
NumberTable,
Table
...
END
But that doesn't work (gives NULL). Any suggestions?
PS: I think the question breaks down to this: How to SET a variable within SELECT while using a PROCEDURE (since := does not work there)
Related
Thanks to this answer https://stackoverflow.com/a/8180159/16349298 , i'm able to translate
a string into a temporary table (usable for WHERE <id> IN <tmpTable>.<colomn>)
The only modification i made is at the end (The select) :
CREATE PROCEDURE stringToTmpTable(IN inputString VARCHAR(255), IN sep VARCHAR(255))
BEGIN
declare pos int; -- Keeping track of the next item's position
declare item varchar(100); -- A single item of the input
declare breaker int; -- Safeguard for while loop
-- The string must end with the delimiter
if right(inputString, 1) <> sep then
set inputString = concat(inputString, sep);
end if;
DROP TABLE IF EXISTS MyTemporaryTable;
CREATE TEMPORARY TABLE MyTemporaryTable ( columnName varchar(100) );
set breaker = 0;
while (breaker < 2000) && (length(inputString) > 1) do
-- Iterate looking for the delimiter, add rows to temporary table.
set breaker = breaker + 1;
set pos = INSTR(inputString, sep);
set item = LEFT(inputString, pos - 1);
set inputString = substring(inputString, pos + 1);
insert into MyTemporaryTable values(item);
end while;
SELECT * FROM MyTemporaryTable;
END
I would like to use this process in a function or procedure in order to call it in any procedure that needs it.
So here is the problem :
I don't know how to store the result of this procedure into a variable : i can't use the SELECT * INTO #p FROM ...; like CALL stringToTmpTable(<string>,<separator>) INTO #table;
An other way would be to add OUT parameter to stringToTmpTable() but it can't return multiple rows. Unfortunatly the amount of parameters in the string is variable so i can't define as much variable as there is parameters in the string.
Finally the FIND_IN_SET() isn't the solution i need.
In the worst case I could copy / past the stringToTmpTable() process in any other procedure that needs it, but that doesn't seem like the best way to me.
Any suggestions ?
"i'm able to translate a string into a temporary table" too, but I am using a different method:
SET #input = 'Banana, Apple, Orange, Pears';
WITH RECURSIVE cte1 as (
select
#input as s,
substring_index(substring_index(#input,',',1),',',-1) as w,
length(#input)-length(replace(#input,',','')) x
union all
select
substring_index(s,',',-x),
trim(substring_index(substring_index(substring_index(s,',',-x),',',1),',',-1)) as w,
x-1 x
from cte1 where s<>'' and x>0
)
select * from cte1
DBFIDDLE
But it's a bit of a problem to determine the real problem you have, which is causing you to ask this question. So this is not an answer, but just a different way of selecting all words from a comma-delimted string.
I'm trying to make only the odd indexes of a string in uppercase (whereas the even indexes to be in lowercase) in MySQL.
For example: StackOverflow -> StAcKoVeRfLoW or hello -> HeLlO.
I found a way to this by extracting a letter at a time using the mid function, then concatenating based on which index the letter is at:
SET #x='hello';
SELECT #x as Initial,
Concat(ucase(mid(#x,1,1)),lcase(mid(#x,2,1)),ucase(mid(#x,3,1)),lcase(mid(#x,4,1)),ucase(mid(#x,5,1)))
as Final;
However I'm interested if there is a way to simplify this, since if the string would be larger then we would have some problems. So basically is there a way to modify it to something like:
Concat(ucase(mid(#x,odd index,1)),lcase(mid(#x,even index,1)))?
This is probably most simply done in your application, but can be achieved in MySQL. For MySQL 8+ you can use a recursive CTE to extract the individual letters from the string and GROUP_CONCAT to put them back together, changing the case on an alternating basis:
WITH RECURSIVE INITIAL AS (
SELECT 'StackOverflow' AS x
),
CTE AS (
SELECT 1 AS upper, SUBSTRING(x, 1, 1) AS letter, SUBSTRING(x, 2) AS remainder
FROM INITIAL
UNION ALL
SELECT 1 - upper, SUBSTRING(remainder, 1, 1), SUBSTRING(remainder, 2)
FROM CTE
WHERE LENGTH(remainder) > 0
)
SELECT GROUP_CONCAT(CASE WHEN upper THEN UPPER(letter) ELSE LOWER(letter) END SEPARATOR '') AS new
FROM CTE
Output:
StAcKoVeRfLoW
In versions lower than 8, you can use a user-defined function:
DELIMITER //
CREATE FUNCTION AlterCase(initial TEXT)
RETURNS TEXT
DETERMINISTIC
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE l CHAR(1);
DECLARE new TEXT DEFAULT '';
WHILE i <= LENGTH(initial) DO
SET l = SUBSTRING(initial, i, 1);
SET new = CONCAT(new,
CASE WHEN i % 2 = 1 THEN UPPER(l) ELSE LOWER(l) END);
SET i = i + 1;
END WHILE;
RETURN new;
END //
DELIMITER ;
And call it as
SELECT AlterCase('StackOverflow')
Output:
StAcKoVeRfLoW
Note the function will work in MySQL 8+ too.
Demo on dbfiddle
This works:
drop table #A
select v = getdate()
into #A
select * from #A
But not this (no result):
drop table #A
create table #A (v varchar(30))
declare #x varchar(30) = 'select v = getdate() into #A'
execute(#x)
select * from #A
I need to be able to do this above one to address a scenario. Must be simple and silly, but just trying to understand why this just doesn't work like first one?
Please advise. Thanks experts!
I can propose workaround and move all you script to #x variable.
So your script will be as:
declare #x nvarchar(MAX) = '
drop table IF EXISTS #A
select v=getdate() into #A
select * from #A'
PRINT(#x)
EXEC(#x)
MSDN says
SELECT…INTO creates a new table in the default filegroup and inserts the resulting rows from the query into it.
So if you create table prior to select into, you cannot use select into, you need to use insert into
i can't seem to found any fault on my code to make a trigger. ( i usually code using oracle, but i convert to my sql in this project, checked all the function and convert those that aren't available in mysql already)
here's the code :
CREATE TRIGGER `transaction_before_insert` BEFORE INSERT ON `transaction` FOR EACH ROW BEGIN
DECLARE TEMPKODE VARCHAR(12);
DECLARE TEMP VARCHAR(5);
TEMP:= CONCAT('T',DATE_FORMAT(NOW(),'%Y'));
SELECT CONCAT(TEMP, LPAD(NVL(MAX(CAST(SUBSTR(TRANSACTION_ID,5,5) AS UNSIGNED))+1,1),5,0))
FROM TRANSACTION INTO TEMPKODE
WHERE SUBSTR(TRANSACTION_ID,1,4) = TEMP;
NEW.TRANSACTION_ID := TEMPKODE;
END
EDIT 1:
i'm coding it from heidisql if there's any code difference, since i heard if i do it on mysql work bench i should use
SET variables
instead of directly
variables :=
the desired result is forex: T201600001
//T for transaction, 2016 i got it from dateformat, and the rest is choosing the biggest data from the database
it's a software for production planning so i'm making the transaction code
NVL, is a function built for you?, Oracle NVL function does not exist in MySQL (find its equivalent in MySQL), see IFNULL.
DELIMITER $$
BEGIN
DECLARE TEMPKODE VARCHAR(12);
DECLARE TEMP VARCHAR(5) DEFAULT CONCAT('T',DATE_FORMAT(NOW(),'%Y'));
-- OR: SET TEMP := CONCAT('T',DATE_FORMAT(NOW(),'%Y'));
-- TEMP := CONCAT('T',DATE_FORMAT(NOW(),'%Y'));
/*
SELECT CONCAT(TEMP,LPAD(NVL(MAX(CAST(SUBSTR(TRANSACTION_ID,5,5) AS UNSIGNED))+1,1),5,0))
FROM TRANSACTION INTO TEMPKODE
WHERE SUBSTR(TRANSACTION_ID,1,4) = TEMP;
*/
SELECT CONCAT(TEMP,LPAD(COALESCE(MAX(CAST(SUBSTR(TRANSACTION_ID,5,5) AS UNSIGNED))+1,1),5,0))
FROM TRANSACTION
WHERE SUBSTR(TRANSACTION_ID,1,4) = TEMP INTO TEMPKODE;
-- NEW.TRANSACTION_ID := TEMPKODE;
SET NEW.TRANSACTION_ID := TEMPKODE;
END$$
DELIMITER ;
UPDATE
You can simplify with the answer of #GordonLinoff:
SET NEW.TRANSACTION_ID := CONCAT(...);
You really do not need temporary variables for this operation (in either Oracle or MySQL). I think the following is the same logic:
BEGIN
select new.transactionid := CONCAT('T', YEAR(now()),
LPAD(COALESCE(MAX(SUBSTR(TRANSACTION_ID, 5, 5) + 1
), 1
), 5, 0)
from transaction t
where TRANSACTION_ID LIKE CONCAT(YEAR(now()), '%')
END;
I want to make propotion codes for my product.
I have created an appropriate SQL statement which basically uses the current timestamp and runs SHA1 on it.
I tried a while ago to create an iterative loop over my INSERT command but failed
anyone know how?
Do 50 times
INSERT INTO ......
end
Also, I cannot have two of the same promotion code so the timestamp needs to be different for each iteration (If it is at all possible that the timestamp might be the same between iterations).
write the code in python or some other scripting language.
Use a GUID for the promotion code rather than a hash of the timestamp.
http://dev.mysql.com/doc/refman/5.0/en/flow-control-constructs.html
Your approach with using the PROCEDURE is the best I guess. I would first set another delimiter, because you are using the ';' already:
delimiter //
After that define your procedure. The INSERT INTO ...... is your INSERT code, what you wrote in your question.
CREATE PROCEDURE createPromotions(p1 INT)
BEGIN
SET #x = 0;
REPEAT
SET #x = #x + 1;
INSERT INTO ......
UNTIL #x > p1
END REPEAT;
END
//
After entering the '//' the procedure is ready to CALL. And if you want to execute it 50 times, just call it 50 times:
CALL createPromotions(50)
This is pretty dirty, but if you have any table on your system which you know has more than 50 rows, you can do the following:
create table promotion_code ( pc varchar(100) );
set #c = 1;
insert into promotion_code
select sha1( now() + (#c := #c + 1 ) )
from mysql.help_relation limit 50;
CREATE PROCEDURE createPromotions(p1 INT)
BEGIN
SET #x = 0;
REPEAT SET #x = #x + 1; UNTIL #x > p1 END REPEAT;
END
Some sort of proceedure like this would be nice but I don't know how to get it into the format I need. which is to repeat an SQL statement 50 times