按日期汇总多个记录

时间:2017-10-31 23:32:12

标签: sql oracle

我的模型看起来像:

MedicationAdherence {
                 :id => :integer,
     :adherence_date => :date,
     :scheduled_time => :string,
    :acknowledged_at => :datetime,
         :patient_id => :integer,
         :created_at => :datetime,
         :updated_at => :datetime
}

我有7条记录(相同patient_id):

{ id: 1, adherence_date: 2017-10-01, scheduled_time: 'morning', acknowledged_at: Tue, 31 Oct 2017 19:59:19 UTC +00:00 }
{ id: 2, adherence_date: 2017-10-01, scheduled_time: 'afternoon', acknowledged_at: nil }
{ id: 3, adherence_date: 2017-10-01, scheduled_time: 'night', acknowledged_at: Tue, 31 Oct 2017 19:59:19 UTC +00:00 }
{ id: 4, adherence_date: 2017-10-02, scheduled_time: 'morning', acknowledged_at: Tue, 31 Oct 2017 19:59:19 UTC +00:00 }
{ id: 5, adherence_date: 2017-10-02, scheduled_time: 'afternoon', acknowledged_at: Tue, 31 Oct 2017 19:59:19 UTC +00:00 }
{ id: 6, adherence_date: 2017-10-02, scheduled_time: 'evening', acknowledged_at: Tue, 31 Oct 2017 19:59:19 UTC +00:00 }
{ id: 7, adherence_date: 2017-10-02, scheduled_time: 'night', acknowledged_at: nil }

我希望的结果是将上面的记录分组到以下输出中:

{
    "adherence_date" => 2017-10-1,
           "morning" => 1,
         "afternoon" => 0,
           "evening" => nil,
             "night" => 1
},
{
    "adherence_date" => 2017-10-2,
           "morning" => 1,
         "afternoon" => 1,
           "evening" => 1,
             "night" => 0
}

如果没有记录(2017-10-1之夜),它应该返回零。当有记录但没有confirmged_at时它应该返回false(0),当有确认_at返回true时(1)

下面是我用来尝试组合所有这些数据的查询,但它给了我重复的记录。如何将我的数据汇总到上面的内容中......我确信这是一种更简单的方法

WITH
  adherences AS (
    SELECT * FROM medication_adherences WHERE patient_id = 10049
  ),

  morning AS (
    SELECT adherence_date,
      CASE acknowledged_at WHEN null THEN 0 ELSE 1 END as morning
    FROM adherences
    WHERE scheduled_time = 'morning'
  ),

  afternoon as (
    SELECT adherence_date,
      CASE acknowledged_at WHEN null THEN 0 ELSE 1 END as afternoon
    FROM adherences
    WHERE scheduled_time = 'afternoon'
  ),

  evening as (
    SELECT adherence_date,
      CASE acknowledged_at WHEN null THEN 0 ELSE 1 END as evening
    FROM adherences
    WHERE scheduled_time = 'evening'
  ),

  night as (
    SELECT adherence_date,
      CASE acknowledged_at WHEN null THEN 0 ELSE 1 END as night
    FROM adherences
    WHERE scheduled_time = 'night'
  )

SELECT morning.morning, afternoon.afternoon, evening.evening, night.night, adherences.adherence_date
FROM adherences
LEFT JOIN morning ON morning.adherence_date = adherences.adherence_date
LEFT JOIN afternoon ON afternoon.adherence_date = adherences.adherence_date
LEFT JOIN evening ON evening.adherence_date = adherences.adherence_date
LEFT JOIN night ON night.adherence_date = adherences.adherence_date

我正在运行oracle-12c

修改

看起来我必须在我的查询中添加GROUP BY morning.morning, afternoon.afternoon, evening.evening, night.night, adherences.adherence_date才能正确分组。是否有更简单的方法来聚合这些数据?

2 个答案:

答案 0 :(得分:2)

我假设(patient_id, adherence_date, scheduled_time)在您的表格中是唯一的,这意味着患者可以每隔一个时间预订一次"和日期。

with medication_adherences  as(
-- This is your test data
   select 10049 as patient_id, 1 as id, date '2017-10-01' as adherence_date, 'morning'    as scheduled_time, timestamp '2017-10-31 19:59:19' as acknowledged_at from dual union all
   select 10049 as patient_id, 2 as id, date '2017-10-01' as adherence_date, 'afternoon'  as scheduled_time, null                            as acknowledged_at from dual union all                          
   select 10049 as patient_id, 3 as id, date '2017-10-01' as adherence_date, 'night'      as scheduled_time, timestamp '2017-10-31 19:59:19' as acknowledged_at from dual union all
   select 10049 as patient_id, 4 as id, date '2017-10-02' as adherence_date, 'morning'    as scheduled_time, timestamp '2017-10-31 19:59:19' as acknowledged_at from dual union all
   select 10049 as patient_id, 5 as id, date '2017-10-02' as adherence_date, 'afternoon'  as scheduled_time, timestamp '2017-10-31 19:59:19' as acknowledged_at from dual union all
   select 10049 as patient_id, 6 as id, date '2017-10-02' as adherence_date, 'evening'    as scheduled_time, timestamp '2017-10-31 19:59:19' as acknowledged_at from dual union all
   select 10049 as patient_id, 7 as id, date '2017-10-02' as adherence_date, 'night'      as scheduled_time, null                            as acknowledged_at from dual
)
select adherence_date
      ,sum(case when scheduled_time = 'morning'   then nvl2(acknowledged_at,1,0) end) as morning
      ,sum(case when scheduled_time = 'afternoon' then nvl2(acknowledged_at,1,0) end) as afternoon
      ,sum(case when scheduled_time = 'evening'   then nvl2(acknowledged_at,1,0) end) as evening
      ,sum(case when scheduled_time = 'night'     then nvl2(acknowledged_at,1,0) end) as night
  from medication_adherences 
 where patient_id = 10049
 group
    by adherence_date;

逻辑的工作原理如下:

  • 如果acknowred_at为null,则我们聚合0(通过nvl2)
  • 如果acknowred_at null,则我们汇总1(通过nvl2)
  • 如果此时间段没有记录,我们会聚合null(因为......失败时的情况)

答案 1 :(得分:0)

我不是Oracle开发人员,但您在这里缺少的是group by子句...如果您想计算记录数,可以用EXP替换MAX ...

Select MAX(Morning.Morning), MAX(afternoon.afternoon), MAX(evening.evening), MAX(night.night), adherences.adherence_date
FROM medication_adherences 
LEFT JOIN morning ON morning.adherence_date = adherences.adherence_date
LEFT JOIN afternoon ON afternoon.adherence_date = adherences.adherence_date
LEFT JOIN evening ON evening.adherence_date = adherences.adherence_date
LEFT JOIN night ON night.adherence_date = adherences.adherence_date
WHERE patient_id = 10049
GROUP BY adherences.adherence_date

我会摆脱坚持CTE,因为我们并不真的需要它......你仍然需要在这个查询之上的早晨,下午等CTE。