First off all I am slightly confused what the best implemtentation would be for the following problem i.e pure can it be done with only mysql without altering tables or would I need a combination of PHP and mysql as I am currently doing.
Please keep that in mind as you read on:
Question Info
A Pickem game works as follow:
1- Display all matches / fixtures in a round for a tournament.
2- User enters which teams he thinks will win each fixture.
The fixtures are pulled from a table schedule and the users results are recorded in a table picks
Keep In mind
Each round can have a number of matches (anywhere between 1 to 30+ matches)
What I am trying todo / PROBLEM
I am trying to calculate how many users selected team1 to win and how many users selected team2 to win for a given round in a tournament.
Example
Manchester United: 7 users picked |
Arsenal 3: users picked
MYSQL TABLES
schedule table Schedule of upcoming games
picks table User Picks are recorded in this table
Expected Output From Above Tables After Calculations
So for Super Rugby Round 1 it should read as follow:
gameID 1 4 picks recorded, 2 users selected Jaquares 1 user Selected Stormers (ignore draw fro now)
gameID 2 4 picks recorded, 4 users selected Sharks, 0 users selected Lions
My Code
function calcStats($tournament, $week)
{
global $db;
//GET ALL GAMES IN TOURNAMENT ROUND
$sql = 'SELECT * FROMpicks
WHERE picks.tournament = :tournament AND picks.weekNum = :weekNum ORDER BY gameID';
$stmnt = $db->prepare($sql);
$stmnt->bindValue(':tournament', $tournament);
$stmnt->bindValue(':weekNum', $week);
$stmnt->execute();
if ($stmnt->rowCount() > 0) {
$picks = $stmnt->fetchAll();
return $picks;
}
return false;
}
test.php
$picks = calcStats('Super Rugby', '1');
foreach($picks as $index=> $pick) {
if($pick['gameID'] !== $newGameID){
?>
<h1><?php echo $pick['gameID']?></h1>
<?php
//reset counter on new match
$team1 = 0;
$team2 = 0;
}
if($pick['picked'] === $newPick){
//gameID is passed as arrayKey to map array index to game ID
//team name
$team1[$pick['picked']];
//number times selected
$team1Selections[$pick['gameID']] = $team1++;
}
else if($pick['picked'] !== $newPick){
///gameID is passed as arrayKey to map array index to game ID
//team name
$team2[$pick['picked']];
$team2Selections[$pick['gameID']] = $team2++;
}
$newPick = $pick['picked'];
$newGameID = $pick['gameID'];
}
PRINT_R() Of function $picks = calcStats('Super Rugby', '1')
I hoe my question makes sense, if you need any additional information please comment below, thank you for taking the time to read.
It seems that you're doing too much within PHP that can be easily done within MySQL; consider the following query:
SELECT gameID, team, COUNT(*) AS number_of_picks
FROM picks
WHERE picks.tournament = :tournament AND picks.weekNum = :weekNum
GROUP BY gameID, team
ORDER BY gameID, team
This will give the following results, given your example:
1 | Jaquares | 2
1 | Stormers | 1
1 | Draw | 1
2 | Sharks | 4
Then, within PHP, you perform grouping on the game:
$result = array();
foreach ($stmnt->fetchAll() as $row) {
$result[$row['gameID']][] = $row;
}
return $result;
Your array will then contain something like:
[
'1' => [
[
'gameID' => 1,
'team' => 'Jaquares',
'number_of_picks' => 2,
],
'gameID' => 1,
'team' => 'Stormers',
'number_of_picks' => 1,
],
...
Related
I am trying to make a function where the following should happen:
Retrieve the ID value of all users in database.
Retrieve all numbers belonging to each user from an other table in the same database.
Add all the numbers belonging to each user together.
By using my code (see below), step 1 and 3 is working. At step 2, it is looping the correct amount of times but in every loop it retrieves the numbers belonging to the first ID from step 1.
Example:
Step 1 finds the following IDs: 1, 2, 3 and 4.
Step 2 loops 4 times, but retrieves the numbers belonging to ID 1 every time instead of retrieving the numbers to ID 1 in the first loop, ID 2 in the second etc.
My PHP:
$users_get = mysqli_query($conn,"SELECT id FROM users");
$users_num = mysqli_num_rows($users_get);
$users_list = array();
while($users_row = mysqli_fetch_array($users_get)){
$users_list[] = $users_row;
}
foreach($users_list as $users_row){
$users_items[] = array(
'id' => $users_row['id']
);
}
for($loop1 = 0; $loop1 < $users_num; $loop1++){
$numbers_get = mysqli_query($conn,"SELECT number FROM users_numbers WHERE userid = '".$users_items[$loop1]['id']."'");
$numbers_num = mysqli_num_rows($numbers_get);
$numbers_list = array();
while($numbers_row = mysqli_fetch_array($numbers_get)){
$numbers_list[] = $numbers_row;
}
foreach($numbers_list as $numbers_row){
$numbers_items[] = array(
'number' => $numbers_row['number']
);
}
$numbers_added = 0;
for($loop2 = 0; $loop2 < $numbers_num; $loop2++){
$numbers_added = $numbers_added + $numbers_items[$loop2]['number'];
}
}
I later added som echos to display the IDs and numbers that is retrieved and got the following result:
User ID: 1
Amount of numbers: 4
Numbers:
4 (Belonging to ID 1)
7 (Belonging to ID 1)
5 (Belonging to ID 1)
2 (Belonging to ID 1)
Total: 18
User ID: 2
Amount of numbers: 0
User ID: 3
Amount of numbers: 3
Numbers:
4 (Belonging to ID 1)
7 (Belonging to ID 1)
5 (Belonging to ID 1)
Total: 16
The amount of numbers for ID 3 is correct, however the 3 retrieved numbers belongs to ID 1.
Another observation I made was if I edit the SELECT query inside loop 1:
"SELECT number FROM users_numbers WHERE userid = '".$users_items[$loop1]['id']."'"
And manually selects an ID, example:
"SELECT number FROM users_numbers WHERE userid = '3'"
Then it retrieves the correct numbers belonging to ID 3.
After hours of trying to figure out what I'm doing wrong I still haven't found anything, so any help is really appreciated! Is there something I can do with my current code to fix it, or maybe there is some other ways to achieve the desired function?
Based on the comments on my question, I ended up with the following code:
$users_get = mysqli_query($conn,"SELECT a.id, SUM(b.number) AS number FROM users AS a INNER JOIN users_numbers AS b ON a.id = b.userid GROUP BY a.id ASC");
$loop1 = 0;
while($users_items[] = mysqli_fetch_array($users_get){
echo "ID: ".$users_items[$loop1]['id']." - Num total: ".$users_items[$loop1]['number']."<br />";
$loop1++;
}
The echo inside the while is only for testing purposes. When I run this, it displays a nice list with all the user IDs and the sum of each users numbers.
I've been banging my head hard over this problem for the last 2-3 days trying to see the problem from as many different angles as possible but to no avail. I'm turning to the SO community for extra perspectives. Below is the code I have which prints all 9 product plans. I'm wanting to find and print the plan with pricing equals or closest to a given user input. How can I do this?
//arrays of productnames
$productnames=array(1=>"Beginner","Advanced","Expert");
//arrays of productlevels
$productlevels=array(1=>"Bronze","Silver","Gold");
//Get The Length of Product Name Array
$planname_array_length=count($productnames);
//Get The Length of Product Level Array
$planlevel_array_length=count($productlevels);
for ($prn=1; $prn <= $planname_array_length; $prn++) {//loop to create plan name indicators
for ($prl=1; $prl <= $planlevel_array_length; $prl++) {//loop to create plan level indicators
$getpoductsql = " SELECT name, level,productNameId,productLevelId,finalProductPrice
FROM (
SELECT wspn.productName AS name, wspl.productLevel AS level, wsp.productNameId AS productNameId, wsp.productPlanLevel AS productLevelId,
ROUND(SUM(`Price`) * 1.12) AS finalProductPrice,
FROM `products` ws
left join product_plan wsp on wsp.productId = ws.wsid
left join product_plan_level wspl on wsp.productPlanLevel = wspl.wsplid
left join product_plan_name wspn on wspn.wspnid = wsp.productNameId
WHERE wspn.productName = '$planname_array_length[$pn]' AND wspl.productLevel = '$planlevel_array_length[$pl]'
)
AS x ORDER BY ABS(finalProductPrice - $compareprice)"
$resultproducts = $conn->query($getpoductsql);
$prodArray = mysqli_fetch_array($resultproducts);
//print array of each plan
$resultArr = array('planNameID' => $prodArray['planNameId'],
'planName' => $prodArray['name'],
'planLevelID' => $prodArray['planLevelId'],
'planLevelName' => $prodArray['level'],
'planPrice' => $prodArray['finalProductPrice'];
//print arrays of products
echo json_encode($resultArr);
}
}
This will output 9 plans as follow :
{"planNameID":"1","productName":"Beginner","productLevelID":"1","productLevelName":"Bronze","productPrice":"15"}
Rather than performing a separate query for each product name and product level, do them all in one query, and let MySQL find the one with the closest price.
$getpoductsql = " SELECT name, level,productNameId,productLevelId,finalProductPrice
FROM (
SELECT wspn.productName AS name, wspl.productLevel AS level, wsp.productNameId AS productNameId, wsp.productPlanLevel AS productLevelId,
ROUND(SUM(`Price`) * 1.12) AS finalProductPrice,
FROM `products` ws
left join product_plan wsp on wsp.productId = ws.wsid
left join product_plan_level wspl on wsp.productPlanLevel = wspl.wsplid
left join product_plan_name wspn on wspn.wspnid = wsp.productNameId
WHERE wspn.productName IN ('Beginner', 'Advanced', 'Expert') AND wspl.productLevel IN ('Bronze', 'Silver', 'Gold')
GROUP BY productNameId, productLevelId
)
AS x ORDER BY ABS(finalProductPrice - $compareprice)"
forgive my formatting, I'm on mobile
Like Amr Berag said above, your result should be the first row returned from your query.
If you have a table like this:
ID value
---- ------
A 7
B 12
C 23
...
You can then SELECT from this table to find the closest to some value, like so:
(Assume your desired value is $VALUE)
SELECT id, value, ABS(value - $VALUE) AS diff
FROM your_table
ORDER BY diff ASC
This will return something like this (say $VALUE is 10):
id value diff
-- ------ ----
B 12 2
A 7 3
C 23 13
...
You can just pick the first row.
You may also be able to add a WHERE clause to only select the row with the least difference using the MIN function:
SELECT id, value, ABS(value - $VALUE) AS diff
FROM your_table
WHERE diff = MIN(diff)
The way you are doing it will produce invalid json, do it like this:
$result=array();
for ($prn=1; $prn <= $planname_array_length; $prn++) {
for ($prl=1; $prl <= $planlevel_array_length; $prl++) {
. . . // the other code
//print array of each plan
$resultArr = array('planNameID' => $prodArray['planNameId'],
'planName' => $prodArray['name'], 'planLevelID' => $prodArray['planLevelId'],
'planLevelName' => $prodArray['level'],
'planPrice' => $prodArray['finalProductPrice'];
//print arrays of products
$resul[]=$resultArr;
}//loop1
}//loop2
echo json_encode($result);
you should also add the limit 1 and do the rest in JS in the front end
I have a table called "car_owners", it has three columns known as:
id owner cars
1 Greg 1
2 Gary 3
3 Aaron 2
4 Farb 3
5 REX 1
6 Fred 2
In the following code I get it into array and print it:
$exc = $conn->prepare("SELECT name,state from current_state");
$exc->execute();
while($finalResult = $exc->fetch(PDO::FETCH_ASSOC))
{
$tables[] = $finalResult;
}
var_dump($tables);
once i get this into an array, is there a way i could sort it in a custom order where i could get the out put like follows,
first the owners with 2 cars, then with 1 car and who has 3
owner cars
Aaron 2
Fred 2
Greg 1
REX 1
Farb 3
Gary 3
P.S doing it from the table is not going to work, because im using a loop above the code which makes it impossible to do it from the SQL, can anybody tell me a way to do it from the php
select * from your_table
order by case when cars = 2 then 1
when cars = 1 then 2
when cars = 3 then 3
else 4
end
You can use usort to sort the values. This will also sort by name if two owners have the same number of cars. I have changed the SELECT statement to match the given database definition.
$exc = $conn->prepare("SELECT owner, cars from current_state");
$exc->execute();
while ($finalResult = $exc->fetch(PDO::FETCH_ASSOC))
{
$tables[] = $finalResult;
}
usort(
$tables,
function($a, $b) {
// If same number of cars, sort by name
if ($a['cars'] == $b['cars']) return strcmp($a['owner'], $b['owner']);
// If owner a has two cars, place before b
if ($a['cars'] == 2) return -1;
// If owner b has two cars, place below a
if ($b['cars'] == 2) return 1;
// Neither owner a nor owner b has two cars, sort by number of cars
return ($a['cars'] < $b['cars']) ? -1 : 1;
}
);
foreach ($tables as $row) {
echo $row['owner'], ' => ', $row['cars'], PHP_EOL;
}
Output:
Aaron => 2
Fred => 2
Greg => 1
REX => 1
Farb => 3
Gary => 3
If you have the array prepared from the mysql table, then you can use the following code-
$car_array=array(
"Aaron"=>2,
"Fred"=>2,
"Greg"=>1,
"REX"=>1,
"Farb"=>3,
"Gary"=>3,
);
$sort_array=array("2","1","3");
$new_array=array();
foreach ($sort_array as $key => $value)
{
foreach ($car_array as $key1 => $value1)
{
if ($value1 == $value )
$new_array[$key1]=$value1;
}
}
print_r($new_array);
Consider sorting the resultset through sql itself. The sql provided by #juergen would meet the purpose. The only change I would like to do in the query is that 'add owner field in the order by clause'. Consider the below code snippet
select * from car_owners
order by (case when cars = 2 then 1
when cars = 1 then 2
when cars = 3 then 3
else 4
end), owner
This should meet the purpose and give you the resultset exactly as you needed.
Also, if you explicitly need to sort it through php then you use the php usort() function and sort the array writing a custom defined function.
Using PHP only, you can use uksort function to sort the array using a user-defined comparison function. The following code requires a copy of your $tables variable.
<?php
$tables2=$tables;
uksort($tables2, function($r1, $r2) use ($tables) {
return ($tables[$r1]["cars"]%3) < ($tables[$r2]["cars"]%3);
});
print_r($tables2);
Ok, so I have some MySQL tables as follows:
Buildings
Building-ID Building-Name
===========----=============
1 Building-1
2 Building-2
3 Building-3
4 Building-4
Building-1
Mroom State
=====----======
1 Booked
2 Empty
3 Empty
4 Empty
Building-2
Mroom State
=====----======
1 Booked
2 Empty
3 Empty
4 Empty
And a query in PHP as follows (Ignore the hard coded while, I've simplified the code a bit):
$sql = "select * from Buildings";
$result = mysql_query ($sql) or die(mysql_error());
while ($row = mysql_fetch_array($result))
{
$building[] = $row['ward_name'];
}
$v1 = 0;
while ($v1 < 4)
{
$sql = "SELECT COUNT(*) FROM `$building[$v1]` WHERE state = 'Empty'";
$result = mysql_query($sql) or die(mysql_error());
$count = mysql_result($result, 00);
var_dump($count[$v1]);
$v1 = $v1 + 1;
}
To my way of thinking this should create an array of the buildings contained in the "Buildings" table, start a loop, load the building name from the array and provide a row count for the table of how many rows contain "Empty" in the state column. What it actually does is provide a count for the first table and then provides "NULL" for the rest.
I'd appreciate any help you can give me.
Cheers!
What about changing your data model?
Table buldings can be kept as is:
Buildings
Building-ID Building-Name
===========----=============
1 Building-1
2 Building-2
3 Building-3
4 Building-4
New table:
Rooms
Building-ID Mroom State
===========-=====-=====
1 1 1
1 2 0
2 1 0
State 0 = Empty, State 1 = Booked
Then use a join with group by:
select count(*) from buildings b inner join rooms r on r.bid = b.id where r.state = 0 group by b.id;
Then you will get a row for each building with the count of empty rooms. You won't need a table for each building.
This does noit make sense:
$count = mysql_result($result, 00);
var_dump($count[$v1]);
you mean to write:
$count[$v1] = mysql_result($result, 00);
var_dump($count[$v1]);
Also do not use several tables with names matching columns of other tables.
You can use one table with a primary key that spans two columns instead, for example create primary key on($buildingid,$roomid)
so that the table has columns $buildingid,$roomid, and $state.
mysql_result() returns a string, not an array.
Modify the code and check that now it works as expected.
var_dump($count);
I'm having a problem in getting an array of a users ratings. The scenario is, I have a function that compares two arrays of numbers, and calculates how similar they are using cosine similarity.
I want to use this, to calculate the similarity of ratings from one user, to x number of other users in the database, finding the user with the most similar ratings.
The two tables relevant to this are films and ratings. Rows relevant for Film are filmID, and ratings has rows filmID, userID, and rating. for example:
filmId userID rating
1 1 3
1 3 4
2 1 2
3 1 2
2 3 3
So for user 1, I'd want an array $user1[3, 2, 2] and for user 3 $user3[4, 3, 0]
Notice that in the array for user 3, the film they HAVEN'T rated is now a zero. These arrays will then be passed to the function to calculate similarity.
I don't know how to get the user arrays from the tables I have. I wrote some code, but am fairly stumped. So far I have:
$users = mysql_query("SELECT * FROM user");
$ratings = mysql_query("SELECT * FROM ratings");
while ($userRow = mysql_fetch_assoc($users)) {
$similarCheck = mysql_query("SELECT * FROM ratings WHERE userID =".$userRow['userID']);
$similarArray = mysql_fetch_assoc($similarCheck);
$count = 0;
while ($similarArray = mysql_fetch_assoc($similarCheck)){
$count++;
}
for ($i=0; $i < $count; $i++){
$user1 = array();
$user1[$i] = $similarArray['rating'];
}
}
Thanks for any help I do receive. If you require any further information, please let me know.
You're not actually doing anything with your query:
while ($similarArray = mysql_fetch_assoc($similarCheck)){
$count++;
}
This code simply loops through the query results and assigns each row to a variable, which is then overwritten over and over. When the loop exits, you'll have a FALSE value assigned to $similarArray, since mysql_fetch calls return a boolean false when there's no more results.
You then try to use this boolean false value in ANOTHER loop as an array which will throw all sorts of warnings.
Most likely you want something like this:
$similarCheck = mysql_query("SELECT * FROM ratings WHERE userID =".$userRow['userID']) or die(mysql_error());
$similarArray = array();
while($row = mysql_fetch_assoc($similarcheck)) {
$similarArray[] = $row['rating'];
}