I have a MariaDB table with an archive of past lottery results, imagine EuroMillions or Powerball lotteries.
For example on EuroMillions numbers go from 1 to 50 and then the extra balls from 1 to 12, each result is 5 numbers form the main pool and 2 from the extra pool. So my historic results table could look like this:
Lottery Results table
(other columns like id, date, draw number, etc) | main_numbers | extra_numbers | (timestamp columns)
... | 1,2,3,4,5 | 1,2 | ...
... | 3,12,34,35,45 | 5,11 | ...
... | 4,15,34,39,45 | 10,11 | ...
... | 7,11,25,28,44 | 10,12 | ...
(you get the idea, I have thousands of records...)
So I could select main_numbers and get result "3,12,34,35,45" for that second example row. And for the extra_numbers I would get "5,11".
What I want is to given a set of numbers for main and extra to see if they match any of my results, finding any number of numbers (numbered lottery balls).
So for example if I SELECT to find main_numbers "5,9,22,34,45" with extra_numbers "2,11" I would get (from my extracted example) two records:
... | 3,12,34,35,45 | 5,11 | ...
... | 4,15,34,39,45 | 10,11 | ...
Matching two main numbers and one extra number, in this case finding lottery prizes in the results table. Makes sense?
I'm using MariaDB and I'm a bit lost on how to proceed, I tried WHERE IN, FIELD_IN_SET, etc.
Is there a way to perform a SELECT to find results in only one statement or do I have to pick all records and then iterate elsewhere, php for example?
My aim would be to have it in one statement, so I could just send the numbers and get the matching records... Possible?
I hope this makes sense.
Many thanks for your answers.
Consider the following.
For simplicity, let's say that a lottery comprises 3 main balls, and two bonus balls:
DROP TABLE IF EXISTS lottery_results;
CREATE TABLE lottery_results
(draw_id INT NOT NULL
,ball_no INT NOT NULL
,ball_val INT NOT NULL
,PRIMARY KEY(draw_id,ball_no)
);
INSERT INTO lottery_results VALUES
(1,1,22),
(1,2,35),
(1,3,62),
(1,4,27),
(1,5,17),
(2,1,18),
(2,2,33),
(2,3,49),
(2,4, 4),
(2,5,35);
And we want to find all results where 34, 35, or 36 were drawn as a main number...
SELECT draw_id
FROM lottery_results
WHERE ball_no <=3
AND ball_val IN(34,35,36);
+---------+
| draw_id |
+---------+
| 1 |
+---------+
Thanks Strawberry,
I found a solution if I have all numbers in distinct columns, but could I find if they are in the same column in CSV?
So if I put my CSV in distinct columns for numbers (n_1...n_5) and extra numbers for the stars in (s_1, s_2) I can seek matched in those multiple columns.
This is using multiple columns:
To find matches numbers 1,2,3,4,5 with stars 1,2...
In EuroMillions you get a prize with 2 or more numbers and any star (one or two).
SELECT
main_numbers, extra_numbers,
((n_1 IN (1,2,3,4,5)) +
(n_2 IN (1,2,3,4,5)) +
(n_3 IN (1,2,3,4,5)) +
(n_4 IN (1,2,3,4,5)) +
(n_5 IN (1,2,3,4,5))) AS matched_numbers,
((s_1 IN (1,2)) +
(s_2 IN (1,2))) AS matched_stars,
created_at
FROM `lottery_results_archive`
HAVING matched_numbers >= 3 OR matched_numbers = 2 AND matched_stars > 0
ORDER BY matched_numbers DESC, matched_stars DESC, created_at DESC
Makes sense?
Thanks.
I am needing a way to count comma separated values like this - any
suggestions please?
Table:
id (int) | site (varchar)
1 | 1,2,3
2 | 2,3
3 | 1,3
Desired output:
site | # of occurrences
1 | 2
2 | 2
3 | 3
Without getting into exactly what you're doing, I'll assume you have a sites table. If so, it's technically achievable with something like
SELECT sites.site_id AS site, COUNT(1) AS `# of occurrences`
FROM sites
INNER JOIN table ON FIND_IN_SET(sites.site_id, table.site)
GROUP BY sites.site_id
Performance of that will be appalling, as there is no way to use an index, and the data will be able to get inconsistent very easily.
What the comments in your question are alluding to, is to use a relational table of some description, where instead of storing a comma-separated list, you store a row for each 'occurrence'
I'm trying to design a first serious database and I arrived upon a problem. Here's a quick overview – I have event reports in .csv files, which I parse. They contain user card numbers, points and final places. I have no problem filling that data into my database, but I would also like to store in which events the users exist and how many points they have in each of them, instead of just adding up to a total sum of points across all their events.
So I thought I would make a table called events, which would have a column id (primary key, a_i), event_name (to be displayed on frontend next to respective points) and event_date (same thing, basically).
The next table would be called users, and it would have a column card_number (unique key), total_points (to display the total sum of all points), event_ids and points. There lies the problem – I would like to have in the last two columns a list of comma-separated values, which would "tie-in" with each other. Example:
`event_ids` = (2, 4, 12, 43)
`points` = (202, 11, 444, 1)
So that when I get this info in frontend, I would just loop through these values and get the event_id (which would be the same as id in the events table) and get all the info I need. However, it seems that list of values in a column in MySQL database is a big NO-NO.
So, how to do this right? I hope you understand my problem, thank you in advance. I'd like to begin with best practices. Any help please? I would like an example..
I'm thinking something like this:
user_id | event_id | points
3 | 5 | 250
3 | 12 | 120
3 | 1 | 200
3 | 52 | 40
6 | 2 | 101
6 | 5 | 3
How would I do this?
I'll try to explain my situation: I'm trying to create a search engine for products on my website, so when the user needs to find a product I need to show similar ones, here's an example.
User searches:
assassins creed OR assassinscreed OR aSsAssIn's CreeD assuming there are no letters/numbers mispelling (those 3 queries should produce the same result)
Expected results:
Assassin's Creed AND Assassin's Creed: Unity AND Assassin's Creed: Special Edition
What have I tried so far
I have created a MySQL field for the search engine which contains a parsed name of the product (Assassin's Creed: Unity -> assassinscreedunity
I parse the search query
I search using MySQL's INSTR()
My problem
I'm fine by using this, but I heard it can be slow when the number of rows increases, I've created a full-text index in my table, but I don't think it would help, so I need another solution.
Thanks for any answer, and ask me anything before downvoting.
First of all, you should keep track of performance issues in your queries more precisely than 'heard it cand be slow' and 'think it would help'. One starting point may be the Slow Query Log.
If you have a table which contains the same parsed name in more than one row, consider normalizing your database. In the specific case, store unique parsed names in one table, and only the id of the corresponding parsed name in the table you described in your question. This way, you only need to check the smaller table with unique names and can then quickly find all matching entries in the main table by id.
Example:
Consider the following table with your structure
id | product_name | rating
-----------------------------------
1 | assassinscreedunity | 5
2 | assassinscreedunity | 2
3 | monkeyisland | 3
4 | monkeyisland | 5
5 | assassinscreedunity | 4
6 | monkeyisland | 4
you would have to scan all six entries to find relevant rows.
In contrast, consider two tables like this:
id | p_id | rating
--------------------
1 | 1 | 5
2 | 1 | 2
3 | 2 | 3
4 | 2 | 5
5 | 1 | 4
6 | 2 | 4
id | name
--------------------------
1 | assassinscreedunity
2 | monkeyisland
In this case, you only have to scan two entries (compared to six) and can then efficiently look up relevant rows using the integer id.
To further enhance the performance, you could extend the concept of a parsed name and use hashes. For example, you could calculate the SHA1-hash of your parsed name which is a 160 bit value. You can find entries in your database for this value very efficiently. To match substrings, you can add them to the second table as well. Since the hash only needs to computed once, you still can use the database to match by an integer. Another thing for you might be fuzzy hashing.
In addition, you should read up on the Rabin–Karp algorithm or string searching in general.
I am thinking of returning a randomly ordered SQL response where the results are mixed up randomly, with a limit.
The thing is I need All the rows back, basically divided into groups (chunks of rows). I hope I am clear.
For example, from table A:
ID | NAME | PROFESSION
++++++++++++++++++++++++++++++++
1 | Jack | Carpenter
2 | Rob | Manager
3 | Phil | Driver
4 | Mary | Cook
5 | Tim | Postman
6 | Bob | Programmer
The query would return something like this:
With a limit of 0,2:
6 | Bob | Programmer
4 | Mary | Cook
With a limit of 2,2:
1 | Jack | Carpenter
5 | Tim | Postman
With a limit of 4,2:
3 | Phil | Driver
2 | Rob | Manager
Note: all the table rows were returned. In my page I need to have a << >> buttons that will show the user the needed "group"s of data.
How do I go about writing such a query ?
A better name for your explained problem would be randomly shuffled records. That is true that the order is random but since the order needs to be remembered, you have no choice but to save it in a column. You can do this by saving a randomly populated field and ordering your records based on that. This way you have ordered your records in no specific order while the order is remembered for future select queries. And whenever you got tired of the order, you can update the mentioned field with new randomly generated values to shuffle them again. This is the technique used by players to shuffle a playlist without replaying a song twice.
[EDIT]
While the first given solution stands as the general answer, there's a hack you can use in MySQL to randomly order records. In this way, all you need to store for remembering an order is its seed.
SELECT * FROM tbl ORDER BY RAND(s);
For instance, if you want each user see the records in some different randomly ordered, you can use their user_id as the seed. This way the order each user will ever see the records in, will remain the same while it is random and different from other users.
I can think of two things here:
If the data in the table is huge, add a column that tells the group to which a row belongs. When the user clicks on >> or << buttons, get the rows for that particular group.
If you are dealing with small amount of data, you could do this in the code itself.
If you use ORDER BY RAND() then you will have to flag selected records somewhere which is no advisable.
You can use some intelligent algorithm with combination of total_pages and ID e.g.
SELECT *
FROM my_table
ORDER BY MOD(ID, total_pages);
Add a column to the table called something like random_col
Then each time you need to randomise the table you run
UPDATE table SET random_col = RAND()
And now each time you want to retrieve results you run a normal select
SELECT * FROM table ORDER BY random_col ASC LIMIT x,y
And the results will appear in the same order until you randomise them again by running the 'UPDATE'