Reputation: 175
I have about 5 million rows in a MySQL database that match the following system
n1-n2-n3-n4-n5 (e.g. 8-23-43-12-3) where each number is unique to that sequence. In addition, each number ranges from 1 to 99.
I need a way to retrieve all rows within the MySQL DB where three out of the five numbers are matched. For example, a user enters 4-23-65-82-3, I want to return all of the rows that share any 3 of the five numbers entered, so 4-65-12-49-82 matches, 34-23-76-3-65 matches, etc.
My table is as follows:
number_table
(id
, uuid
, five_numbers
, first_number
, second_number
, third_number
, fourth_number
, fifth_number
)
What I have tried so far:
loop through every row and match for any row that has the first_number
be any of the five numbers the user submitted. This is just not smart!
matching with RegExp in MySQL, but that would require a SQL statement that includes every possible combination. That is not too smart, however if anyone has a more efficient MySQL REGEXP
that I can use great.
I am essentially looking for a SQL solution since I don't have to worry about memory exhaustion, SQL execution would be faster, and I would like to place it in a view so I can execute some commands on that.
I apologize for the lengthy post, but I wanted to give as much info.
Thanks!
Upvotes: 0
Views: 114
Reputation: 4921
The MySQL FIELD
function is useful here:
SELECT id, uuid, five_numbers,
FIELD(A, first_number , second_number , third_number , fourth_number , fifth_number) > 0 as aFound,
FIELD(B, first_number , second_number , third_number , fourth_number , fifth_number) > 0 as bFound,
FIELD(C, first_number , second_number , third_number , fourth_number , fifth_number) > 0 as cFound,
FIELD(D, first_number , second_number , third_number , fourth_number , fifth_number) > 0 as dFound,
FIELD(E, first_number , second_number , third_number , fourth_number , fifth_number) > 0 as eFound
FROM number_table
WHERE
(
first_number in (A, B, C, D, E)
OR second_number in (A, B, C, D, E)
OR third_number in (A, B, C, D, E)
)
AND aFound + bFound + cFound + dFound + eFound >= 3;
The FIELD
function returns the index of the argument in which it finds the first argument, or it returns 0. If you SELECT (n > 0)
as an argument, it resolves to TRUE
which MySQL treats as an integer value of 1
. So you can add them together to check the values, without having to do a subquery. You can get a little extra performance out of doing the 'in' checks on the individual fields so you don't have to calculate the function values against the whole table rowset. You only have to check the first three fields, though, because if it hasn't matched at least one of them, it can't possibly match three of the five numbers.
It should also possible to simply select
SELECT *
FROM number_table
WHERE
((LOCATE(A, five_numbers) > 0) +
(LOCATE(B, five_numbers) > 0) +
(LOCATE(C, five_numbers) > 0) +
(LOCATE(D, five_numbers) > 0) +
(LOCATE(E, five_numbers) > 0)) >= 3
Upvotes: 0
Reputation: 71
Assuming you have your input from the user as n1, n2, n3, n4, n5 you can write an sql as follows:
select id, uuid, five_numbers from
(select *,
if(first_number in (n1,n2,n3,n4,n5), 1, 0) +
if(second_number in (n1,n2,n3,n4,n5), 1, 0) +
if(third_number in (n1,n2,n3,n4,n5), 1, 0) +
if(fourth_number in (n1,n2,n3,n4,n5), 1, 0) +
if(fifth_number in (n1,n2,n3,n4,n5), 1, 0) as total
from number_table) as t
where total >= 3
So if any of the five numbers have the value it will add 1 to the total. Then you can filter your rows with numbers that contain 3 or more numbers of the users input
Upvotes: 1
Reputation: 17289
Quick answer is:
SELECT * FROM
(SELECT *,
five_numbers REGEXP '^3-|-3-|-3$' as n1,
five_numbers REGEXP '65' as n2,
five_numbers REGEXP '82' as n3
FROM `number_table`) as t
WHERE t.n1+t.n2+t.n3=3
if you need I can set php code with PDO, just ask
Upvotes: 0