【问题标题】:Recognizing duplicates while iterating through query results在遍历查询结果时识别重复项
【发布时间】:2012-06-15 14:25:14
【问题描述】:

这是question I asked previously 的后续行动。

我可以很好地计算排名(包括平局的逻辑);当我遇到重复排名的第一个实例时,问题是检测未来的重复

这是获取结果集的 SQL 查询:

SELECT
    s1.team_id,
    sum(s1.score>s2.score) wins
FROM scoreboard s1
    LEFT JOIN scoreboard s2
        ON s1.year=s2.year
        AND s1.week=s2.week
        AND s1.playoffs=s2.playoffs
        AND s1.game_id=s2.game_id
        AND s1.location<>s2.location
GROUP BY s1.team_id
ORDER BY wins DESC;

这是我将在 PHP 中循环遍历的示例 SQL 结果集:

team_id   wins
--------------
10        52
2         48
5         46
11        46
3         42
9         39
...

这是我用于显示的 PHP 代码,它需要在所有绑定的行列上附加“T-”:

$i = 0;
while($row = mysql_fetch_assoc($r)) { //iterate thru ordered (desc) SQL results
    ++$i;
    ($row['wins'] == $prev_val)
        ? $rnk = 'T-' . $rnk    //same as previous score, indicate tie
        : $rnk = $i;            //not same as previous score
    $rnk = str_replace('T-T-','T-',$rnk); //eliminate duplicative tie indicator
    if ($row['team_id'] == $team_id) { //current team in resultset matches team in question, set team's rank
        $arr_ranks['tp']['cat'] = 'Total Wins';
        $arr_ranks['tp']['actual'] = number_format($row['wins'],1);
        $arr_ranks['tp']['league_rank'] = $rnk;
        $arr_ranks['tp']['div_rank'] = $div_rnk;
    }
    else if ($i == 1) { //current team is category leader (rank=1) and is not team in question, set current team as leader
        $arr_ranks['tp']['leader'] = "<a href='index.php?view=franchise&team_id=" . $row['team_id'] . "'>" . get_team_name($row['team_id']) . '</a> (' . number_format($row['wins']) . ')';
    }
    $prev_val = $row['wins']; //set current score as previous score for next iteration of loop
}

上面的“平局”逻辑会将第 4 队视为与第 3 队平局,但反之则不然

换句话说,对于团队 #3,$rnk = 3,而对于团队 #4,$rnk = T-3。 (两者应该都是“T-3”。)

所以问题变成了:我如何在遍历结果时“向前看”以找出当前分数是否与列表后面的分数相同/重复,因此我可以将其与后续的欺骗?

@Airzooka 给了我a potential solution,但我很想知道是否有更有效的方法来做到这一点(甚至可能在 SQL 级别)。

谢谢。

【问题讨论】:

  • 为什么不在一个循环中一次性读取所有点列表,然后在下一个循环中使用 array_search 检查重复项?

标签: php mysql ranking


【解决方案1】:

在伪代码中:

loop through rows as row1
    loop through rows as row2
        if row1 ain't row2 and row1.points == row2.points, append T    

更新:

好的,这个怎么样,因为你是按wins来排序你的结果集,无论如何:尝试将每一行的信息存储在一个临时数组或变量中,比如$previousTeamWins$previousTeamName 等。然后您可以比较当前和上一个,并据此分配 T。因此,您实际上将分配延迟到下一次迭代(或者在最后一行的情况下直到循环退出)。遍历行集,应该可以完成工作。

【讨论】:

  • 见上面我的 cmets。我必须通过查询计算值;它们没有预先填充在现成的表格中。
  • 很好——这个伪代码告诉你当你有一行信息时该怎么做。我假设您已经了解 PHP 中的循环,因此实现起来应该很简单。
  • 我认为 [Airzooka 提供的解决方案](stackoverflow.com/questions/10855462/detect-future-duplicate-values-while-iterating-through-mysql-results-in-php) 将是比循环两次结果更有效。我很想知道是否有比那个更有效的方法,无论是否直接通过 SQL。
  • His 的效率稍高一些,是的,但只有在存在平局时——如果没有平局,您仍然有效地循环两次结果。
  • 那么您会说没有一种有效的方法可以在 SQL 级别提前检测到关系吗?
【解决方案2】:

这个怎么样?

SELECT
 t1.*,
 EXISTS (
  SELECT *
  FROM `teams` as t2
  WHERE t2.pts = t1.pts AND t1.id != t2.id
 ) as `tied`
 FROM `teams` as t1
...

【讨论】:

  • 谢谢,但这只有在结果存储在表格中时才有效,而我的不是。我在上面的一个编辑中添加了我的查询,所以你可以看到我实际上必须计算我然后检查的值是骗子。
  • 您的结果不在表格中?或许您应该删除巨大的标题:这是获取结果集的 SQL 查询:
  • @BrianWarshaw 我正在检查重复的值(“wins”)不在表中。如您所见,我必须通过比较分数来动态计算它。
【解决方案3】:

试试这个,希望对你有用

SELECT t1.`id`,t1.`pts`,t1.`team_id`,
IF(t1.`pts` = t2.`pts` AND t1.`id` != t2.`id` ,1,0) AS `tied`
FROM `teams` t1
LEFT JOIN `teams` t2 on t2.`pts` = t1.`pts` AND t2.`id` != t1.`id`
GROUP bY t1.`id`

【讨论】:

  • 谢谢,但我相信我在上面对@Matmarbon 所做的评论也适用于这里......
【解决方案4】:

哎,还在看你的代码。所以说到底,你只想输出一两个队,对吧?如果领导者是相关团队,则为一个,否则为两个。如果是这种情况,请尝试这样的事情(警告它未经测试):

$i = 0;
while($row = mysql_fetch_assoc($r)) { //iterate thru ordered (desc) SQL results 
    ++$i; 
    ($row['wins'] == $prev_wins) 
        ? $rnk = $prev_rnk    //same as previous score, indicate tie 
        : $rnk = $i;            //not same as previous score 
    $rnk = str_replace('T-T-','T-',$rnk); //eliminate duplicative tie indicator 

    if ($prev_team_id == $team_id) {
        $arr_ranks['tp']['cat'] = 'Total Wins'; 
        $arr_ranks['tp']['actual'] = number_format($prev_wins,1); 
        $arr_ranks['tp']['league_rank'] = $prev_rnk; 
        $arr_ranks['tp']['div_rank'] = $div_rnk;

        if ($row['wins'] == $prev_wins)
        {
            $arr_ranks['tp']['tie'] = true;
        }
        else
        {
            $arr_ranks['tp']['tie'] = false;
        }

    break;
    }
    else if ($i == 1) { //current team is category leader (rank=1) and is not team in question, set current team as leader 
        $arr_ranks['tp']['leader'] = "<a href='index.php?view=franchise&team_id=" . $row['team_id'] . "'>" . get_team_name($row['team_id']) . '</a> (' . number_format($row['wins']) . ')'; 
    }

    $prev_wins = $row['wins'];
    $prev_team_id = $row['team_id'];
    $prev_rnk = $rnk;
}

if ($prev_team_id == $team_id) {
    $arr_ranks['tp']['cat'] = 'Total Wins'; 
    $arr_ranks['tp']['actual'] = number_format($prev_wins,1); 
    $arr_ranks['tp']['league_rank'] = $prev_rnk; 
    $arr_ranks['tp']['div_rank'] = $div_rnk;

    if ($row['wins'] == $prev_wins)
    {
        $arr_ranks['tp']['tie'] = true;
    }
    else
    {
        $arr_ranks['tp']['tie'] = false;
    }

}

【讨论】:

  • 实际上,每页的输出是针对单个团队的。输出是类别、实际价值、排名(如果有问题的团队与另一个团队并列,希望包括“T-”)和联赛领袖。
【解决方案5】:

我想我通过 SQL 找到了解决方案!可能不优雅(我可以稍后清理),但这里......

查询:

SELECT a.team_id, a.wins, count(*) instances
FROM
    (SELECT
        s1.team_id,
        sum(s1.score>s2.score) wins
    FROM scoreboard s1
        LEFT JOIN scoreboard s2
            ON s1.year=s2.year
            AND s1.week=s2.week
            AND s1.playoffs=s2.playoffs
            AND s1.game_id=s2.game_id
            AND s1.location<>s2.location
    GROUP BY s1.team_id) AS a
    LEFT JOIN
        (SELECT
            sum(s1.score>s2.score) wins
        FROM scoreboard s1
            LEFT JOIN scoreboard s2
                ON s1.year=s2.year
                AND s1.week=s2.week
                AND s1.playoffs=s2.playoffs
                AND s1.game_id=s2.game_id
                AND s1.location<>s2.location
        GROUP BY s1.team_id) AS b
            ON a.wins = b.wins
GROUP BY a.team_id, b.wins
ORDER BY a.wins DESC;

这给出了输出...

=================================
|team_id   | wins    |instances |
=================================
|10        | 44      |1         |
|2         | 42      |3         | //tie
|9         | 42      |3         | //tie
|5         | 42      |3         | //tie
|3         | 41      |1         |
|11        | 40      |1         |
|...       |         |          |
=================================

然后,在 PHP 中,我将能够通过检查 $row['instances'] &gt; 1 的时间来检测所有关系。

感谢大家在这个异常繁琐的问题上与我相处!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-16
    • 2011-12-02
    • 1970-01-01
    • 2021-10-22
    • 2015-05-09
    • 1970-01-01
    • 1970-01-01
    • 2012-08-22
    相关资源
    最近更新 更多