Fixture generator in PHP or MySQL - php

I am trying to generate fixtures for a sports website. I have a table called Members, with relevant columns being member_id and league_id. The league_id will be passed from a form on the previous page as the variable $leagueid.
I'm pulling out all the member ID's relating to that league ID using...
$result = mysql_query("SELECT member_id FROM Members WHERE league_id = '$leagueid'")
I now need to generate fixtures for all these member ID's and then insert that data into the MySQL table 'Fixtures'. Each row of data in that table needs to include:-
player1 - member_id of the first player
player2 - member_id of the second player
week - integer showing which week the match will be played
league_id
However, there are some special conditions that also need to be applied.
Every 3rd week needs to remain free (i.e. weeks 3,6,9,12 etc). No matches can be scheduled on these weeks
There needs to be an option (which will be selected and passed from a form on the previous page as a checkbox variable called $double) which will double up the matches. This means that after generating one complete round of fixtures, you need to take the generated list, swap ID's for players 1 and 2, and duplicate them all. So 1 round of fixtures could look like this....
Week 1
1 vs 2
3 vs 4
Week 2
1 vs 3
2 vs 4
Week 3
1 vs 4
2 vs 3
Then you would swap the ID's and add on another set...
Week 4
2 vs 1
4 vs 3
Week 5
3 vs 1
4 vs 2
Week 6
4 vs 1
3 vs 2
What I'm looking for is some code that will generate all these fixtures while keeping in mind all the special conditions that I've listed.
I know this is all possible in PHP but I also think I can do it using one SQL query instead, which might be a lot cleaner. Can anyone help me out?? Thanks!!
P.S. I know I'm using mysql and not mysqli. I am currently trying to transfer over to mysqli but I'm having some problems which I have posted on a separate question that I have yet to get a correct answer to.

SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
SELECT * FROM ints WHERE MOD(i,3) > 0;
+---+
| i |
+---+
| 1 |
| 2 |
| 4 |
| 5 |
| 7 |
| 8 |
+---+
The second part is simply
INSERT INTO my_table SELECT week_id+3, column_2, column_1 FROM my_table;

Related

Remove duplicated records in sphinx without doing setGroupBy?

Hey I am new to sphinx search.
In my query I retrieve course_ids. All the courses belong to a theme_id, but some of them can belong to more than 1 theme, so some of them are duplicated.
I set limits to my query to display results from 1-20, then 21-40... So 20 by 20.
But sometimes in those 20 results there are duplicated results, so for example if from 21 from 40 there are 3 duplicated results I want to remove them and then fill the 3 empty spaces with the next 3 results, so the query returns instead 21-43. Then 44-64...
I tried setGroupBy(), and it worked, but I don't want the courses to be sorted by course_id but with setSortMode(), so the course_ids are again duplicated.
How can I remove the duplicated records and keep the sorting?
Any help would be appreciated. Thanks
setGroupBy has a third and option argument, to specify the final sort order.
So can group by (for example) course_ids but still do the final sorting by weight (or whatever), rather than the default '#group desc'.
$client->setSortOrder( SPH_SORT_RELEVANCE );
$client->setGroupBy( 'course_id', SPH_GROUPBY_ATTR, "#weight desc" );
Still use setSortOrder, which determins WHICH of the rows from the course, is kept. Ie show the highest rank one first, which mimicks overall sorting of weight.
Looks like what you are looking for is exactly what REMOVE_REPEATS() does. Not sure it's available in the programming language clients. You'll probably need to use SphinxQL instead which is anyway recommended as the clients are outdated and miss a lot of functionality.
Here's an example:
Without REMOVE_REPEATS():
MySQL [(none)]> select * from testrt;
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
| 2 | 10 |
| 3 | 20 |
| 4 | 30 |
| 5 | 30 |
+------+------+
5 rows in set (0.04 sec)
With REMOVE_REPEATS() by gid:
MySQL [(none)]> select remove_repeats((select * from testrt), gid, 0,10);
+------+------+
| id | gid |
+------+------+
| 1 | 10 |
| 3 | 20 |
| 4 | 30 |
+------+------+
3 rows in set (0.06 sec)

Search for a string in an array through SQL [duplicate]

This question already has answers here:
MySQL query finding values in a comma separated string
(11 answers)
Closed 6 years ago.
I have a table named 'offers' that has a column in_stores. It contains the ids of the stores that this offer is available in. Graphically this table looks like this:
id | title | in_stores
1 | Shoes | 1002,1003
2 | Gloves | 1020,1011
3 | Shades | 1002,1009
4 | Hats | 1010,1002
5 | Shoes | 1220
6 | Shirts | 1010
7 | Hats | 1002
Each value in in_stores is saved with the implode() function through PHP.
My question:
How to select in a single mysqli query all the offers that are available in a store with id 1002. In this example the query should return offers with id 1,3,4,7. I guess I should use something like explode() first to get the results in an array and than in_array() to search for the specific id in it but all those functions are unavailable within SQL.
This is a major issue with storing comma separated fields.
MySQL does have a function to allow searching for these, and this will be a lot more reliable than trying to rely on using LIKE. But as it still cannot effectively use any index it will not be fast.
SELECT *
FROM offers
WHERE FIND_IN_SET('1002', in_stores)
Far better to redesign your database to use an extra table with a row for each value for each id.
You "could" do it with a LIKE Query, but this is not recommended.
SELECT * FROM offers WHERE in_stores LIKE "%1002%".
As long as you don't have values bigger than 9999 this will work.
BUT when one of your stores has the id 11002 of 99991002 it will also return these unwanted values.
What you should do is transform your mysql table to a have a second table storeLocations or sth. else. This should only have the properties offer_id and store_id.
It will transform your data to:
`offers`
id | title
1 | Shoes
2 | Gloves
3 | Shades
4 | Hats
5 | Shoes
6 | Shirts
7 | Hats
`storeLocations`
offer_id, store_id
1 | 1002
1 | 1003
2 | 1020
2 | 1011
3 | 1002
3 | 1009
4 | 1010
4 | 1002
5 | 1220
6 | 1010
7 | 1002
Then you can select from it like
SELECT * FROM offers AS o
LEFT JOIN storeLocations as l ON (o.id=l.offer_id)
WHERE l.store_id = 1002;
Now when you insert data you don't have to use implode but insert as many rows into storeLocations as there are store_id's for that specific item.
For more info on that topic have a look here.
I think you should be using the MySQL LIKE operator. It searches the database column for strings specified in your query.
Try this query:
$sql = "SELECT * FROM offers WHERE in_store LIKE '%1002%'";
Check this link for more explanation: W3Schools - SQL LIKE Operator
I think that should do the trick.

Calculations after Summing values in Drupal views with module aggregation plus

In Drupal 7, I use the module views aggregation plus.
There are 2 columns (A and B) which I apply a group aggregation of 'Average' and 'Sum' respectively. I want to have a 3rd column (C) which does a math expression (A - B) after the grouping. How can I achieve this? An example below
Before grouping
ID | Column A | Column B | Column C
1 | 5 | 10 | -5
1 | 5 | 10 | -5
2 | 5 | 10 | -5
What I get currently
ID | Column A | Column B | Column C
1 | 5 | 20 | -10
2 | 5 | 10 | -5
What I want to get
ID | Column A | Column B | Column C
1 | 5 | 20 | -15
2 | 5 | 10 | -5
I tried retrieving the values of the summed field using devel module, and while I get this: $...['#views_contextual_links_info']['views_ui']['view']->style_plugin->rendered_fields[2]['expression_1']
I tried outputting that using Views PHP but it doesn't return back the correct value. I believe it is only returning back the value prior to being summed by the views aggregator plus.
You can add the field: Global: Math expression.
It allows you to enter mathematical expressions such as 2 + 2 or sqrt(5).
As it supports Replacement Patterns of the fields you added before, you can easily enter [field_column_A]-[field_column_B]

Generate and Insert the five digit random numbers using mysql [duplicate]

This question already has answers here:
mysql unique number generation
(9 answers)
Closed 8 years ago.
I am wondering if there is any way to generate the random five digit number and insert into database using mysql. I know i can do it using PHP but wanted to know if i can get rid of the php and do it using database. Also, the generated number should be different than the numbers already stored in the database.
Following is example as how it should look like:
I have four letters of pattern common in random_no field which is org1 and want to append other 5 random letters as shown in following example:
+-------+-----------+-----------+--------------------------------------------+
| id | title | phone | ABN | Random No |
+-------+-----------+----------+---------------------------------------------
| 1 | title1 | 4765 5678 | 214-444-1234 | org123456 |
| 2 | title2 | 4444 4444 | 555-111-1234 | org109876 |
| 3 | title3 | 3333 3333 | 214-222-1234 | org187654 |
| 4 | title4 | 1111 1111 | 817-333-1234 | org156432 |
| 5 | title5 | 2222 2222 | 214-555-1234 | org177654 |
+-------+-----------+-----------+--------------------------------------------
Any help will be appreciated.
Now there is no guarentee that there are not going to be duplicates... but this is getting two random numbers and multiplying them by different numbers so its not all that likely that they will be getting random numbers
UPDATE table t,
( SELECT id, LPAD(FLOOR(7 + (RAND() * 50) * (RAND() * 333)), 5, 0) as join_num
FROM table
)t1
SET t.random_no = CONCAT(t.random_no, t1.join_num)
WHERE t.id = t1.id;
From here I recommend you do this.. after updating your table go back through and run this query
SELECT id FROM table
GROUP BY random_no
HAVING COUNT(*) > 1;
if there are any results returned then the id's there will need a different random number and you can just change it at any duplicate spots once you know if there are any dupes
Breakdown of the update query....
update the table alias t.
select from table the id and then the random number alias t1.
concat the number and the column by row..
where the id's are equal... getting a different number for each row.
LPAD is a zero fill so that way if the number is smaller than 5 spaces it'll fill it in with 0's and then you have to use FLOOR() with RAND() for the random number.
Hope thats helpful!

MySQL: GROUP BY within ranges

I have a table with scores like this:
score | user
-------------------
2 | Mark
4 | Alex
3 | John
2 | Elliot
10 | Joe
5 | Dude
The table is gigantic in reality and the real scores goes from 1 to 25.
I need this:
range | counts
-------------------
1-2 | 2
3-4 | 2
5-6 | 1
7-8 | 0
9-10 | 1
I've found some MySQL solutions but they seemed to be pretty complex some of them even suggested UNION but performance is very important. As mentioned, the table is huge.
So I thought why don't you simply have a query like this:
SELECT COUNT(*) as counts FROM score_table GROUP BY score
I get this:
score | counts
-------------------
1 | 0
2 | 2
3 | 1
4 | 1
5 | 1
6 | 0
7 | 0
8 | 0
9 | 0
10 | 1
And then with PHP, sum the count of scores of the specific ranges?
Is this even worse for performance or is there a simple solution that I am missing?
Or you could probaly even make a JavaScript solution...
Your solution:
SELECT score, COUNT(*) as counts
FROM score_table
GROUP BY score
ORDER BY score;
However, this will not returns values of 0 for count. Assuming you have examples for all scores, then the full list of scores is not an issue. You just won't get counts of zero.
You can do what you want with something like:
select (case when score between 1 and 2 then '1-2'
when score between 3 and 4 then '3-4'
. . .
end) as scorerange, count(*) as count
from score_table
group by scorerange
order by min(score);
There is no reason to do additional processing in php. This type of query is quite typical for SQL.
EDIT:
According to the MySQL documentation, you can use a column alias in the group by. Here is the exact quote:
An alias can be used in a query select list to give a column a
different name. You can use the alias in GROUP BY, ORDER BY, or HAVING
clauses to refer to the column:
SELECT
SUM(
CASE
WHEN score between 1 and 2
THEN ...
Honestly, I can't tell you if this is faster than passing "SELECT COUNT(*) as counts FROM score_table GROUP BY score" into PHP and letting PHP handle it...but it add a level of flexibility to your setup. Create a three column table as 'group_ID', 'score','range'. insert values into it to get your groupings right
1,1,1-2
1,2,1-2
1,3,3-4
1,4,3-4
etc...
Join to it on score, group by range. THe addition of the 'group_ID' allows you to set groups...maybe have group 1 break it into groups of two, and let a group_ID = 2 be a 5 set range (or whatever you might want).
I find the table use like this is decently fast, requires little code changing, and can readily be added to if you require additional groupings or if the groupings change (if you do the groupings in code, the entire case section needs to be redone to change the groupings slightly).
How about this:
select concat((score + (1 * (score mod 2)))-1,'-',(score + (1 * (score mod 2)))) as score, count(*) from TBL1 group by (score + (1 * (score mod 2)))
You can see it working in this fiddle: http://sqlfiddle.com/#!2/215839/6
For the input
score | user
-------------------
2 | Mark
4 | Alex
3 | John
2 | Elliot
10 | Joe
5 | Dude
It generates this:
range | counts
-------------------
1-2 | 2
3-4 | 2
5-6 | 1
9-10 | 1
If you want a simple solution which is very powerful, add an extra field within your table and put a value in it for the score so 1 and 2 have the value 1, 3 and 4 has 2. With that you can group by that value. Only by inserting the score you've to add an extra field. So your table looks like this:
score | user | range
--------------------------
2 | Mark | 1
4 | Alex | 2
3 | John | 2
2 | Elliot | 1
10 | Joe | 5
5 | Dude | 3
Now you can do:
select count(score),range from table group by range;
This is always faster if you've an application where selecting has prior.
By inserting do this:
$scoreRange = 2;
$range = ceil($score/$scoreRange);

Categories