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

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.

Related

How to implement score points for each WHERE clause in SELECT statement

how can i create column with information about how much condition was passed for each field?
eg. I have client who find property with max price to 500000, 3th floor and living area between 45 meters. Now when i use "AND" for each condidtions i will get rows with 100% compatibility. But What abaout to find rows with the same condidtions as before but without living area in range. There will be 66% copatibility because 2/3 of my conditions is passed.
There is my sqlfiddle http://sqlfiddle.com/#!9/1ef60c/5
Simple way to solve your problem is:
SELECT *,
(
CASE WHEN `property_max-price` < 550000 THEN 1 ELSE 0 END
+
CASE WHEN property_additional LIKE "%hot_water%" THEN 1 ELSE 0 END
+
CASE WHEN `property_floor-from` >= 2 AND `property_floor-to` <=5 THEN 1 ELSE 0 END
) / 3 * 100 AS `%`
FROM client

MySQL ORDER BY CASE + operator

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

Zend Framework 1 query, ordering results by satisfied criteria

I've to extract all products from "product" table (DBMS: MySQL, Adapter: PDO), ordering result by the number of filtering criteria that are matched.
This is an example of raw SQL query (but I'll use Zend_DB classes and adapters):
SELECT *
FROM product
WHERE price < 300
AND price > 100
AND discount = TRUE
AND used = FALSE
AND type = MEAL
and a lot of other optionals filter criteria that end user could introduce from the UI.
All the filter criteria (where conditions in the query) could be optionally matched by the user in the form of the web app, and the GOAL the my algorithm is to order the results from the most matching criteria product to the product that match at least 2 criteria.
I'm using Zend Framework 1, and my question is:
Is there any Zend class that could help me in this particular algorithm?
If no, could anyone suggest a solution for this problem?
I've tried a crude solution where I'll compose the query considering all the possible combination of the criteria, but considering that there are a lot of criteria, the algorithm complexity increases so much, so I suppose that an alternative may exists.
Thanks
Something like...
SELECT * FROM (
SELECT P.*,
case when price < 300 and price > 100 then 1 else 0 end +
case when discount = true then 1 else 0 end +
case when used = false then 1 else 0 end +
case when type = 'MEAL' then 1 else 0 end +
... (for each possible outcome) as Matches
FROM product p)
Where matches > 2
Order by Matches descending

SELECT Inside a Case in MySQL

Is it possible to create an SELECT Statement within Conditional CASE, like this
SELECT la.*,
(
CASE
WHEN la.SoftDelete = 1
SELECT SUM(la.LoansAmount) FROM loans_account
ELSE
SELECT 0
END
) AS outstanding
FROM loans_account
I have tried this, but it does not work, I would like to know how to go about something like this please.
I guess you need the sum of loan amount where softdelete is 1
SELECT la.*,
SUM(
CASE
WHEN la.SoftDelete = 1
THEN la.LoansAmount
ELSE
0
END
) AS outstanding
FROM loans_account la
WHERE ...
or if you need the sum from whole where softdelete is 1 then you can do so
SELECT la.*,
SUM(la.LoansAmount) outstanding
FROM loans_account la
WHERE la.SoftDelete = 1
Note sum is aggregate function and without group by it will result as a single row assuming the whole table as one group
try this
SELECT la.*, CASE
WHEN la.SoftDelete = 1 THEN SUM(la.LoansAmount)
ELSE 0 END AS outstanding
FROM loans_account

Use previous value in MySQL to compute the next field?

How to use previous values in MySQL to compute the next value? I couldn't explain what I mean more clearly in my poor English (anyone can understand what I asked by seeing the title of this post?), so let me explain it in a snippet:
select
year_id,
sum(case when event_cd >= 20 then 1 else 0 end) as h,
sum(case when ab_fl = "T" then 1 else 0 end) as ab,
h/ab as ba
from events
group by year_id
in the above snippet, when you run the query you will get the error, since there are no such columns in events table as h or ab. However, I want to use h and ab which are computed in the previous sum(case when ~) syntax. I remember there are some sort of ways to make it possible, but I don't remember how to do nor as I said, I couldn't find any relevant posts to meet what I'm asking due to my poor English, though since I'm sure this question is already posted here at SO, it's quite helpful even if you just link it with no detailed explanation.
Thanks.
[Update]
Thanks for the answers. I just wanted to use previous values in order to avoid subqueries and hence lots of redundant typing, and make the entire code more readable. I've used either methods (subqueries or write the entire syntax twice just to compute another value) as described by Mosty Mostacho, and if this is not feasible or pretty risky to use in MySQL, I can surely accept those two methods above. Sorry for the confusion.
There are 2 ways in MySQL (BTW, I've simplified the query a bit but it is still legal):
Option #1: Expand the variables
SELECT
year_id,
SUM(event_cd >= 20) h,
SUM(ab_fl = "T") ab,
SUM(event_cd >= 20) / SUM(ab_fl = "T") ba
FROM events
GROUP BY year_id
Option #2: Use a derived table
SELECT year_id, h, ab, h / ab ba FROM (
SELECT
year_id,
SUM(event_cd >= 20) h,
SUM(ab_fl = "T") ab
FROM events
GROUP BY year_id
) s
You might be tempted to think that the second will run faster but it is not the case. The first one is most likely to run faster because it doesn't need a derived table and can solve the issue in just one pass.
try
select * h/ab as ba from
(
select
year_id,
sum(case when event_cd >= 20 then 1 else 0 end) as h,
sum(case when ab_fl = "T" then 1 else 0 end) as ab,
from events
group by year_id)
source
Update
As #MostyMostacho explains in the comment below, this is not an advisable technique, due to the order of evaluation of user variable being undefined.
You can write a query using a MySQL variable using the syntax #varname := 'value' to store your sums in, and then reference that.
SELECT
year_id
, #h := SUM(CASE WHEN event_cd >= 20 THEN 1 ELSE 0 END) AS h
, #ab := SUM(CASE WHEN ab_fl = "T" THEN 1 ELSE 0 END) AS ab
, #h/#ab AS ba
FROM events
GROUP BY year_id