簡體   English   中英

mysql - 獲取最接近正確值的值,根據結果將零返回到多個

[英]mysql - get closest value to correct value return zero to many depending on result

我的網站允許用戶猜測體育比賽的結果。 在比賽結束時,應將猜測與實際結果進行比較。 獲勝者是具有最接近正確猜測的成員

我正在尋找一種方法來返回所有猜測正確結果和得分差異的成員如果沒有(零)成員猜對了那些猜測最接近正確結果的成員

請參閱MYSQL FIDLE示例

我修改了腳本以更改固定值,如下所示

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)";

我的問題是如果我在下表中運行此腳本:

在此輸入圖像描述

即使我把結果完全正確,NOTHING也會顯示:

我的變量值在sql語句中是正確的,所以這不是問題

任何幫助將受到歡迎......

重要的是,選擇最嚴格的結果的用戶,對於所有游戲,在圓圈期間是贏家

例如:如果用戶A贏得了4個選擇而用戶B贏得了5個選擇,那么用戶B就是該輪的贏家

你為什么不想要

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:沒有用戶選擇正確的團隊

我相信這種情況的結果應該是空洞的,因為每個人都犯了一個錯誤。

分數回歸成員選擇最接近的分數和結果

它似乎已經在您的代碼示例中工作,除了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)認為最接近正確的分數

與上一個問題相同。

場景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'";

小提琴。

一場比賽的最佳猜測

首先找到選擇獲勝者並且得分最接近的成員:

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) - >“贏了”的成員列表。 重新來...

缺少信息

有一個謎 - 事件結果來自哪里? 我將假設此表已填充:

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);

這一切都非常復雜; 我可能有一些拼寫錯誤,甚至邏輯錯誤。 但也許我走近了。

似乎存儲實際結果的附加表在這里會有所幫助。 例如,假設這是一個名為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小提琴演示

在這個答案中,我稱之為“最佳”選擇任何為特定比賽選擇了正確贏家的選秀權,並且與實際比賽得分的得分最接近。

這些腳本也尊重競爭中的不同“輪次”,因為這是一個重要的復雜因素。

這個答案分為兩部分:首先是一個類似於問題中的查詢,該查詢返回特定匹配的所有“最佳”選擇。 為了更容易在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顯示特定匹配的選擇

-- 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,作為實際得分與每個猜測得分之間的最小差異。 然后將此子選擇連接到每個選擇,以便僅返回“最佳”選擇。

-- 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
;

通過將之前的查詢按member_nr和round分組,可以輕松獲得每輪每位玩家的最佳選擇數:

-- 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小提琴,適用於所有比賽的所有最佳選秀和計數

-- 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適用於每輪最佳選秀權的玩家

-- 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似乎有時允許這樣做,但我無法找到關於何時允許的明確指導,所以我選擇編寫上述查詢以避免這個“功能”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM