多个条目的

时间:2015-09-18 13:52:43

标签: mysql

我有一个名为POINTS的mysql表,如下所示:

userid1 | userId2 | points
---------------------------
    1   |    1    |   3
    1   |    1    |   2
    1   |    2    |   5
    2   |    1    |   4
    1   |    3    |   5

我正在尝试创建此表的视图,如下所示:

userId | gained | received | spent | current
--------------------------------------------
   1   |    5   |     4    |  10   |   -1
   2   |    0   |     5    |   4   |    1
   3   |    0   |     5    |   0   |    5

列的算法是:

  • userId,在userId1或userId2列中的POINTS表中找到的userIds的唯一值
  • 获得,在POINTS表中userId1 = userId和userId2 = userId的点数总和
  • 收到,在POINTS表中userId1!= userId和userId2 = userId的点数总和
  • 花费,在POINTS表中userId1 = userId和userId2!= userId的点数总和
  • 当前,获得+收到 - 花费

我是mysql的新手,我的问题是,如果我进入多个子查询,我不知道如何为不同的用户保存总和值。任何帮助将不胜感激

更新:示例中的数字是准确的

2 个答案:

答案 0 :(得分:3)

这是结构化查询语言的结构化部分的直接应用

您需要两个关键组件子查询才能将它们组合在一起。一个是每个用户的点gained列表。这是这样的。 (http://sqlfiddle.com/#!2/1b1884/1/0

                      SELECT userid1 AS userid,
                             SUM(points) AS gained
                        FROM points
                       WHERE userid1 = userid2
                       GROUP BY userid1

同样,您可以生成支出和接收点数(http://sqlfiddle.com/#!2/1b1884/5/0

                      SELECT userid1 AS userid,
                             SUM(points) AS spent
                        FROM points
                       WHERE userid1 != userid2
                       GROUP BY userid1

和(http://sqlfiddle.com/#!2/1b1884/7/0

                      SELECT userid2 AS userid,
                             SUM(points) AS received
                        FROM points
                       WHERE userid1 != userid2
                       GROUP BY userid2

您还需要一个子查询,它会为您提供所有不同用户的列表。如果你有一个单独的user表,你在这里没有提到,那将比这更好。 (http://sqlfiddle.com/#!2/1b1884/9/0

                      SELECT DISTINCT userid1 userid FROM points
                       UNION
                      SELECT DISTINCT userid2 userid FROM points

现在,您需要将这四个子查询加在一起,结果就是这样。这是大纲。

SELECT a.userid, 
       IFNULL(g.gained,0) gained, 
       IFNULL(s.spent,0) spent,
       IFNULL(r.received,0) received,
       IFNULL(g.gained,0)-IFNULL(s.spent,0)+IFNULL(r.received,0) total
  FROM (   /* all users subquery */
       ) a
  LEFT JOIN (   /* gained subquery */
       ) g ON a.userid = g.userid
  LEFT JOIN (   /* received subquery */
       ) r ON a.userid = r.userid
  LEFT JOIN (   /* spent subquery */
       ) s ON a.userid = s.userid
 ORDER BY a.userid

最后,将它们全部放在一起(http://sqlfiddle.com/#!2/1b1884/13/0

SELECT a.userid, 
       IFNULL(g.gained,0) gained, 
       IFNULL(s.spent,0) spent,
       IFNULL(r.received,0) received,
       IFNULL(g.gained,0)-IFNULL(s.spent,0)+IFNULL(r.received,0) total
  FROM (   /* all users subquery */
                      SELECT DISTINCT userid1 userid FROM points
                       UNION
                      SELECT DISTINCT userid2 userid FROM points
       ) a
  LEFT JOIN (   /* gained subquery */
                      SELECT userid1 AS userid,
                             SUM(points) AS gained
                        FROM points
                       WHERE userid1 = userid2
                       GROUP BY userid1
       ) g ON a.userid = g.userid
  LEFT JOIN (   /* received subquery */
                      SELECT userid2 AS userid,
                             SUM(points) AS received
                        FROM points
                       WHERE userid1 != userid2
                       GROUP BY userid2
       ) r ON a.userid = r.userid
  LEFT JOIN (   /* spent subquery */
                      SELECT userid1 AS userid,
                             SUM(points) AS spent
                        FROM points
                       WHERE userid1 != userid2
                       GROUP BY userid1
       ) s ON a.userid = s.userid
 ORDER BY a.userid

如果你认为它是一个四层俱乐部三明治,子查询作为奶酪片,JOIN条款作为面包片,它可能会有所帮助。我承认它是满口的!

答案 1 :(得分:0)

您可以对条件表达式(或ifs)使用条件聚合来完成您想要的任务。

基本查询如下所示:

select 
    userid
    , sum(case when u.userid =  p.userid1 and u.userid =  p.userId2 then points else 0 end) gained
    , sum(case when u.userid <> p.userid1 and u.userid =  p.userId2 then points else 0 end) received
    , sum(case when u.userid =  p.userid1 and u.userid <> p.userId2 then points else 0 end) spent
    , sum(case when u.userid =  p.userid1 and u.userid =  p.userId2 then points else 0 end) 
    + sum(case when u.userid <> p.userid1 and u.userid =  p.userId2 then points else 0 end) 
    - sum(case when u.userid =  p.userid1 and u.userid <> p.userId2 then points else 0 end) _current
from 
  (select userid1 userid from points union select userid2 from points) u
  , points p
group by u.userid;

如果要基于它创建视图,from子句中的子查询也需要在视图中。在下面链接的小提琴中,代码已被重构为几个视图。

此示例SQL Fiddle显示了使用视图实现的视图,根据您的示例数据,输出:

| userid | gained | received | spent | current |
|--------|--------|----------|-------|---------|
|      1 |      5 |        4 |    10 |      -1 |
|      2 |      0 |        5 |     4 |       1 |
|      3 |      0 |        5 |     0 |       5 |

另一种选择,而不是条件聚合,将使用相关子查询:

select 
    userid
    , (select coalesce(sum(points),0) from points p where u.userid =  p.userid1 and u.userid =  p.userId2) gained
    , (select coalesce(sum(points),0) from points p where u.userid <> p.userid1 and u.userid =  p.userId2) received
    , (select coalesce(sum(points),0) from points p where u.userid =  p.userid1 and u.userid <> p.userId2) spent
from (select userid1 userid from points union select userid2 from points) u;

这会产生相同的结果(但我没有包含当前列,因为它只是重复以保持代码简短。)