【问题标题】:Oracle query to display missing results用于显示缺失结果的 Oracle 查询
【发布时间】:2021-07-08 04:34:19
【问题描述】:

我在下面有 SQL 查询来显示人名,日期范围之间的计数。结果如下:

DAY           NAME           count_person 
04-MAY-2020   person_1       220
06-MAY-2020   person_1       30

如果该日期的姓名缺失,我希望我的结果如下所示

DAY           NAME           count_person 
01-MAY-2020   person_1       0
02-MAY-2020   person_1       0
03-MAY-2020   person_1       220
04-MAY-2020   person_1       30
'
'
'
31-MAY-2020   person_1       0

下面是我的sql查询:

SELECT  TRUNC(AN.DATE_CREATED) DAY,  AN.NAME, COUNT(AN.NAME) count_person 
FROM 
    person AN 
WHERE 
    TRUNC(AN.DATE_CREATED) >= '01-MAY-20' 
    AND TRUNC(AN.DATE_CREATED) <= '31-MAY-20' 
    GROUP BY TRUNC(AN.DATE_CREATED), AN.NAME

感谢您的解决方案,我对我的输出进行了修改 输出如下所示:

DAY           NAME           count_person 
01-MAY-2020   person_1       0
02-MAY-2020   person_1       0
03-MAY-2020   person_1       220
04-MAY-2020   person_1       30
05-MAY-2020   person_1       30
'
'
15-MAY-2020   person_1       12
16-MAY-2020   person_1       12
'
'
31-MAY-2020   person_1       30


意思是如果在特定日期我的计数为零,那么它应该从前一个日期开始计数,如果它不为零,那么它会离开吗?我尝试使用铅,但逻辑无法取之前的值。

【问题讨论】:

  • 您的日期和值似乎不太匹配;编辑后更是如此。我想我已经明白你的意思了,但并不完全清楚。
  • 您的解决方案对我有用,谢谢!

标签: sql oracle


【解决方案1】:

您可以使用递归 CTE 生成日期范围内的所有日期,然后对已有的表执行左连接。

例如:

with
range (d) as (
  select date '2020-05-01' from dual
 union all
  select d + 1
  from range
  where d < date '2020-05-31'
)
select
  r.d, 
  coalesce(p.name, 
    (select name from person order by name fetch next 1 rows only)
  ) as person, 
  coalesce(p.count, 0) as count
from range r
left join person p on p.day = r.d
order by r.d

结果:

 D          PERSON    COUNT 
 ---------- --------- ----- 
 01-MAY-20  person_1  0     
 02-MAY-20  person_1  0     
 03-MAY-20  person_1  0     
 04-MAY-20  person_1  220   
 05-MAY-20  person_1  0     
 06-MAY-20  person_1  30    
 07-MAY-20  person_1  0     
 08-MAY-20  person_1  0     
 09-MAY-20  person_1  0     
 10-MAY-20  person_1  0     
 11-MAY-20  person_1  0     
 12-MAY-20  person_1  0     
 13-MAY-20  person_1  0     
 14-MAY-20  person_1  0     
 15-MAY-20  person_1  0     
 16-MAY-20  person_1  0     
 17-MAY-20  person_1  0     
 18-MAY-20  person_1  0     
 19-MAY-20  person_1  0     
 20-MAY-20  person_1  0     
 21-MAY-20  person_1  0     
 22-MAY-20  person_1  0     
 23-MAY-20  person_1  0     
 24-MAY-20  person_1  0     
 25-MAY-20  person_1  0     
 26-MAY-20  person_1  0     
 27-MAY-20  person_1  0     
 28-MAY-20  person_1  0     
 29-MAY-20  person_1  0     
 30-MAY-20  person_1  0     
 31-MAY-20  person_1  0     

请参阅db<>fiddle 的运行示例。

【讨论】:

  • 嗨,谢谢您的解决方案。我已更新问题,我的输出要求已更改
  • @shanky 我建议您针对新要求提出一个单独的问题。顺便问一下,12 是从哪里来的?还有,为什么 4-may 里面有 30 个?
【解决方案2】:

这个想法是使用cross join 来生成行,并使用left join 来引入现有数据。您还需要生成一个计数,因此也涉及到聚合。

@TheImpaler 的回答是正确的。 . .为一个人。但对于所有人:

with days (d) as (
      select date '2020-05-01' from dual
      union all
      select d + interval '1' day
      from days
      where d < date '2020-05-31'
     )
select d.day, p.name, count(p.name) as count_person 
from days d cross join
     (select distinct p.name from person) n left join 
     person p
     on trunc(p.date_created) = d.d and
        p.name = n.name
group by d.day, p.name
order by p.name, d.day;

【讨论】:

    【解决方案3】:

    与@TheImpaler 类似的想法,至少生成单独的日子;但您还需要获取相关名称,并在您的人员表的外部连接中使用两者,例如:

    with days (day) as (
      select date '2020-05-01' from dual
      union all
      select day + 1 from days where day < last_day(day)
    ),
    names (name) as (
      select distinct name from person
      -- possibly only within the target month?
    )
    select d.day, n.name, count(p.name) as count_person
    from days d
    cross join names n
    left join person p on p.name = n.name
    and p.date_created >= d.day
    and p.date_created < d.day + 1
    group by d.day, n.name
    order by d.day, n.name
    

    递归天数 CTE 从一个月的第一天开始,获取该月的所有天数,无需指定结束日期 - 当然,如果您愿意,您仍然可以这样做。

    名称 CTE 从目标表中获取所有名称;但是您可能实际上想从另一个表中获取它们,或者使用固定名称或名称集合;或者可能只想要在该月有任何数据的名称。目前还不清楚是否需要限制。

    然后将它们交叉连接以使每个人每天都在工作。然后根据名称和日期将结果外连接到您的真实表,使用范围而不是截断。

    db<>fiddle 用模拟当前输出的数据显示结果;并为另一个人额外增加一行,显示每个人每天获得一行。


    如果在特定日期我的计数为零,那么它应该从上一个日期开始计数,如果它不为零,那么它就会离开它

    您可以使用last_value(),稍加操作:

    with days (day) as (
      select date '2020-05-01' from dual
      union all
      select day + 1 from days where day < last_day(day)
    ),
    names (name) as (
      select distinct name from person
      -- possibly only within the target month?
    )
    select d.day, n.name,
      coalesce(
        last_value(nullif(count(p.name),0) ignore nulls)
          over (partition by n.name order by d.day), 0) as count_person
    from days d
    cross join names n
    left join person p on p.name = n.name
    and p.date_created >= d.day
    and p.date_created < d.day + 1
    group by d.day, n.name
    order by n.name, d.day
    

    nullif(count(...), 0) 将零计数视为 null; last_value() 忽略空值,因此获取最后一个非空值(包括当前行);由于前三天没有可使用的非空值,coalesce(..., 0) 将这些值转换为零。

    db<>fiddle

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-10
      • 2013-01-31
      • 2012-12-30
      • 1970-01-01
      相关资源
      最近更新 更多