Reputation: 9007
I've just solved an interesting problem using MySQL's IN, but I don't know what this "trick" is called.
In my design I needed to filter out rows that either did not require a certain skill, or for which the skill name and the skill level were met. Here's the solution:
SELECT * FROM table WHERE
skillname = "" OR
(skillname, skilllevel) IN (
SELECT name, level FROM skills WHERE user="Mikhail"
)
I didn't know that expr
IN (value
,...), as according to dev.mysql.com both expr
and value
can be multiple columns.
What is this called, and are there more shortcuts like these?
More importantly - is there a way to convert this query to match skilllevel
as "greater than or equal to"?
Solution as per @yokoloko (though he won't admit it)
SELECT * FROM t1 WHERE
skillname = "" OR
skillname IN (
SELECT name FROM skills WHERE user="Mikhail" AND level >= t1.skilllevel
)
Upvotes: 4
Views: 134
Reputation: 562300
Sorry, the IN
predicate always compares values for equality, not greater than or equal to.
Here's how I'd write it:
SELECT table.*
FROM table WHERE skillname = ''
UNION ALL
SELECT table.*
FROM table JOIN skills
ON table.skillname = skills.name AND table.skilllevel >= skills.level
WHERE skills.user = 'Mikhail'
As for terminology of your query, @guide points out that you ran a row subquery, and compared it to a literal row using row constructor syntax. SQL allows you to create anonymous rows using columns, expressions, or values, and use them in certain circumstances, like comparing to another row with a compatible number of columns. I'd call this row comparison.
You can also use this in a join condition, but if you want equality comparison for one column and inequality for another column, it gets really unclear:
SELECT table.*
FROM table JOIN skills
ON (table.skillname, table.skilllevel) >= (skills.name, skills.level)
WHERE skills.user = 'Mikhail'
The above would probably not do what you want. Example:
SELECT (1,2) = (1,2); -- returns true (i.e. 1 in MySQL)
SELECT (1,2) >= (1,2); -- returns true
SELECT (1,3) >= (1,2); -- returns true
SELECT (1,2) >= (1,3); -- returns false
SELECT (2,3) >= (1,2); -- returns true
SELECT (1,3) >= (2,2); -- returns false
The same comparison operator is applied to all columns in these rows. But it also short-circuits (unlike AND
):
SELECT (2,3) >= (1,4); -- returns true
The 2 is greater than 1, but 3 is not greater than 4. Confusing? Consider an example of alphabetizing:
SELECT ('Smith', 'Agent') >= ('Anderson', 'Thomas'); -- returns true
Smith is greater than Anderson, but Agent is not greater than Thomas. Nevertheless, we know how we would order these two names in a phone book.
The point of all this is that you need to write complete boolean expressions if you want more control over the comparison.
Upvotes: 3
Reputation: 19194
That's called row subquery
A row subquery is a subquery variant that returns a single row and can thus return more than one column value.
Upvotes: 2
Reputation: 2860
i don't know how is it called but if I understand well you can do something like this to get the greater than :
SELECT * FROM table t1 WHERE
skillname = "" OR
(skillname, skilllevel) IN (
SELECT name, level FROM skills s WHERE user="Mikhail" and t1.skilllevel >= s.level
)
But I don't know if it's really well optimized.
Upvotes: 0