MySQL ORDER BY CASE + operator - mysql

I am trying to do a search that would be sorted by relevance.
Let's say the search term contains 3 words: A, B and C. What I am trying to do is to check if the search term is present in the SELECT result and if yes that would increase its rank.
ORDER BY CASE
(
WHEN search_word_A_is_present THEN +1
WHEN search_word_B_is_present THEN +1
WHEN search_word_C_is_present THEN +1
ELSE 0
END
)
DESC
While there is no syntax error and the search runs and sorts by something (that seems different from what I want) but I am not sure what is being added up if anything. How would I go about seeing what the final rank (sum) is at the end for each result? Is this the correct way to do it?

Since in MySQL boolean conditions result in 1 and 0, you can simply add those up
ORDER BY search_word_A_is_present + search_word_B_is_present + search_word_C_is_present
DESC
A more practical example:
ORDER BY col1 = 1 + col2 = 'A' + col3 = 44 DESC

Related

SQL query - find values that meet m conditions out of n

Is there any way to find values that meet any m conditions out of given n conditions? For instance, if there are 10 conditions, and I want to find values that meet any 2 of them.
Use CASE expressions in the WHERE clause, 1 for each condition like this:
WHERE 2 =
CASE WHEN <condition1> THEN 1 ELSE 0 END +
CASE WHEN <condition2> THEN 1 ELSE 0 END +
CASE WHEN <condition3> THEN 1 ELSE 0 END +
..........................................
You can change the = sign to > or < to meet your requirement.
There is. It's not gonna be pretty though.
Start with your conditions as SELECT expressions.
select T.*,
case
when T.SOME_NUMERIC_COLUMN > 0 then 1
else 0
end IS_POSITIVE,
(select sign(COUNT(*))
from SOME_OTHER_TABLE
where parent_id = T.ID) HAS_CHILDREN
...
from SOME_TABLE T
Design these expression in such a way that you get 1 when a condition is met and 0 when it's not.
Then sum up the score and add a WHERE clause.
SELECT *
FROM (
SELECT R.*,
IS_POSITIVE + HAS_CHILDREN + ... SCORE
FROM (...) R)
WHERE SCORE > 2
Of course you're gonna pay a hefty price in performance for this. You won't be able to use your conditions directly to limit the resultset so I'd expect the execution plans to be extremely disappointing. That said, it's not like what you have in mind is a standard task for RDBMS so it should be enough for a proof of concept.

SQL How to sort by "Ranges"

I am currently using a database with different entries like dates, names, but also one column with time "ranges". This basically means that there can be a definite number like "10" in this cell, but also a value like "10-15" or "5-10".
So what I want to do here is to sort them by an "average" value ((Lowest+Highest)/2). So in case of the 3 mentioned values it should be
5-10
10
10-15
I am wondering if it is possible to embed this into the SQL statement in some way.
And if it is not possible, I'd like to know the easiest way to implement it otherwise.
Right now I am putting the $SQL_statement together via several conditions, then putting everything into $resultset which is then used with "while". Here are some snippets:
$resultset=mysql_query($SQL_statement);
while ($currententry=mysql_fetch_array($resultset))
{
echo $currententry['Platform'];
echo $currententry['PlaytimeInH']."h";
}
You can do this with substring_index() and arithmetic:
order by (substring_index(col, '-', 1) + 0 +
substring_index(col, '-', -1) + 0
) / 2
The division by 2 is unnecessary, but you do specify the average in your question.
Note that the above will work even if col has no hyphen in it.
You could use a select with a case when clause in order by
select col1, col2, cole
from your_table
order by case
when your_column = '5-10' then 1
when your_column = '10-15' then 2
when your_column = '15-20' then 3
else 4
end

MySQL match area code only when given the full number

I have a database that lists a few area codes, area code + office codes and some whole numbers and a action. I want it to return a result by the digits given but I am not sure how to accomplish it. I have some MySQL knowledge but its not very deep.
Here is a example:
match | action
_____________________
234 | goto 1
333743 | goto 2
8005551212| goto 3
234843 | goto 4
I need to query the database with a full 10 digit number -
query 8005551212 gives "goto 3"
query 2345551212 gives "goto 1"
query 3337431212 gives "goto 2"
query 2348431212 gives "goto 4"
This would be similar to the LIKE selection, but I need to match against the database value instead of the query value. Matching the full number is easy,
SELECT * FROM database WHERE `match` = 8005551212;
First the number to query will always be 10 digits, so I am not sure how to format the SELECT statement to differentiate the match of 234XXXXXXX and 234843XXXX, as I can only have one match return. Basically if it does not match the 10 digits, then it checks 6 digits, then it will check the 3 digits.
I hope this makes sense, I do not have any other way to format the number and it has to be accomplished with just a single SQL query and return over a ODCB connection in Asterisk.
Try this
SELECT match, action FROM mytable WHERE '8005551212' like concat(match,'%')
The issue is that you will get two rows in one case .. given your data..
SELECT action
FROM mytable
WHERE '8005551212' like concat(match,'%')
order by length(match) desc limit 1
That should get the row that had the most digits matched..
try this:
SELECT * FROM (
SELECT 3 AS score,r.* FROM mytable r WHERE match LIKE CONCAT(SUBSTRING('1234567890',1,3),'%')
UNION ALL
SELECT 6 AS score,r.* FROM mytable r WHERE match LIKE CONCAT(SUBSTRING('1234567890',1,6),'%')
UNION ALL
SELECT 10 AS score,r.* FROM mytable r WHERE match LIKE CONCAT(SUBSTRING('1234567890',1,10),'%')
) AS tmp
ORDER BY score DESC
LIMIT 1;
What ended up working -
SELECT `function`,`destination`
FROM reroute
WHERE `group` = '${ARG2}'
AND `name` = 0
AND '${ARG1}' LIKE concat(`match`,'%')
ORDER BY length(`match`) DESC LIMIT 1

Order by date and field

I have SELECT query with LEFT JOINT (SELECT) and order by COALESCE(SELECT2.date, SELECT1.date) but i need to order it too with important field.
So: if row have important = 1 it need to be first, then important = 0 but ordered by coleasce date so as so. Is this even posible?
You could place the important column first in the order by list. Sorting desc (for descending) will place 1 before 0:
order by
important DESC
, coalesce(select2.date, select1.date)
You can even use case to sort the important column in a custom way:
order by
case
when important = 'SENATOR' then 1
when important = 'PATRICIAN' then 2
when important = 'PLEBS' then 3
else 4
end
, coalesce(select2.date, select1.date)

how can I tell if the last x rows of 'state' = 1

I need help with a SQL query.
I have a table with a 'state' column. 0 means closed and 1 means opened.
Different users want to be notified after there have been x consecutive 1 events.
With an SQL query, how can I tell if the last x rows of 'state' = 1?
If, for example, you want to check if the last 5 consecutive rows have a state equals to 1, then here's you could probably do it :
SELECT IF(SUM(x.state) = 5, 1, 0) AS is_consecutive
FROM (
SELECT state
FROM table
WHERE Processor = 3
ORDER BY Status_datetime DESC
LIMIT 5
) as x
If is_consecutive = 1, then, yes, there is 5 last consecutive rows with state = 1.
Edit : As suggested in the comments, you'll have to use ORDER BY in your query, to get the last nth rows.
And for more accuracy, since you have a timestamp column, you should use Status_datetime to order the rows.
You should be able to use something like this (replace the number in the HAVING with the value of x you want to check for):
SELECT Processor, OpenCount FROM
(
SELECT TOP 10 Processor, DateTime, Sum(Status) AS OpenCount
FROM YourTable
WHERE Processor = 3
ORDER BY DateTime DESC
) HAVING OpenCount >= 10