mysql - 获取最接近正确值的值,根据结果将零返回到多个

时间:2015-06-26 08:13:54

标签: php mysql sql

我的网站允许用户猜测体育比赛的结果。在比赛结束时,应将猜测与实际结果进行比较。获胜者是具有最接近正确猜测的成员

我正在寻找一种方法来返回所有猜到正确结果和得分差异的成员如果没有(零)成员猜对了那些猜到最接近的成员正确的结果

See MYSQL FIDLE EXAMPLE

我修改了脚本以更改固定值,使用变量,如下所示

if(isset($_POST['resultBtn'])){
    foreach($_POST['winner'] as $id =>$winner){
        $winScore = $_POST['score'][$id];
        :
        :


$sql="SELECT p.*
        FROM Multiple_Picks p
        WHERE p.event_id='$matchId' AND 
        p.pick='$winner' AND
        abs(p.score-'$winScore') = (SELECT min(abs(p2.score-1))
                        FROM Multiple_Picks p2
                        Where p2.pick=p.pick AND
                        p2.event_id = p.event_id)";

我的问题是如果我在下表中运行此脚本:

enter image description here

即使我把结果完全正确,也会显示NOTHING:

我的变量值在sql语句中是正确的,所以这不是问题

欢迎任何帮助......

重要事项选择最严格结果的用户,对于所有游戏,在圆桌会议期间是胜利者

示例:如果用户A赢得了4个选秀权而用户B赢得了5个选秀权,那么用户B就是该轮次的赢家

5 个答案:

答案 0 :(得分:2)

为什么不想要

SELECT p.*, abs(p.score-'$winScore') as diff
        FROM Multiple_Picks p
        WHERE p.event_id='$matchId' AND p.pick='$winner'
        ORDER BY diff ASC 
        LIMIT 1

这将返回该事件的最近成员。如果您需要其中一些,请移除LIMIT

此外,永远不要将您的参数直接放入SQL查询,即使是受信任的(不是您的情况),即使您确定它们将始终是整数或非字符串类型。使用准备好的陈述。

答案 1 :(得分:1)

  

方案1:没有用户选择正确的队伍

我相信这种情况的结果应该是空洞的,因为每个人都犯了一个错误。

  

分数回归成员选择最接近的分数和分数   RESULT

除了select中的一个错误外,它似乎已经在您的代码示例中工作了。

 abs(p.score-'$winScore') = (SELECT min(abs(p2.score-1))

而不是常量1(一),它应该是变量'$winScore'

并且为了控制您获得的用户数量,您可能会限制结果,因此您将获得以下内容:

$sql="SELECT p.*
        FROM Multiple_Picks p
        WHERE p.event_id='$matchId' AND 
        p.pick='$winner' AND
        abs(p.score-'$winScore') = (SELECT min(abs(p2.score-'$winner'))
                        FROM Multiple_Picks p2
                        Where p2.pick=p.pick AND
                        p2.event_id = p.event_id)
order by p.id limit '$numberOfMembers'";
  

情景2:场景2:多个用户选择了正确的团队但是   分数是不同的返回用户(S)谁认为最接近正确   SCORE

与上一个问题相同。

  

情景3:多个用户选择了正确的队伍并且分数全部返回   选择正确的团队和分数的用户

您可以使用相同的查询来实现这一点,只需将LIMIT替换为'rank'功能,如果您将获得几个最接近的分数,但您必须根据他们的投票顺序限制他们的数字,为此我建议排序。 所以最终的查询将是:

$sql="select * from (SELECT p.*, 
         abs(p.score-'$winScore') scr_diff,
         @rownum := @rownum + 1 rank
        FROM Multiple_Picks p,
            (SELECT @rownum := 0) rank_gen
        WHERE p.event_id='$matchId' AND 
        p.pick='$winner' AND
        abs(p.score-'$winScore') = (SELECT min(abs(p2.score-'$winner'))
                        FROM Multiple_Picks p2
                        Where p2.pick=p.pick AND
                        p2.event_id = p.event_id)
order by p.id
  ) sq
 where sq.scr_diff = 0
    or sq.rank < '$numberOfMembers'";

Fiddle.

答案 2 :(得分:1)

一场比赛的最佳猜测

首先找到选出获胜者且得分最接近的成员:

SELECT  p.*
    FROM  
      ( SELECT  MIN(ABS(score-'$winScore')) AS closest
            FROM  Multiple_Picks
            WHERE  event_id = '$matchId'
              AND  pick='$winner' 
      ) AS c
    JOIN  Multiple_Picks p
    WHERE  p.event_id = '$matchId'
      AND  p.pick = '$winner'
      AND  ABS(score-'$winScore') = c.closest 

如果返回没有结果,那会发生什么? (这是因为没有人选择特定赛事的获胜者。)

但是,我认为你的问题要复杂得多。但是,上面给出了一个映射(event_id,pick) - &gt; “赢了”的成员名单。重新开始...

缺少信息

有一个谜 - 事件结果来自哪里?我将假设此表已填充:

CREATE TABLE Win (
    event_id ...,   -- which game
    winnner ...,    -- who won
    score ...       -- by what score
)

最佳猜测

因此,创建一个BestGuessers表(event_id,member)。 “所有游戏”和“圆形”的细节有点模糊。所以我将至少向前迈进一步。

CREATE TEMPORARY TABLE BestGuessers(
    event_id ...,
    member_nr ...   -- who guessed the best for that event
)
SELECT  p.event_id, p.member_nr
    FROM  
      ( SELECT  w.event_id, w.winner, MIN(ABS(mp.score-w.score)) AS closest
            FROM  Multiple_Picks AS mp
            JOIN  Win AS w ON mp.event_id = w.event_id
              AND  mp.pick = w.winner
            GROUP BY  w.event_id, w.winner 
      ) AS c
    JOIN  Multiple_Picks p
         ON  p.event_id = c.event_id
        AND  p.pick = c.pick
        AND  p.score = c.closest 

现在,从那里,你可以选择最好的猜测者。

SELECT  y.member_nr
    FROM  
      ( SELECT  COUNT(*) AS ct
            FROM  BestGuessers
            GROUP BY  member_nr
            ORDER BY  COUNT(*) DESC
            LIMIT  1 
      ) AS x   -- the max number of correct guesses
    STRAIGHT_JOIN  
      ( SELECT  member_nr, COUNT(*) AS ct
            FROM  BestGuessers
            GROUP BY  member_nr
      ) AS y   -- the users who guessed correctly that many times
     USING (ct);

这一切都非常复杂;我可能有一些拼写错误,甚至逻辑错误。但也许我接近了。

答案 3 :(得分:1)

似乎存储实际结果的附加表在这里会有所帮助。 例如,这是在一个名为results的表中,其示例值如下:

event_id  winner     result
1         Crusaders  16
2         Waratahs   15
3         Chiefs      4
4         Crusaders  17
5         Reds       12
0         Rebels     14
7         Cheetahs   15
8         Crusaders  14

然后可以对每一行进行JOIN,并将结果进行比较,如下所示:

SELECT p.*
     , CASE WHEN ABS(p.score - r.result)
                 - CASE WHEN p.pick = r.winner THEN 999999 ELSE 0 END
                 = (SELECT MIN(ABS(p2.score - r2.result)
                               - CASE WHEN p2.pick = r2.winner THEN 999999 ELSE 0 END)
                    FROM picks p2
                    JOIN results r2
                    ON p2.event_id = r2.event_id
                    WHERE p2.event_id = p.event_id)
            THEN 1
            ELSE 0
            END AS win
FROM picks p
JOIN results r
ON p.event_id = r.event_id;

<强>解释

如果成员计算赢得或抽取事件,则最右边的win列为1,否则为0.使用的方法类似于帖子中的方法,主要区别在于团队和得分相结合。这里要解释的主要内容是999999,当选择正确的球队时会减去 - 所以这可以肯定会超过分数差异。 (当然,如果需要,可以选择更大的值。)

<强>演示

SQL Fiddle Demo

答案 4 :(得分:1)

在这个答案中,我称之为&#34; Best&#34;选择为特定比赛选择了正确赢家的任何选秀权,并且得分与实际比赛得分最接近。

这些脚本也尊重不同的轮次&#34;在比赛中,因为这是一个重要的复杂因素。

这个答案分为两部分:首先是一个类似于问题中的一个查询,该查询返回所有&#34; Best&#34;挑选特定的比赛。为了更容易在SQL Fiddle中运行,我使用了MySQL变量而不是PHP变量。

包含测试数据的架构:

create table Multiple_Picks (
  pick_id int,
  member_nr int,
  event_id int,
  pick varchar(100),
  score int
  );

insert into Multiple_Picks 
values
(11,100,1,'Crusaders',15),
(12,100,2,'Waratahs',10),
(13,100,3,'Chiefs',4),

(21,200,1,'Crusaders',15),
(22,200,2,'Waratahs',10),
(23,200,3,'Lions',4),

(31,300,1,'Crusaders',15),
(32,300,2,'Waratahs',12),
(33,300,3,'Lions',6),

(41,100,4,'Crusaders',20),
(42,100,5,'Waratahs',20),
(43,100,6,'Lions',20)
;

查询以显示所有选择,然后显示特定匹配的最佳选择:

set @matchId = 2;
set @winner = 'Waratahs';
set @winScore = 8;

-- Show all picks for a particular match
select * from Multiple_Picks
where event_id = @matchId;

-- Show best picks for a particular match
select p.*
from Multiple_Picks p
where p.event_id = @matchId
and p.pick = @winner
and abs(p.score - @winScore) = 
  (select min(abs(other.score - @winScore)) 
   from Multiple_Picks other
   where other.event_id = @matchId
   and other.pick = @winner
  )
;

SQL Fiddle to show picks for particular match

-- Show all picks for a particular match
+---------+-----------+----------+----------+-------+
| pick_id | member_nr | event_id |   pick   | score |
+---------+-----------+----------+----------+-------+
|      12 |       100 |        2 | Waratahs |    10 |
|      22 |       200 |        2 | Waratahs |    10 |
|      32 |       300 |        2 | Waratahs |    12 |
+---------+-----------+----------+----------+-------+

-- Show best picks for a particular match
+---------+-----------+----------+----------+-------+
| pick_id | member_nr | event_id |   pick   | score |
+---------+-----------+----------+----------+-------+
|      12 |       100 |        2 | Waratahs |    10 |
|      22 |       200 |        2 | Waratahs |    10 |
+---------+-----------+----------+----------+-------+

现在我们需要努力寻找每一轮比赛的胜利者。

首先,我们有额外的测试数据,其中包含第1轮和第2轮中匹配的实际分数。

create table Matches (
  event_id int,
  winner varchar(100),
  score int,
  round int
  );

insert into Matches 
values
(1,'Crusaders',10,1),
(2,'Waratahs',11,1),
(3,'Lions',4,1),

(4,'Crusaders',20,2),
(5,'Waratahs',20,2),
(6,'Chiefs',20,2)
;

现在为所有比赛选择最佳选秀权。子选择(别名为m)计算每次匹配的best_diff,作为实际得分与每个猜测得分之间的最小差异。然后将此子选择加入到每个选择中,以便只有&#34; Best&#34;选秀权归还。

-- Show all best picks for all Matches
select p.*, m.round
from Multiple_Picks p
join (
  select m2.event_id, m2.winner, m2.score, m2.round, 
         min(abs(m2.score-p2.score)) as best_diff
  from Matches m2
  join Multiple_Picks p2
  on p2.event_id = m2.event_id and p2.pick = m2.winner
  group by m2.event_id, m2.winner, m2.score, m2.round
) as m
on p.event_id = m.event_id and p.pick = m.winner 
   and abs(m.score - p.score) = m.best_diff
order by m.round, p.event_id
;

通过将之前的查询按成员组合并轮次分组,可以轻松获得每轮每位玩家的最佳选择次数:

-- Show a count of best picks for each player for each round
select p.member_nr, m.round, count(*) as best_count
from Multiple_Picks p
join (
  select m2.event_id, m2.winner, m2.score, m2.round, 
         min(abs(m2.score-p2.score)) as best_diff
  from Matches m2
  join Multiple_Picks p2
  on p2.event_id = m2.event_id and p2.pick = m2.winner
  group by m2.event_id, m2.winner, m2.score, m2.round
) as m
on p.event_id = m.event_id and p.pick = m.winner 
   and abs(m.score - p.score) = m.best_diff
group by p.member_nr, m.round
order by m.round, count(*) desc
;

SQL Fiddle for all best picks and counts for all matches

-- Show all best picks for all Matches
+---------+-----------+----------+-----------+-------+-------+
| pick_id | member_nr | event_id |   pick    | score | round |
+---------+-----------+----------+-----------+-------+-------+
|      31 |       300 |        1 | Crusaders |    15 |     1 |
|      21 |       200 |        1 | Crusaders |    15 |     1 |
|      11 |       100 |        1 | Crusaders |    15 |     1 |
|      12 |       100 |        2 | Waratahs  |    10 |     1 |
|      32 |       300 |        2 | Waratahs  |    12 |     1 |
|      22 |       200 |        2 | Waratahs  |    10 |     1 |
|      23 |       200 |        3 | Lions     |     4 |     1 |
|      41 |       100 |        4 | Crusaders |    20 |     2 |
|      42 |       100 |        5 | Waratahs  |    20 |     2 |
+---------+-----------+----------+-----------+-------+-------+

-- Show a count of best picks for each player for each round
+-----------+-------+------------+
| member_nr | round | best_count |
+-----------+-------+------------+
|       200 |     1 |          3 |
|       300 |     1 |          2 |
|       100 |     1 |          2 |
|       100 |     2 |          2 |
+-----------+-------+------------+

最后阶段是仅选择那些拥有最多最佳选秀权的每轮选手。我尝试修改上面的查询,但嵌套变得令人困惑,所以我的解决方案是创建一些逻辑视图,以便更容易理解最终查询。这些视图基本上封装了我上面解释过的查询的逻辑:

create view MatchesWithBestDiff as
select m.event_id, m.winner, m.score, m.round, 
       min(abs(m.score-p.score)) as best_diff
from Matches m 
join Multiple_Picks p
on p.event_id = m.event_id and p.pick = m.winner
group by m.event_id, m.winner, m.score, m.round
;

create view BestPicks as
select p.*, m.round
from Multiple_Picks p
join MatchesWithBestDiff m
on p.event_id = m.event_id and p.pick = m.winner 
   and abs(m.score - p.score) = m.best_diff
;

create view BestPickCount as
select member_nr, round, count(*) as best_count
from BestPicks
group by member_nr, round
;

因此,显示每轮获胜者的查询只是:

-- Show the players with the highest number of Best Picks for each round
select *
from BestPickCount p
where best_count = 
(
    select max(other.best_count)
    from BestPickCount other
    where other.round = p.round
)
order by round
;

SQL Fiddle for players with most Best picks for each round

-- Show the players with the highest number of Best Picks for each round
+-----------+-------+------------+
| member_nr | round | best_count |
+-----------+-------+------------+
|       200 |     1 |          3 |
|       100 |     2 |          2 |
+-----------+-------+------------+

整个调查提醒我,如果需要根据最大值和总和选择记录,可以让SQL进行大量操作是多么棘手。使用窗口函数(OVER和PARTITION BY子句)可以更容易地进行某些类型的查询,但它们在MySQL中不可用。

在设计上述查询时,我发现了一些有趣的限制: MySQL不允许在视图定义中加入子查询。 ANSI SQL不允许子查询中的聚合引用内部查询中的列和外部查询中的列。 MySQL似乎有时会允许这样做,但我无法找到关于何时允许的明确指导,所以我选择编写上述查询来避免这个&#34;功能&#34;。