I've already written the function, I'm trying to use FROM within an IF statement. The code below is written within a function.
IF myParameter IN (SELECT id FROM myTable) AND myTable.myType='Type A' THEN
Of course, it gives an error
Unknown table 'myTable'
when trying to execute the function.
EDIT: myParameter is an INT
Is this what you want?
IF myParameter IN (SELECT id FROM myTable WHERE myTable.myType = 'Type A') THEN
That is, move the condition to the subquery.
Typically, I'd use EXISTS for this kind of check:
IF EXISTS (SELECT * FROM myTable WHERE id = myParameter AND myType='Type A') THEN
EXISTS will stop processing at the first match, and despite requiring a SELECT for syntax reasons, doesn't actually create an intermediate result; IN generally processes the entire query within it, formulates a result set, and then checks the left hand argument of the IN against potentially everything in that result (it probably stops at the first match two, but it still had to assemble the entire result).
If myparameter is filtering on the table's primary key, it probably will not make much of a difference in this case; but it something to keep in mind in the more general sense.
Related
I'm using Grafana to plot data from a MySQL datasource. Is it possible to, in a panel's query editor, use an IF ... THEN ... type statement. I would like to create a variable that I could put in the IF. I want the variable to be a condition, not necessarily to be used directly in the query.
For example:
//IN THE DATA SOURCE:
CREATE TABLE Example (Id INT, ANIMALS VARCHAR(15));
INSERT INTO Example VALUES (1,'Dog'), (2,'Fish'), (3,'Cat'), (4,'Lizard')
For a variable Test with values "Mammal',"Reptile", "Other":
//WHAT I'D LIKE IN GRAFANA QUERY EDITOR:
IF($Test = "Mammal") THEN
SELECT * FROM Example WHERE Id = 1 OR Id =3;
ELSE
SELECT * FROM Example WHERE Id = 2 OR Id =4;
END IF;
Is this kind of condition based query even possible? If so, what is the proper syntax to get it to work? Is there any way I can use Grafana variables to have a similar effect?
Use query. Query starts with SELECT keyword. Don't use any IF ELSE conditions before query, e.g.:
SELECT *
FROM Example
WHERE
Data IN ( ${variable:csv} )
This WHERE condition syntax will work with single value, multi value Grafana dashboard variables and also with All value (no custom All value, but blank=auto). Of course this condition is mainly for INT column types. STRING types may need different one (e.g. with LIKE and regexp matching).
Code all your logic (dependency on the dashboard variable) in the WHERE section. Use query inspector to see SQL which is generated and tweak it to correct SQL syntax.
Instead of an if, you can use or. It's really useful for conditionally checking variables:
select * from Example
where (Id in (1,3) or '$Test' != 'Mammal')
and (Id in (2,4) or '$Test' == 'Mammal')
Hi I'd like to know if it's OK to assume that the SELECT statement selects the fields from left to right to make sure that it is safe to construct a statement as the following (it wouldn't be nice to try to use a variable that has't been set):
SELECT #variable := IFNULL(var, 0), value + #variable, somevalue, value2*#variable, ..., #variable/whatever...
FROM table1 LEFT JOIN table2 LEFT JOIN table3
The reason I'm asking the question is because it is possible that var equals null in some of the tuples due the use of the LEFT JOINS (let's suppose that var comes from table 3), and I need to use the variable several times to make derivative fields as you can see, so I don't want to use IFNULL(var, 0) every time.
From the docs (with my emphasis):
As a general rule, other than in SET statements, you should never
assign a value to a user variable and read the value within the same
statement. For example, to increment a variable, this is okay:
SET #a = #a + 1;
For other statements, such as SELECT, you might get the results you
expect, but this is not guaranteed. In the following statement, you
might think that MySQL will evaluate #a first and then do an
assignment second:
SELECT #a, #a:=#a+1, ...;
However, the order of evaluation for expressions involving user
variables is undefined.
So, if we go by the book, the answer to your question is NO.
This case is similar to: S.O Question; mySQL returns all rows when field=0, and the Accepted answer was a very simple trick, to souround the ZERO with single quotes
FROM:
SELECT * FROM table WHERE email=0
TO:
SELECT * FROM table WHERE email='0'
However, my case is slightly different in that my Query is something like:
SELECT * FROM table WHERE email=(
SELECT my_column_value FROM myTable WHERE my_column_value=0 AND user_id =15 LIMIT 1 )
Which in a sense, becomes like simply saying: SELECT * FROM table WHERE email=0, but now with a Second Query.
PLEASE NOTE: It is a MUST that I use the SECOND QUERY.
When I tried: SELECT * FROM table WHERE email='( SELECT my_column_value FROM myTable WHERE my_column_value=0 LIMIT 1 )' (Notice the Single Quotes on the second query)
MySql SCREAMED Errors near '(.
How can this be achieved
Any Suggestion is highly honored
EDIT1: For a visual perspective of the Query
See the STEN_TB here: http://snag.gy/Rq8dq.jpg
Now, the main aim is to get the sten_h where rawscore_h = 0;
The CURRENT QUERY as a whole.
SELECT sten_h
FROM sten_tb
WHERE rawscore_h = (
SELECT `for_print_stens_rowscore`
FROM `for_print_stens_tb`
WHERE `for_print_stens_student_id` =3
AND `for_print_stens_factor_name` = 'Factor H' )
The result of the Second Query can be any number including ZERO.
Any number from >=1 Works and returns a single corresponding value from sten_h. Only =0 does not Work, it returns all rows
That's the issue.
CORRECT ANSWER OR SOLUTION FOR THIS
Just in case someone ends up in this paradox, the Accepted answer has it all.
SEE STEN_TB: http://snag.gy/Rq8dq.jpg
SEE The desired Query result here: http://snag.gy/wa4yA.jpg
I believe your issue is with implicit datatype conversions. You can make those datatype conversions explicit, to gain control.
(The "trick" with wrapping a literal 0 in single quotes, that makes the literal a string literal, rather than a numeric.)
In the more general case, you can use a CAST or CONVERT function to explicitly specify a datatype conversion. You can use an expression in place of a column name, wherever you need to...
For example, to get the value returned by my_column_value to match the datatype of the email column, assuming email is character type, something like:
... email = (SELECT CONVERT(my_column_value,CHAR(255)) FROM myTable WHERE ...
or, to get the a literal integer value to be a string value:
... FROM myTable WHERE my_column_value = CONVERT(0,CHAR(30)) ...
If email and my_column_value are just indicating true or false then they should almost certainly be both BIT NOT NULL or other two-value type that your schema uses for booleans. (Your ORM may use a particular one.) Casting is frequently a hack made necessary by a poor design.
If it should be a particular user then you shouldn't use LIMIT because tables are unordered and that doesn't return a particular user. Explain in your question what your query is supposed to return including exactly what you mean by "15th".
(Having all those similar columns is bad design: rawscore_a, sten_a, rawscore_b, sten_b,... . Use a table with two columns: rawscore, sten.)
I'm having some trouble setting a user variable in MySQL and using it in the same query. I found one or two other questions similar to this, but couldn't get any of their solutions to work in my case.
Here's my query, stripped down a bit. I replaced values and names and stuff for simplicity, and removed some irrelevant parts, but left the basic structure for some context. Not really relevant but fyi I'm using CodeIgniter's active record class to build the query.
SELECT * FROM (things, (SELECT #exp_time := IF(5 < 10, X, Y) as var))
JOIN more_things ON ...
WHERE ...
AND #exp_time < UNIX_TIMESTAMP()
AND `#exp_time` > 1319180316
ORDER BY ...
LIMIT 1 ...
The error I'm getting is: "Every derived table must have its own alias."
Would really appreciate any assistance. Thanks!
Your actual error is because (as the error message explains) you haven't specified an alias for your derived table, and this is required in MySQL (even if you never use the alias anywhere else in your query).
SELECT *
FROM
(
things,
(SELECT #exp_time := IF(5 < 10, X, Y) as var) AS your_alias
)
...
However you don't need variables here. Now that your derived table actually has a name you have a way to refer to your value without needing to store it an a variable.
From working on this specific situation, it was news to me that the logic operators are not short circuited in SQL.
I routinely do something along these lines in the where clause (usually when dealing with search queries):
WHERE
(#Description IS NULL OR #Description = myTable.Description)
Which, even if it's not short-circuited in this example, doesn't really matter. However, when dealing with the fulltext search functions, it does matter.. If the second part of that query was CONTAINS(myTable.Description, #Description), it wouldn't work because the variable is not allowed to be null or empty for these functions.
I found out the WHEN statements of CASE are executed in order, so I can change my query like so to ensure the fulltext lookup is only called when needed, along with changing the variable from null to '""' when it is null to allow the query to execute:
WHERE
(CASE WHEN #Description = '""' THEN 1 WHEN CONTAINS(myTable.Description, #Description) THEN 1 ELSE 0 END = 1)
The above code should prevent the full-text query piece from executing unless there is actually a value to search with.
My question is, if I run this query where #Description is '""', there is still quite a bit of time in the execution plan spent dealing with clustered index seeks and fulltextmatch, even though that table and search does not end up being used at all: is there any way to avoid this?
I'm trying to get this out of a hardcoded dynamic query and into a stored procedure, but if the procedure ends up being slower, I'm not sure I can justify it.
It's not ideal, but maybe something like this would work:
IF #Description = ''
BEGIN
SELECT ...
END
ELSE
BEGIN
SELECT ...
WHERE CONTAINS(mytable.description, #Description)
END
That way you avoid mysql and also running the FT scan when it's not needed.
As a few general notes, I usually find CONTAINSTABLE to be a bit faster. Also, since the query plan is going to be very different whether you're using my solution or yours, watch out for parameter sniffing. Parameter sniffing is when the optimizer builds a plan based on a passed in specific parameter value.
In case anyone else runs into a scenario like this, this is what I ended up doing, which is pretty close to what M_M was getting at; I broke away the full-text pieces and placed them behind branches:
DECLARE #TableBfullSearch TABLE (TableAId int)
IF(#TableBSearchInfo IS NOT NULL)
INSERT INTO #TableBfullSearch
SELECT
TableAId
FROM
TableB
WHERE
...(fulltext search)...
DECLARE #TableCfullSearch TABLE (TableAId int)
IF(#TableCSearchInfo IS NOT NULL)
INSERT INTO #TableCfullSearch
SELECT
TableAId
FROM
TableC
WHERE
...(fulltext search)...
--main query with this addition in the where clause
SELECT
...
FROM
TableA
WHERE
...
AND (#TableBSearchInfo IS NULL OR TableAId IN (SELECT TableAId FROM #TableBfullSearch))
AND (#TableCSearchInfo IS NULL OR TableAId IN (SELECT TableAId FROM #TableCfullSearch))
I think that's probably about as good as it'll get without some sort of dynamic query