SQL lottery query - php

I have a simple table of 7 columns
Week ¦ 1st ¦ 2nd ¦ 3rd ¦ 4th ¦ 5th ¦ 6th ¦
Each week, my father adds Saturdays UK lottery numbers to a simple PHP script that I created. He has early onset Alzheimers and tries to keep his brain active. Tonight he asked me a question about the database. He asked me if it was possible to see the 6 most popular numbers.
I tried to create a simple SQL query:
SELECT 1st, 2nd, 3rd, 4th, 5th, 6th, COUNT(*) AS 'foo' FROM `dad` GROUP BY 1st, 2nd, 3rd, 4th, 5th, 6th ORDER BY foo DESC
But the results weren't as I expected.
1st 2nd 3rd 4th 5th 6th foo
2 6 8 32 33 35 1
3 6 12 17 35 40 1
3 6 31 43 46 53 1
etc
What I hoped would happen would be for the table to merge into one column, and then count and have a simple result, something like:
Number Count
2 1
3 2
6 3
8 1
And then maybe put it in ascending order. I can then use that SQL query to create a simple table for him to show the most common numbers.
I'm thinking of doing a general SQL query
SELECT 1st FROM `dad`
Then creating an Array with the results, then adding
SELECT 2nd FROM `dad`
To the end of the Array and continuing for all 6 columns, then using PHP to count the numbers individually.
Is there a quicker way?

Your first effort should go into fixing your data model. Each number should be stored on a separate row rather than in a column, like:
week pos num
1 1 6
1 2 8
1 3 32
Then your query would be a simple aggregate query:
select num, count(*) no_picks from dad group by num order by no_picks desc
For your given table structure, you would need to unpivot the columns to rows. In MySQL, you can use union all for this:
select num, count(*) no_picks
from (
select `1st` num from dad
union all select `2nd` from dad
union all select `3rd` from dad
union all select `4th` from dad
union all select `5th` from dad
union all select `6th` from dad
) t
group by num
order by no_picks

You can do:
select
n, cnt
from (
select
n,
count(*) as cnt
from (
select `1st` as n from `dad` union all
select `2nd` from `dad` union all
select `3rd` from `dad` union all
select `4th` from `dad` union all
select `5th` from `dad` union all
select `6th` from `dad`
) x
group by n
) y
order by cnt desc
limit 6

Related

How to count multiple columns with mysqli?

I am facing a problem I am not capable to solve on my own. There a several questions out that regarding counting but I did no see one where the counting is done like I would need it. In my table I have three slots that can be booked by a Person, represented by their ID, like this:
ID | Slot1 | Slot2 | Slot3
1 45 53
2 1 27 6
3 53
4 6 45
5 15 53
It is possible that slots are free but it is not possible that an ID blocks to slots.
Now I would like to count how often each ID used on of the three slots. The result would look like this for the table above:
ID Count
1 1
6 2
15 1
27 1
45 2
53 3
Is that possible with one mysql statement or do I need to GROUP BY for each slot and add the slots up later in my script?
If it is possible to do the counting in mysql over all three slots, would it also be possible to join the result with a second table that holds the names to the IDs?
You want a union all and aggregation:
select slot, count(*)
from ((select slot1 as slot from t
) union all
(select slot2 as slot from t
) union all
(select slot3 as slot from t
)
) s
where slot is not null
group by slot
You can use UNION :
SELECT s.SLOT_ID, COUNT(*)
FROM (
SELECT slot1 as slot_id FROM YourTable
UNION ALL
SELECT slot2 FROM YourTable
UNION ALL
SELECT slot3 FROM YourTable ) s
GROUP BY s.slot_id

MySQL Find an ID based on 2 ids

i would like to see if player A (9) and player B (14) have ever both entered the same round, one round has many entries by many players. this is the middle table of a many to many relationship between rounds and players
table: entries
id | roundID | PlayerID
5 | 7 | 14
4 | 6 | 2
3 | 5 | 14
2 | 5 | 9
1 | 4 | 9
Im looking to return round ID 5 obviously, but what SQL statement does this need? a JOIN?
i could do it by getting all rounds played by player A and B seperately looping through As rounds and looping through Bs rounds on each iteration of A to look for a match, but that seems needlessly costly.
Something like this should work, basically getting a count of all the PlayerID enteries per roundID for only the specified players and restricting to show only ones with multiples.
SELECT
roundID
FROM
entries
WHERE
PlayerID IN (9, 14)
GROUP BY
roundID
HAVING
COUNT(*)>1
If I understand the question correctly, something as simple as a SELECT DISTINCT will work here:
SELECT DISTINCT roundID
FROM entries
WHERE PlayerID IN (9, 14)
Use INNER JOIN with subqueries as follow
SELECT * FROM (SELECT * FROM tests WHERE player_id='9') t9 INNER JOIN (SELECT * FROM tests WHERE player_id='14') t14 ON t9.round_id = t14.round_id

count repeated value in table field

how i can count the repeated value in any field of mysql db's table.
Example:
id name
1 aaa
2 aaa
3 ttt
4 ccc
5 ttt
6 ccc
7 aaa
8 zzz
How i can get how many times value is repeated in table like.
aaa =3 times in table
ttt =2 times in table
ccc =2 times in table
zzz =1 times in table
I think it possible with count of the mysql but how to use it i dont know any one can help ?please answer ma question thanks in adv.
You need to group by your name column and then you can use an aggregate function like count() on that group
select name, count(id)
from your_table
group by name
Write below query to get count of each name
select name, count(name)
from your_table
group by name
OR
to get count of specific name
select name, count(name)
from your_table
where name = "aaa"
group by name

Mysql Sorted items by user get an overall order

I have a list of films that users can rank in order of which they like best using jQuery UI Sortable (all works well). The lower the order number the better the film (1) and the higher (26) the worse it is. The list of films could be endless but is fixed in the database (users can't add more), so the user can only select from x list of films.
Films do not have to be in the users list, if they haven't seen film 5 then it won't get included (this may be compounding the problem).
Currently this is stored in the table:
film_id | user_id | order
4 2 3
5 3 3
6 2 1
7 2 2
7 3 1
8 3 2
What I want, and don't know where to start is an overall 'Top 10' style list. i.e. film 7 is the most popular because it appears higher up peoples lists and is in more lists. Film 6 could be the most popular but it's only in one list?!
I am stuck on both the logic and the Mysql queries to do it!
I am thinking I might need to weight the order somehow? Or have a separate table with the score per film and just update it after every edit. The following query seems like the right idea if it was just based on the count of items in the table but not when I want to add position in to the equation.
SELECT ff.film_id, COUNT(ff.film_id) AS cnt, SUM(ff.order) AS rank FROM
`favourite_film` AS ff GROUP BY ff.film_id ORDER BY cnt DESC, rank ASC
I guess I need the count of all the films in the table and the sum of the order (but reversed?), my theory then goes flat!
Any help or links would be greatly appreciated. Thanks.
Depending your "business rules", I think you should find some sort of calculation to both take into account the position and the number of "votes".
Just a random guess, but why not sorting by COUNT(votes)/AVG(pos) ? For maintainability reason, you might want to factor out the ranking function:
CREATE FUNCTION ranking(average_pos REAL, vote_count INT)
RETURNS REAL
DETERMINISTIC
RETURN vote_count/average_pos;
The query is now simply:
SELECT film_id,
AVG(pos) as a, COUNT(*) as c, ranking(AVG(pos),COUNT(*)) AS rank
FROM vote GROUP BY film_id
ORDER BY ranking(AVG(pos), COUNT(*)) DESC;
Producing with your example:
+----------+------+----+----------------+
| FILM_ID | A | C | RANK |
+----------+------+----+----------------+
| 7 | 1.5 | 2 | 1.333333333333 |
| 6 | 1 | 1 | 1 |
| 8 | 2 | 1 | 0.5 |
| 5 | 3 | 1 | 0.333333333333 |
| 4 | 3 | 1 | 0.333333333333 |
+----------+------+----+----------------+
See http://sqlfiddle.com/#!2/3b1d9/1
you should have reverted the list before saving it. this way you could leave the unselected movies out of the rating.
a workaround might be:
Count the amount of lists SELECT COUNT(DISTINCT(user_id) save this as $AMOUNT_OF_LISTS
now count the points using
SELECT film_id, (SUM(order)+($AMOUNT_OF_LISTS-COUNT(DISTINCT(user_id)))*POINTS_FOR_NOT_IN_LIST) as points FROM table GROUP BY film_id
logic: sum up all points and add POINTS_FOR_NOT_IN_LIST points for every time not in a list (total amount of lists - amount of times movie is in the list)
insert a value POINTS_FOR_NOT_IN_LIST to your liking. (might be 26 or 27 or even lower)
you probably want to add ORDER BY points DESC LIMIT 10 to the query to get 10 highest points
SELECT MIN( `order` ) , COUNT( * ) AS cnt, `film_id`
FROM `favourite_film`
GROUP BY `film_id`
ORDER BY cnt DESC , `order`
I would do this, I would assign a higher value to the movies with the higher ranking. Then I would sum the values per movie and order by the total descending to get the overall ranking. This way you are giving weight to both the popularity and rankings of each movie.
So if you wanted to do it by the top 3 ranked movies per user you could do this:
SELECT film_id, SUM(3 -- The max number of ranked movies per user
- order -- the ranking
+ 1) total_score
FROM TABLE_NAME
GROUP BY film_id
ORDER BY total_score DESC;
Obviously you could remove the comments
This way the top rated movie would get the higher score, the next highest, the next highest score, etc. If you were counting the top 10 movies per user, just change the 3 to 10.

Mysql Group Data By Time

Updated Question:
Here is the data
m_to m_from m_id m_time
5 5 1 1374769716
5 5 2 1374771178
5 5 3 1374771294
5 5 4 1374771396
5 5 5 1374771784
1 5 6 1374772120
1 5 7 1374773097
5 1 8 1374773579
5 1 9 1374774095
5 1 10 1374774148
1 5 11 1374777304
444 5 12 1374779752
5 444 13 1374780378
5 5 14 1374781374
5 5 15 1374832375
444 5 16 1374837258
5 444 17 1374837525
5 444 18 1374838801
444 5 19 1374838976
1 5 20 1374842736
5 5 21 1374842954
444 5 22 1374843389
5 5 23 1374843466
1 5 24 1374843853
1 5 25 1374848855
444 5 26 1374848889
5 5 27 1374848912
1 5 28 1374849001
5 5 29 1374849056
444 5 30 1374850406
First coulmn is "m_to" second is m_from and third is m_id and fourht is m_time
Now what I want is, I wanna group by m_from and order by m_time. ut new message which ever wwill be added should be on top and the next row should be on second......etc
I have used.
SELECT m_from,m_time FROM messages WHERE m_to='5' GROUP BY m_from ORDER BY m_time DESC
but is resuting in something like this
444
1
5
so, its not correctly sorting data..
If you're grouping by one(or more) column then you have to do something to all the non-grouped columns in order for your query to make sense.
You have to say what you want done with all the grouped values. Usually something like SUM(), AVG(), MIN(), MAX(), GROUP_CONCAT()
If you're grouping by m_from, then you won't be able to sort by m_time, as all the records for m_from will be grouped together, and for the non-grouped values you will get an arbitrary answer, since you didn't specify what to do with the group.
You probably want to use an aggregate function, such as MAX(m_time) to get the highest value for m_time, and then sort on that.
I'd suggest something like.
SELECT MAX(m_id),m_from, MAX(m_time) as latest FROM messages
WHERE m_to='XXX' OR m_from='XXX'
GROUP BY m_from
ORDER BY latest DESC;
This seems to be an issue stemming from the SELECT * and GROUP BY. MySQL allows this to happen, but it can cause some issues.
MySQL extends the use of GROUP BY so that the select list can refer to nonaggregated columns not named in the GROUP BY clause. This means that the preceding query is legal in MySQL. You can use this feature to get better performance by avoiding unnecessary column sorting and grouping. However, this is useful primarily when all values in each nonaggregated column not named in the GROUP BY are the same for each group. The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate. Furthermore, the selection of values from each group cannot be influenced by adding an ORDER BY clause. Sorting of the result set occurs after values have been chosen, and ORDER BY does not affect which values within each group the server chooses.
As far as getting the data you want, I think this will work for you:
SELECT * FROM `messages` ORDER BY m_from ASC, m_time DESC
If you want it sorted by time first, just move m_from ASC to the end
EDIT
Given your updated question, this should limit the columns to what you want:
SELECT m_from, m_time FROM `messages` ORDER BY m_from ASC, m_time DESC
You can get the m_from that correspond to the last message to appear at the top of the list by doing something like this :
SELECT m_from, MAX(m_time) AS m_time
FROM messages
GROUP BY m_from
ORDER BY m_time DESC
but hard to say without knowing what is the output that you want...
EDIT :
Hope this one will work :
SELECT m_user, MAX(m_id) as m_id, MAX(m_time) AS m_time
FROM (
SELECT m_from AS m_user, MAX(m_id) as m_id, MAX(m_time) AS m_time
FROM messages
WHERE m_to = 5
GROUP BY m_from
UNION
SELECT m_to AS m_user, MAX(m_id) as m_id, MAX(m_time) AS m_time
FROM messages
WHERE m_from = 5
GROUP BY m_to
) AS result
GROUP BY m_user
ORDER BY m_time DESC

Categories