SQL PHP Select columns with several conditions in same query - php

I can't figure out how to make a selection of the matches between 2 teams even if is at home or away.
Example:
I have this table:
MatchID | status | date | short (home) | opponent (Away)
1 ENDED XXX TEAM A TEAM B
2 ENDED XXX TEAM B TEAM A
3 ENDED XXX TEAM C TEAM B
4 ENDED XXX TEAM D TEAM A
I have a lot of matches and I want to make a module where I can show all previous matches between team A and team B. (even if is at home or away).
Right now this is my code, but is only showing 1 match of 2 possible matches.
$ergebnis = safe_query("SELECT * FROM table WHERE status='ENDED' AND ((opponent = '".$opp_match."' AND short = '".$short_match."') OR (opponent = '".$short_match."' AND short = '".$opp_match."')) ORDER BY date LIMIT 0,5");
And I want to limit 0,5. Just want the last 5 matches between the 2 teams.
"opp_match" and "short_match" are connections to the other module. When I'm check the match I can check home team and away team with those.
With or without the limits I can't show more than one result.
I just want to show matchID 1 and 2. But right now I'm just getting matchID 1.
EDIT: I tried another way but I'm loading all ended matches.
$ergebnis = safe_query("SELECT * FROM ".PREFIX."upcoming WHERE status='ENDED'");
$i=1;
while($ds=mysql_fetch_array($ergebnis)) {
if($ds['short']==$short_match AND $ds['opponent']==$opp_match) {
eval ("\$matches = \"".gettemplate("matches")."\";");
echo $matches;
}
elseif($ds['opponent']==$short_match AND $ds['short']==$opp_match) {
eval ("\$matches = \"".gettemplate("matches")."\";");
echo $matches;
}
else echo '';
$i++;
}

Will this work?
SELECT *
FROM table
WHERE status = "ENDED"
AND
(
(opponent = "team1" AND short = "team2")
OR
(opponent = "team2" AND short = "team1")
)
ORDER BY MatchID DESC
LIMIT 5;
This assumes that if one match has a smaller ID than another, it has been played before the other.

Related

Very slow mysql request + php

The ideia is: select all professions from a table. After this count how many professionals have the profession id in his category column. The category column store the professions id's separeted by commas (1, 2, 3, 420). The professions table has 604 rows.
I have the following piece of code:
<?php
$select_professions = mysql_query("SELECT * FROM professions");
if(mysql_num_rows($select_professions) == "0"){
echo"No registers in DB";
}else{while($row_professions = mysql_fetch_assoc($select_professions)){
$id = $row_professions['id'];
$count_profiles = mysql_query("SELECT
COUNT(FIND_IN_SET(professions.id, professional.category) > 0) AS profile_numbers
FROM
professions
INNER JOIN
professional
WHERE
FIND_IN_SET(professions.id,professional.category) > 0
AND
professions.id = $id
GROUP BY
professions.id");
$reg_profiles = mysql_fetch_assoc($count_profiles);
$numProfiles = $reg_profiles['profile_numbers'];
if($numProfiles > 4){
$style = 'display:none';
}else{
$style = '';
}
?>
My basic question is WHY this is so slow in Google Chrome?
Its taking like 15 seconds to load entire page with these results in a html table. In Edge or Firefox is taking about 5 seconds. I heard about Chrome using so much memory lately but I don't believe its soo slowly. In time this is the first time I use the FIND_IN_SET function on mysql. Is that may are slowing down the request? Anyone knows what I'm doing wrong or how can be optimized? This is actualy working but we know that 15 seconds of waiting makes the user give up or think that page is not working. I have to say too that if I do the same consultation on my HeidiSQL it takes 1 second.
I recommend to normalize this:
The category column store the professions id's separeted by commas (1,
2, 3, 420)
This is an n:n relationship. Your layout:
professionals:
id | catgeory
12 | 1,2,4,50
professions
id | desc
1 | prof A
2 | prof B
...
The string operations (split the list, normalize internal, query result in to temp, ...) is very cost intensive. Better:
professionals:
id | ...
12 | ..
profrelations
pid | cid
12 | 1
12 | 2
12 | 4
12 | 50
professions
id | desc
1 | prof A
2 | prof B
...
This would skip the COUNT(FIND_IN_SET(professions.id, professional.category) > 0) as a string operation (even twice):
SELECT COUNT(cid) AS profile_numbers from professionals, profrelations where
professionals.id = profrelations.pid AND profrelations.pid = $id;
etc. You might restructure the above query like this, as long as you won't actually need any column from professions.
You can add a unique index on the cols (pid, cid) in table profrelations as one professional actually can have one profession only one times.
Remark
The different behaviour in two browser might result from the server caching the query: You're doing the query with Chrome, it's slow, but the result gets cached. Next with FF, server will respond with the cached result as its the same query again - fast. Try it three times or the other way round, should then be the same in all browsers.
At first,
this operation COUNT(FIND_IN_SET(professions.id, professional.category) > 0) will not return result that you expected. Count in above expression will return 1 even if find_in_set returns 0.
Secondly, I wouldn't use join in this case at all. This tables have no direct relation by identifiers.
I would optimize the query as following:
SELECT COUNT(professions.id) AS profile_numbers FROM professions, professional
WHERE FIND_IN_SET(professions.id,professional.category) > 0 AND professions.id = $id
GROUP BY professions.id

sql statement to alphabetize and count

Here is the mySQL I got
id terms
1 a
2 c
3 a
4 b
5 b
6 a
7 a
8 b
9 b
10 b
I want to get an alphabetized list sorted by count as follows
terms count
a 4
b 5
c 1
What mySQL statement do I need for that?
I believe something like this will work:
SELECT terms, COUNT( id) AS count
FROM table
GROUP BY terms
ORDER BY terms DESC
Read : GROUP BY (Transact-SQL)
Groups a selected set of rows into a set of summary rows by the values of one or more columns or expressions in SQL. One row is returned for each group. Aggregate functions in the SELECT clause list provide information about each group instead of individual rows.
You just need to apply group by clause for getting result
select terms, count (id) as count from table
group by terms
order by terms
I had a very similar need for a used record store to display artists in stock alphabetically with their count in parenthesis e.g.:
Smokey Robinson and The Miracles (2) | Sonic Youth (2) | Spoon (3) | Steely Dan (1) | Stevie Wonder (2) | Sufjan Stevens (1) |
Note that I used SELECT DISTINCT when pulling from my table "records". Here are the relevant code snippets:
//QUERY
$arttool = mysql_query("SELECT DISTINCT * FROM records GROUP BY artist ORDER BY artist ASC");
//OUTPUT LOOP START
while($row = mysql_fetch_array($arttool)){
//CAPTURE ARTIST IN CURRENT LOOP POSITION
$current=$row['Artist'];
//CAPTURING THE NUMBER OF ALBUMS IN STOCK BY CURRENT ARTIST
$artcount = mysql_num_rows(mysql_query("SELECT * FROM records WHERE artist = '$current'"));
//ECHO OUT.
echo $current . "($artcount)";
The actual code in my site is more complicated, but this is the bare bones of it. Hope that helps...

PHP/MySQL - Ranking based on last db column

I’ve two tables (MySQL): player and scores. In scores table are stored annual scores in this way:
player_id | 2002 | 2003 | 2004
1 | 5 | 6 | 4
2 | 3 | 2 | 5
Etc.
I write the follow code to make a ranking based on last year scores.
$extract = mysql_query("SELECT * FROM players AS p, scores AS s WHERE p.player_id =s.player_id ORDER BY s.2004 desc");
while ($row = mysql_fetch_assoc($extract)) {
$name = $row['name'];
$score = $row['2004'];
if ($row['2004'] < $row['2003']) {
$value = "-";
}
else if ($row['2004'] > $row['2003']) {
$value = "+";
}
else if ($row['2004'] == $row['2003']) {
$value = "=";
}
echo "<b>".$name."</b> | ".$score." ".$value."<br>\n";
}
But this code has two big problems:
1) In the query I have to specify the last year (ORDER BY s.2004), so if I add another column (eg. 2005) into scores table, I have to manually change the code.
2) Same thing for the “$value” var. If I add 2005, the comparison between 2004 and 2003 becomes wrong (it should be between 2005 and 2004).
I know I have to use loops and array but... how?
You should redesign your scores table to store player_id, score and year in one row. So, each score gets its own row. When you find yourself duplicating columns, you are usually heading in the wrong direction.
Then, your query would look like:
Select Year(CURDATE());
select *
from players p
inner join scores s on p.player_id = s.player_id
where s.`Year` = Year(CURDATE()) --or (select max(Year) from Score)

Counting rows in MySQL (highscore)

I've created a game with a highscore table in MySQL.
I have a "My scores" button that needs to retrieve the users scores, e.g.:
10. John 395
42. John 340
90. John 10
How should I go out retrieving the rank (10th, 42th, 90th) of each score of the user?
I could pull all the scores from the database and iterate through them but that doesn't seem like a good solution.
Let me try to expand:
I retrieve all MY scores from the database. E.g. 10 scores. I want to display these 10 scores however I won't know what the rank of these scores is compared to the other scores in my database! (10th, 16th, etc) ..Hope that makes more sense...
Thanks
For the position in the total list you either need to build up a list every time you want this overview, or use a stored procedure to build a list for a given moment. You could 'cache' a list on a given interval. Or maybe update a list when some one played a game that would change the top 100.
As #WhiteElephant suggested, you'd be making the table every time you want the data.
#stefandoorn suggest to not use the optimized count of sql, i think this is not efficient enough for these kind of computations.
A simple SQL query would do it for you. For example, if you want the 10th score, you could use:
SELECT name, score FROM highscores ORDER BY score DESC LIMIT 1 OFFSET 9
The offset will always be the position required - 1.
If you want to have the associated rank as a column beside the score, you could do the following:
SELECT #rownum:=#rownum+1 position, name, score FROM (SELECT #rownum:=0) r, highscores ORDER BY score DESC
This doesn't work with an offset (the position number will always start at 1). The result would be something like the following:
+----------+-------------+-------+
| position | name | score |
+----------+-------------+-------+
| 1 | Player 1 | 27681 |
| 2 | Player 2 | 14982 |
+----------+-------------+-------+
But I think the best solution is to just loop through the returned values with an index and use the index to keep track of the position.
SELECT
id, name, score,(select count(*) FROM highscores AS higherscores WHERE higherscores.score>currentscores.score)+1 AS rank
FROM
highscores AS currentscores
WHERE name="john"
;
Just use ORDER BYscoreDESC in the end of your query to sort them in reversed order (from high to low). When iterating and showing it in PHP you can use a count:
Query e.g.: SELECT * FROM scores ORDER BY score DESC
$count = 1;
$sql = 'SELECT * FROM scores ORDER BY score DESC';
$result = mysql_query($sql) or die(mysql_error());
while($fetch = mysql_fetch_object($result)) {
echo $count . ' ' . $fetch->score . '<br />';
$count++;
}

MySQL Result - "Group By" removing incorrect duplicates

Will do my best to describe the problem Im having :)
Each thread/topic in my forum represents one disc. Registered members of the forum use a series of checkboxes (one displayed next to each disc) to tick each disc that they have in their collection. When the form is $_POST'ed it stores the information in a table like so:
| user_id - disc_id |
+--------------------+
| 2 - 571 |
| 2 - 603 |
| 2 - 4532 |
When the user next views the forum I have the checkboxes ticked and disabled on discs that the user owns. This is done using:
$sql = 'SELECT id, poster, subject, posted, last_post, last_post_id,
last_poster, num_views, num_replies, closed, sticky, moved_to, topicimage,
c.user_id, c.disc_id FROM topics LEFT JOIN collections AS c ON c.disc_id=id
WHERE forum_id='.$id.' ORDER BY sticky DESC;
The above grabs all of the discs, which I then display using the following (stripped down) code:
$result = $db->query($sql) or error('Unable to fetch topic list '.$sql.'', __FILE__, __LINE__, $db->error());
// If there are topics in this forum
if ($db->num_rows($result))
{
while ($cur_topic = $db->fetch_assoc($result))
{
// If logged in users ID matches the current discs user_id (i.e if this user owns this disc)
if ($cur_topic['user_id']==$pun_user['id']) {
$read = ' I own this!';
} else {
$read = ' I own this!';
}
}
}
This works great, until a second user adds the same disc ID to his collection, eg:
| user_id - disc_id |
+--------------------+
| 2 - 571 |
| 2 - 603 |
| 6 - 571 |
This causes a duplicate thread to appear in the forum. One is correctly ticked (because I own it), the other is not ticked, though it shares all of the same information such as topic id and image.
My first thought was to try adding GROUP BY c.disc_id to the SQL, which does successfully remove the duplicate topic - However, it is removing the wrong one. The disc that I have ticked is no longer shown, leaving only the unticked version.
Hope that makes sense. Can anyone offer any insight or ideas?
Many Thanks.
This is a guess, since I don't know your schema, but I don't see you specifying the user's ID in your WHERE clause.
What about something like the following?
SELECT t.id, t.poster, t.subject, t.posted, t.last_post, t.last_post_id,
t.last_poster, t.num_views, t.num_replies, t.closed, t.sticky,
t.moved_to, t.topicimage, c.user_id, c.disc_id
FROM topics AS t LEFT JOIN collections AS c ON c.disc_id = t.id
WHERE forum_id = '.$id.'
AND c.user_id = '.$user_id.'
ORDER BY t.sticky DESC;
Also, you're joining on Topic ID = Disc ID. Is that intentional?
I can see two easy way for solving this:
first:
with two query, you group query and a second to fetch all the disc_id owned by the user
second:
with your first query:
if ($db->num_rows($result)) {
$array = Array();
while ($cur_topic = $db->fetch_assoc($result)) {
$id = $cur_topic['disc_id'];
if (!array_key_exists ($id, $array)) { // allow only result per disc_id
$array[$id] = $cur_topic;
$array[$id]['owned'] = false;
}
// If logged in users ID matches the current discs user_id (i.e if this user owns this disc)
if ($cur_topic['user_id']==$pun_user['id']) // check if one is owned by the user
$array['owned'] = true;
}
foreach ($array as $cur_topic) {
if ($cur_topic['owned']) {
$read = '<br /><input type="checkbox" disabled="disabled" checked="checked" /> <span style="color:#999">I own this!</span>';
} else {
$read = '<br /><input type="checkbox" name="discs[]" value="'.$cur_topic['id'].'" /> I own this!';
}
}
}

Categories