IF condition in MYsql not giving proper result - mysql

This is code of mysql stored procedure:
BEGIN
DECLARE sms INT(100);
SET sms=(SELECT COUNT(1) FROM tbl_intofone_alert_transaction WHERE smsid='sms_id');
IF(sms<=>0) THEN
INSERT INTO tbl_intofone_alert_transaction(MSISDN,Message,Tag,SenderID,InTime,deliverystatus,
memberid,smsid,updatetime,submit_type,wu_id,DeviceID)
VALUES(mob,msg,tag,sender,NOW(),'0',memid,sms_id,NOW(),'NULL','NULL',DevId);
END IF;
END$$
IF CONDITION in above code doing insertion for all the cases . what i have done wrong here?

it must be
IF(sms<=0) THEN //sms less then or equal 0
or
IF(sms>=0) THEN //sms bigger then or equal 0
<=> this is not comparaison in mysql
obs
VALUES(mob,msg,tag,sender,NOW(),'0',memid,sms_id,NOW(),'NULL','NULL',DevId);
most of those values i dont know what they are , they looks wrong
they must be variables that u get them from your code.
in this code there is only NOW() and NULL which are right

Are you sure that you want to search for the string literal 'sms_id' here?
SELECT COUNT(1) FROM tbl_intofone_alert_transaction WHERE smsid='sms_id'
Probably you meant to use the value of the sms_id variable:
SELECT COUNT(1) FROM tbl_intofone_alert_transaction WHERE smsid = sms_id

Related

MySQL: Is it possible to set a variable outside of SELECT with SELECT as the only permission?

WHAT
I'm on MySQL 5.6 and my account only has permissions for SELECT and USAGE (as found using the SHOW GRANTS command).
Presumably because of this using DECLARE before SELECT returns a generic syntax error.
WHY
I want to use variables to both make the code easier to read and maintain.
Below you can see variable #isOwn is needed in WHERE clause and the day differences could be shortened (note: DATEDIFF didn't work for me in WHERE for some reason)
QUESTION
Being able to declare the variables before SELECT would simplify everything.
Am I doing something wrong or can I not do this because of my minimal permissions?
CODE EXAMPLE
DECLARE #test INT = 5 -- <<< syntax error
SELECT
CASE
WHEN #isOwn := sp.`name` LIKE 'TST %'
THEN 'O' ELSE 'S'
END AS 'Group',
st.`name` AS 'Type',
COUNT(st.`name`) AS 'Count',
DATE(MIN(os.endTime)) AS 'From',
CASE
WHEN #isOwn
THEN TO_DAYS(CURRENT_DATE) - TO_DAYS(MIN(os.endTime)) - 3 + 1
ELSE TO_DAYS(CURRENT_DATE) - TO_DAYS(MIN(os.endTime)) - 28 + 1
END AS 'DO'
FROM tdb.orders AS os
LEFT OUTER JOIN tdb.shipment_type AS st
ON (st.ID = os.shipmentType_ID)
LEFT OUTER JOIN tdb.suppliers AS sp
ON (sp.ID = os.supplier_ID)
WHERE
os.proof IS NULL
AND os.endTime IS NOT NULL
AND ((
sp.`name` NOT LIKE 'TST %' AND
(TO_DAYS(CURRENT_DATE) - TO_DAYS(os.endTime)) >= 3
) OR (
sp.`name` NOT LIKE 'TST %' AND
(TO_DAYS(CURRENT_DATE) - TO_DAYS(os.endTime)) >= 28
))
AND YEAR(os.endTime) = YEAR(CURRENT_DATE)
GROUP BY
CASE
WHEN sp.`name` LIKE 'TST %'
THEN 'O' ELSE 'S'
END,
st.`name`
Use SET keyword instead of DECLARE. The latter is only needed in stored procedures and functions, to define local variables.
You need an user variable, which is different, for example it is not required to define it and it has no strict type. User variables have # prefix, local variables don't. But you can still access it, even from stored procedures/functions.
Also, as commented, you need to separate the two statements (SET and SELECT) with a delimiter ; (or perhaps call them as two statements on the same connection).

Assigning query's results into variable inside MySQL procedure

Here is the piece of sql from my procedure:
....
SET #list := (
SELECT
`i`.`id`
FROM
`Item` AS `i`
Order by RAND()
LIMIT 10
);
RETURN CONCAT_WS( '-', #list );
Inside procedure, I need to set query's results (yes, query returns multiple rows as a result) into some variable.
Then as a second variable, I need to concatenate previous results into one string.
But when I do it, I get following error:
Sub-query returns more than 1 row
So the question is, what am I doing wrong?
By the way, I know about group_concat. In second part of procedure, there is a requirement for checking if some id exists on this #list variable: find_in_set(item_id, #list )
And the query returns random results every time when I call it.
That's why, calling sub-query 2 times: 1 time as group concat string, second time just as list of results is not a solution for me. So, I need them as a set stored in variable.
You are approaching this is exactly the wrong way. There is no reason to store the ids in a list.
In the second part of the procedure, you should just be using a subquery:
where exists (select 1
from item i
where i.id = <outer table>.item_id
)
If you really did want to put things into a list, you would use group_concat() as you allude to:
SELECT #list := GROUP_CONCAT(i.id ORDER BY RAND() SEPARATOR '-') as ids
FROM Item i;
I don't see a use for storing the value in a variable, nor for ordering the ids randomly.
So the question is, what am I doing wrong?
What you're doing wrong is trying to store a result set in a user variable.
https://dev.mysql.com/doc/refman/5.7/en/user-variables.html says:
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.
This kind of variable cannot store an array or a result set. Only one scalar value.
This question has code that seems to be related to Checking and preventing similar strings while insertion in MySQL
You should try following solution to overcome the issue of storing large data, it might help others too looking for solution:
# sets the default 1Mb storage limit to 10Mb
SET SESSION group_concat_max_len = (1024*10);
SET #list := (SELECT GROUP_CONCAT(id) FROM `Item` AS `i` Order by RAND() LIMIT 10);

IF STATEMENT IN MYSQL INSERT is not working

Please, I do not understand why it is not working:
SET #key = (SELECT customer.key_stamp FROM customer WHERE customer.key_stamp = "0000");
CASE WHEN (#key > 0) THEN
INSERT INTO transaction
(transaction.to, transaction.key, transaction.type, transaction.cost_bitcoin, transaction.quantity)
VALUES ("0000", "f5rwsd", 2, 0.0075,
(500000 +
(
(SELECT bonus.amount
FROM bonus
WHERE 500000 BETWEEN bonus.min_quantity AND bonus.max_quantity
) / 500000
) * 100))
END;
I tried the CASE STATEMENT, but it still does not work, and i can't understand the issue.
Please help.
CASE is not a valid MySQL statement. (It's not a valid statement outside the context of a MySQL stored program.)
"Why it is not work"... is because it's not valid SQL.
A CASE expression can be used in a SQL statement where an expression is allowed. (In SQL, an expression returns a value of a particular datatype.)
As an example of using a CASE expression in a SQL statement, something like this:
SELECT CASE WHEN #key > 0 THEN 'somevalue' ELSE 'othervalue' END AS foo
in fact now i use just an sql functions, and it work now, all work, switch case mysql, if else statement mysql, and loops too, like while do, or LOOP ITERATE, all work, just need use it in sql functions, or sql procedure.

Select in IF statement, MySQL

I'm trying to do something like this in My MySQL stored proc:
if val > SELECT numericalValue FROM table where userId=theUserId then ..
Is it ok to do that, or do I have to store numericalValue in a temporary?
You can have a select statement within an if statement.
It needs to be in parentheses and it must evaluate to a single row each time, so it works well for sums and counts, and if you are returning a field's value, you will want to use LIMIT 1
You could also use a variable, that would also work.
You shouldn't have to, but it would make things more convenient if you plan to reuse the selection elsewhere in your code.
Also, you should use the following syntax as a guideline:
CREATE PROCEDURE sp_condition(IN var1 INT)
BEGIN
IF (val > SELECT numericalValue FROM table where userId='theUserId')
THEN SELECT 'greater';
ELSE SELECT 'less than or equal';
END IF;
END|

Using SQL LIKE and IN together

Is there a way to use LIKE and IN together?
I want to achieve something like this.
SELECT * FROM tablename WHERE column IN ('M510%', 'M615%', 'M515%', 'M612%');
So basically I want to be able to match the column with a bunch of different strings. Is there another way to do this with one query or will I have to loop over the array of strings I am looking for?
How about using a substring with IN.
select * from tablename where substring(column,1,4) IN ('M510','M615','M515','M612')
You can do it by in one query by stringing together the individual LIKEs with ORs:
SELECT * FROM tablename
WHERE column LIKE 'M510%'
OR column LIKE 'M615%'
OR column LIKE 'M515%'
OR column LIKE 'M612%';
Just be aware that things like LIKE and per-row functions don't always scale that well. If your table is likely to grow large, you may want to consider adding another column to your table to store the first four characters of the field independently.
This duplicates data but you can guarantee it stays consistent by using insert and update triggers. Then put an index on that new column and your queries become:
SELECT * FROM tablename WHERE newcolumn IN ('M510','M615','M515','M612');
This moves the cost-of-calculation to the point where it's necessary (when the data changes), not every single time you read it. In fact, you could go even further and have your new column as a boolean indicating that it was one of the four special types (if that group of specials will change infrequently). Then the query would be an even faster:
SELECT * FROM tablename WHERE is_special = 1;
This tradeoff of storage requirement for speed is a useful trick for larger databases - generally, disk space is cheap, CPU grunt is precious, and data is read far more often than written. By moving the cost-of-calculation to the write stage, you amortise the cost across all the reads.
You'll need to use multiple LIKE terms, joined by OR.
Use the longer version of IN which is a bunch of OR.
SELECT * FROM tablename
WHERE column LIKE 'M510%'
OR column LIKE 'M615%'
OR column LIKE 'M515%'
OR column LIKE 'M612%';
SELECT * FROM tablename
WHERE column IN
(select column from tablename
where column like 'M510%'
or column like 'M615%'
OR column like 'M515%'
or column like'M612%'
)
substr([column name],
[desired starting position (numeric)],
[# characters to include (numeric)]) in ([complete as usual])
Example
substr([column name],1,4) in ('M510','M615', 'M515', 'M612')
I tried another way
Say the table has values
1 M510
2 M615
3 M515
4 M612
5 M510MM
6 M615NN
7 M515OO
8 M612PP
9 A
10 B
11 C
12 D
Here cols 1 to 8 are valid while the rest of them are invalid
SELECT COL_VAL
FROM SO_LIKE_TABLE SLT
WHERE (SELECT DECODE(SUM(CASE
WHEN INSTR(SLT.COL_VAL, COLUMN_VALUE) > 0 THEN
1
ELSE
0
END),
0,
'FALSE',
'TRUE')
FROM TABLE(SYS.DBMS_DEBUG_VC2COLl('M510', 'M615', 'M515', 'M612'))) =
'TRUE'
What I have done is using the INSTR function, I have tried to find is the value in table matches with any of the values as input. In case it does, it will return it's index, i.e. greater than ZERO. In case the table's value does not match with any of the input, then it will return ZERO. This index I have added up, to indicate successful match.
It seems to be working.
Hope it helps.
You can use a sub-query with wildcards:
SELECT 'Valid Expression'
WHERE 'Source Column' LIKE (SELECT '%Column' --FROM TABLE)
Or you can use a single string:
SELECT 'Valid Expression'
WHERE 'Source Column' LIKE ('%Source%' + '%Column%')
u can even try this
Function
CREATE FUNCTION [dbo].[fn_Split](#text varchar(8000), #delimiter varchar(20))
RETURNS #Strings TABLE
(
position int IDENTITY PRIMARY KEY,
value varchar(8000)
)
AS
BEGIN
DECLARE #index int
SET #index = -1
WHILE (LEN(#text) > 0)
BEGIN
SET #index = CHARINDEX(#delimiter , #text)
IF (#index = 0) AND (LEN(#text) > 0)
BEGIN
INSERT INTO #Strings VALUES (#text)
BREAK
END
IF (#index > 1)
BEGIN
INSERT INTO #Strings VALUES (LEFT(#text, #index - 1))
SET #text = RIGHT(#text, (LEN(#text) - #index))
END
ELSE
SET #text = RIGHT(#text, (LEN(#text) - #index))
END
RETURN
END
Query
select * from my_table inner join (select value from fn_split('M510', 'M615', 'M515', 'M612',','))
as split_table on my_table.column_name like '%'+split_table.value+'%';
For a perfectly dynamic solution, this is achievable by combining a cursor and a temp table. With this solution you do not need to know the starting position nor the length, and it is expandable without having to add any OR's to your SQL query.
For this example, let's say you want to select the ID, Details & creation date from a table where a certain list of text is inside 'Details'.
First create a table FilterTable with the search strings in a column called Search.
As the question starter requested:
insert into [DATABASE].dbo.FilterTable
select 'M510' union
select 'M615' union
select 'M515' union
select 'M612'
Then you can filter your data as following:
DECLARE #DATA NVARCHAR(MAX)
CREATE TABLE #Result (ID uniqueIdentifier, Details nvarchar(MAX), Created datetime)
DECLARE DataCursor CURSOR local forward_only FOR
SELECT '%' + Search + '%'
FROM [DATABASE].dbo.FilterTable
OPEN DataCursor
FETCH NEXT FROM DataCursor INTO #DATA
WHILE ##FETCH_STATUS = 0
BEGIN
insert into #Result
select ID, Details, Created
from [DATABASE].dbo.Table (nolock)
where Details like #DATA
FETCH NEXT FROM DataCursor INTO #DATA
END
CLOSE DataCursor
DEALLOCATE DataCursor
select * from #Result
drop table #Result
Hope this helped
select *
from tablename
where regexp_like (column, '^M510|M615|^M515|^M612')
Note: This works even if say, we want the code M615 to match if it occurs in the middle of the column. The rest of the codes will match only if the column starts with it.