在子查询SQLite中使用Ifnull

时间:2014-12-30 04:57:06

标签: sqlite

我有这两张桌子,成员和water_meter

成员

id | name
=========
1  | Dani
2  | Dina
3  | Roni

water_meter

id | member_id  | date      | start | finish    | paid  |   paid_at
===+============+===========+=======+===========+=======+=====================+
1  |    1       |2014-07-01 |  12.3 |   38.7    |   1   | 2014-12-29 18:28:30
2  |    2       |2014-07-01 |  57.2 |   64.3    |   0   | null
3  |    3       |2014-07-01 |  14.6 |   52.3    |   0   | null

该会员需要每月支付用水量。我想要的是,'开始'每个月的价值是“完成”。前几个月的价值。这是我8月检查用水量的问题,

SELECT m.id, m.name, 
ifnull(t.start, (SELECT ifnull(finish, 0) FROM members m2 
LEFT JOIN water_meter t2 ON m2.id = t2.member_id AND t2.date = '2014-07-01') ) as start, 
t.finish, paid
FROM members m 
LEFT JOIN water_meter t ON m.id = t.member_id AND t.date = '2014-08-01'

结果:

id | name   | start  |  finish |
===+========+========+=========+
1  |  Dani  | 38.7   |   null  |
2  |  Dina  | 38.7   |   null  |
3  |  Roni  | 38.7   |   null  |

正如您所看到的,"开始"价值不对。这种情况的正确查询是什么?

我想要的是这样的

id | name   | start  |  finish |
===+========+========+=========+
1  |  Dani  | 38.7   |   null  |
2  |  Dina  | 64.3   |   null  |
3  |  Roni  | 52.3   |   null  |

检查:http://sqlfiddle.com/#!7/29a4c/2

1 个答案:

答案 0 :(得分:1)

您尚未在内部查询中分配正确的where条件。

SELECT m.id, m.name, 
  ifnull(t.start,
         (SELECT ifnull(finish, 0) FROM members m2 
          LEFT JOIN water_meter t2
            ON m2.id = t2.member_id AND t2.date = '2014-07-01'
          where m2.id = m.id)) as start, 
  t.finish, paid
FROM members m 
LEFT JOIN water_meter t ON m.id = t.member_id AND t.date = '2014-08-01'
WHERE m.active = 1

我不喜欢自我查询,但这会产生你想要的输出。

稍好一点(没有子查询,大型数据集可能很慢)解决方案:

select
  members.id,
  name,
  coalesce(wm_cur.start, wm_prev.finish),
  wm_cur.finish
from members
left join water_meter wm_cur
  on members.id = wm_cur.member_id
    and wm_cur.date between '2014-08-01' and date('2014-08-01','start of month','+1 month','-1 day')
left join water_meter wm_prev
  on members.id = wm_prev.member_id
    and wm_prev.date between '2014-07-01' and date('2014-07-01','start of month','+1 month','-1 day')
where members.active = 1

如果您愿意,可以将coalesce替换为ifnull。它还处理整个月而不仅仅是第一天,这可能是你想要的也可能不是。