2

我有两个描述用户及其付款的表格:

CREATE TABLE test_users
(id int IDENTITY NOT NULL,
name varchar(25),
PRIMARY KEY (id));

CREATE TABLE test_payments
(id int IDENTITY NOT NULL,
user_id int NOT NULL,
money money NOT NULL,
date datetime NOT NULL,
PRIMARY KEY (id));

INSERT INTO test_users (name) 
VALUES ('john');

INSERT INTO test_users (name) 
VALUES ('peter');

INSERT INTO test_payments (user_id, money, date)
VALUES (1, $1, CONVERT(datetime, '15.12.2012'));

INSERT INTO test_payments (user_id, money, date)
VALUES (1, $2, CONVERT(datetime, '16.12.2012'));

INSERT INTO test_payments (user_id, money, date)
VALUES (2, $1, CONVERT(datetime, '16.12.2012'));

INSERT INTO test_payments (user_id, money, date)
VALUES (2, $3, CONVERT(datetime, '17.12.2012'));

INSERT INTO test_payments (user_id, money, date)
VALUES (1, $1, CONVERT(datetime, '19.12.2012'));

表 test_users:

id  name
-------------
1   john
2   peter

表 test_payments:

id  user_id money   last_activity
---------------------------------------
1   1   1.0000  2012-12-15
2   1   2.0000  2012-12-16
3   2   1.0000  2012-12-16
4   2   3.0000  2012-12-17
5   1   1.0000  2012-12-19

我需要制作一个用户统计数据,它会告诉我:

  1. 用户名
  2. 一段时间内的总费用
  3. 最后一个用户活动的日期(一般,不是一段时间)。

例如,以 15-18.12.12 期间为例,我期望得到以下结果:

name    total    last_activity
--------------------------------
peter   $4       2012-12-17
john    $3       2012-12-19

我尝试了以下查询:

SELECT u.*, SUM(p.money) total, MAX(p.date) last_activity
FROM test_users u
JOIN test_payments p
ON u.id= p.user_id
WHERE p.date BETWEEN CONVERT(datetime, '15.12.2012') AND CONVERT(datetime, '18.12.2012')
GROUP BY u.id, u.name
ORDER BY total DESC;

但 last_activity 的结果错误,因为它也在日期范围内:

id  name    total   last_activity
--------------------------------
2   peter   4.0000  2012-12-17
1   john    3.0000  2012-12-16

请提出解决方案。

4

4 回答 4

3

您需要将条件从where子句移动到case语句:

SELECT u.id, u.name,
      SUM(case when p.date BETWEEN CONVERT(datetime, '15.12.2012') AND CONVERT(datetime, '18.12.2012')
               then p.money
          end) total,
      MAX(p.date) last_activity
FROM test_users u JOIN
     test_payments p
     ON u.id= p.user_id
GROUP BY u.id, u.name
ORDER BY total DESC;

如果您只想要在该期间付款的用户,那么您可以包括:

having total is not null

如果您希望 NULL 值显示为 0 而不是 NULL,则包含else 0在 case 语句中。

于 2012-12-20T16:52:28.080 回答
3

看起来我在做我的工作时弹出了其他几个答案,但无论如何都在这里。这里有一个工作 sql fiddle:http://sqlfiddle.com/#! 3/14808/6

基本上,无论日期范围如何,您都需要一个查询来提取最大日期。我选择将其作为相关子查询来执行。

SELECT 
  u.id,
  u.name,
  SUM(IsNull(money,0)) as TotalMoneyInRange,
  (SELECT max(date) FROM test_payments where user_id = u.id) AS LastPaymentOverAll
FROM test_users AS u
LEFT JOIN test_payments AS p
ON u.id = p.user_id
WHERE 
  p.date IS NULL OR
  p.date between 
  CAST('12-11-2012' AS datetime) --range begin
  and 
  CAST('12-16-2012' as datetime) --range end
GROUP BY u.id, u.name
于 2012-12-20T17:07:11.647 回答
1

您还可以使用子查询来获取结果:

SELECT u.*, total, last_activity
FROM test_users u
JOIN
(
  select sum(money) total, user_id
  from test_payments
  WHERE date BETWEEN CONVERT(datetime, '2012-12-15') 
    AND CONVERT(datetime, '2012-12-18')
  group by user_id
) p
  ON u.id= p.user_id
inner join 
(
  select user_id, max(date) last_activity
  from test_payments
  group by user_id
) p1
  on p.user_id = p1.user_id
ORDER BY total DESC;

请参阅带有演示的 SQL Fiddle

于 2012-12-20T17:02:19.423 回答
0

您可以为没有 WHERE 子句的 MAX 日期添加子查询,如下所示:

SELECT 
  u.*
  ,SUM(p.money) total
  ,a.max_date last_activity
FROM test_users u
  INNER JOIN test_payments p ON u.id = p.user_id
  INNER JOIN (SELECT user_id, MAX(date) AS max_date 
              FROM test_payments 
              GROUP BY user_id) a ON u.id = a.user_id
WHERE p.date BETWEEN CONVERT(datetime, '15.12.2012') AND CONVERT(datetime, '18.12.2012')
GROUP BY u.id, u.name, a.max_date
ORDER BY total DESC;
于 2012-12-20T17:05:46.357 回答