SQL内部连接和限制记录

时间:2014-09-08 17:43:59

标签: php mysql

这是我的简化表结构。

我有两张桌子。

TABLE 1

       ID        PTS        PID        TID
    ----------------------------------------
        1         3          1          22
        2         10         1          22
        3         5          1          22
        4         1          2          58
        5         0          2          58
        7         0          3          47
        8         5          3          47
        15        5          4          51
        15        3          4          51
        9         7          3          6
        10        0          1          8
        11        2          1          8
        12        4          5          1
        13        1          6          9
        14        2          5          12
        15        5          4          61
        15        6          4          61
        15        2          4          61
        16        0          7          100
        ect.      ect.       ect.       ect.


TABLE 2

      NAME       PID
    -------------------
      Jhon       1
      Peter      2
      Lisa       3
      Doe        4
      Joey       5
      Mike       6
      Debby      7
      ect.       ect.

现在我需要从每个TID中选择最新的两个PTS,并将它们与表2中的白色PID行匹配,并计算平均值。

THE DESIRED OUTCOME

      NAME       AVG
    -------------------
      Jhon       4,25
      Peter      1,00
      Lisa       6,00
      Doe        4,00
      Joey       3,00
      Mike       1,00
      Debby      0,00
      ect.       ect.

澄清:PID行是关系型的。多个TID可以具有相同的PID,并且TID可以具有多个PTS。我正在使用PDO套接字。

当我的查询是:

$query = $db->prepare("SELECT IFNULL(AVG(pts), 0) AS P, TA1.PID AS TA1PID, name AS N FROM ".
                    "table1 TA1 LEFT JOIN table2 TA2 ON TA1.PID = TA2.PID ".
                    "GROUP BY name, TA2.PID ".
                    "ORDER BY TA1.id DESC");

但是这会从TID计算所有点数(PTS)。但我想只计算每个TID的两个最新点(PTS)。我整天都尝试过不同的查询,但我无法弄明白。我对SQL很陌生我设法让一个例子工作但是使用纯PHP并且它不漂亮:D

sqlFiddle: LINK

问题在于它计算平均值中的所有TID点。它只应计算每个TID的最后两个条目

我希望这是一个明确的问题。我尽力解释我的问题。如有任何问题请咨询。我已经在Stackoverflow上阅读了除了我之外的其他类似问题,但我无法修改它们以便为我工作。

2 个答案:

答案 0 :(得分:2)

您可以使用此查询

仅从第一个表中选择最近的2行
select t1.id, t1.pts, t1.pid, t1.tid
from table1 t1
join table1 t2 on t2.id >= t1.id and t1.tid = t2.tid
group by t1.id
having count(*) <= 2

并将其插入原始查询而不是表1

SELECT IFNULL(AVG(pts), 0) AS AVG, TA1.PID AS 
Table1_ID, name AS Name FROM
(
    select t1.id, t1.pts, t1.pid, t1.tid
    from table1 t1
    join table1 t2 on t2.id >= t1.id and t1.tid = t2.tid
    group by t1.id
    having count(*) <= 2
)
TA1 LEFT JOIN table2 TA2 ON TA1.PID = TA2.PID
      GROUP BY name, TA2.PID
      ORDER BY TA1.id DESC

答案 1 :(得分:1)

在大多数数据库中,每N组都很容易。只需使用ROW_NUMBER。不幸的是MySQL没有它们所以我们必须模拟它

SELECT name, 
       Avg(PTS) 
FROM
(
    SELECT *, 
                  CASE 
                    WHEN @previousPID IS NULL 
                          OR @previousTID IS NULL 
                          OR ( @previousPID = ORDERED.pid 
                          AND @previousTID = ORDERED.tid )
                          THEN @rownum := @rownum + 1 
                    ELSE @rownum := 1 
                  end rn, 
                   @previousPID := ORDERED.pid ,
                   @previousTID := ORDERED.tid
           FROM   (SELECT t2.name, 
                          t2.pid, 
                          t1.id, 
                          t1.tid ,
                          t1.Pts

                   FROM   table2 t2 
                          INNER JOIN table1 t1 
                                  ON T2.pid = t1.pid 
                   ORDER  BY t1.pid, 
                             t1.tid,
                             t1.id DESC)ORDERED, 
                  (SELECT @rownum := 0, 
                          @previousPID := NULL,
                          @previousTID := NULL) t) CTE 
WHERE  CTE.rn <= 2 
GROUP  BY name 

具有以下Results

|      NAME | AVG(PTS) |
|-----------|----------|
|       Doe |        4 |
|      Jhon |     4.25 |
|      Joey |        3 |
|      Lisa |        4 |
|      Mike |        1 |
| No points |        0 |
|     Peter |      0.5 |

DEMO

查看intermediate results可能有助于理解CASE语句如何生成rownumbers

|      NAME | PID | ID | TID | PTS | @ROWNUM := 0 | @PREVIOUSPID := NULL | @PREVIOUSTID := NULL | RN | @PREVIOUSPID := ORDERED.PID | @PREVIOUSTID := ORDERED.TID |
|-----------|-----|----|-----|-----|--------------|----------------------|----------------------|----|-----------------------------|-----------------------------|
|      Jhon |   1 |  3 |  22 |   5 |            0 |               (null) |               (null) |  1 |                           1 |                          22 |
|      Jhon |   1 |  2 |  22 |  10 |            0 |               (null) |               (null) |  2 |                           1 |                          22 |
|      Jhon |   1 |  1 |  22 |   3 |            0 |               (null) |               (null) |  3 |                           1 |                          22 |
|      Jhon |   1 | 12 |   8 |   2 |            0 |               (null) |               (null) |  1 |                           1 |                           8 |
|      Jhon |   1 | 11 |   8 |   0 |            0 |               (null) |               (null) |  2 |                           1 |                           8 |
|     Peter |   2 |  5 |  58 |   0 |            0 |               (null) |               (null) |  1 |                           2 |                          58 |
|     Peter |   2 |  4 |  58 |   1 |            0 |               (null) |               (null) |  2 |                           2 |                          58 |
|      Lisa |   3 |  7 |  47 |   5 |            0 |               (null) |               (null) |  1 |                           3 |                          47 |
|      Lisa |   3 |  6 |  47 |   0 |            0 |               (null) |               (null) |  2 |                           3 |                          47 |
|      Lisa |   3 | 10 |   6 |   7 |            0 |               (null) |               (null) |  1 |                           3 |                           6 |
|       Doe |   4 |  9 |  51 |   3 |            0 |               (null) |               (null) |  1 |                           4 |                          51 |
|       Doe |   4 |  8 |  51 |   5 |            0 |               (null) |               (null) |  2 |                           4 |                          51 |
|       Doe |   4 | 19 |  61 |   2 |            0 |               (null) |               (null) |  1 |                           4 |                          61 |
|       Doe |   4 | 17 |  61 |   6 |            0 |               (null) |               (null) |  2 |                           4 |                          61 |
|       Doe |   4 | 16 |  61 |   5 |            0 |               (null) |               (null) |  3 |                           4 |                          61 |
|      Joey |   5 | 13 |   1 |   4 |            0 |               (null) |               (null) |  1 |                           5 |                           1 |
|      Joey |   5 | 15 |  12 |   2 |            0 |               (null) |               (null) |  1 |                           5 |                          12 |
|      Mike |   6 | 14 |   9 |   1 |            0 |               (null) |               (null) |  1 |                           6 |                           9 |
| No points |   7 | 18 | 100 |   0 |            0 |               (null) |               (null) |  1 |                           7 |                         100 |