我有一个名为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
列的算法是:
我是mysql的新手,我的问题是,如果我进入多个子查询,我不知道如何为不同的用户保存总和值。任何帮助将不胜感激
更新:示例中的数字是准确的
答案 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;
这会产生相同的结果(但我没有包含当前列,因为它只是重复以保持代码简短。)