【问题标题】:Advice on a complex SQL query for a BIRT dataset关于 BIRT 数据集的复杂 SQL 查询的建议
【发布时间】:2011-02-17 10:29:26
【问题描述】:

我有以下(简化的)PostgreSQL 数据库表,其中包含有关在特定设备上完成的维护的信息:

id bigint NOT NULL,
"time" timestamp(0) with time zone,
action_name text NOT NULL,
action_info text NOT NULL DEFAULT ''::text,

action_name 字段可以有四个感兴趣的值:

MAINTENANCE_START
DEVICE_DEFECT
DEVICE_REPAIRED
MAINTENANCE_STOP
<other (irrelevant) values>

我必须使用此表中的信息进行 BIRT 报告。每次遇到 MAINTENANCE_STOP 操作时,我都应该在表中有一个条目。如果在此 MAINTENANCE_STOP 操作与其相应的 MAINTENANCE_START 操作之间(应该是最大“时间”值小于 MAINTENANCE_STOP 操作的 MAINTENANCE_START 操作)我遇到 DEVICE_DEFECT 或 DEVICE_REPAIRED 操作我应该在表格单元格中写入字符串“设备不可用”,否则我应该写“设备可用”。

另外,我应该将维护的持续时间计算为 MAINTENANCE_STOP 操作和 MAINTENANCE_START 操作之间的时间差。

我第一次尝试在 SQL 查询中执行此操作,但现在我不确定是否可行。你推荐什么方法?

【问题讨论】:

标签: sql postgresql birt


【解决方案1】:

我的工作 sn-p:

CREATE TABLE "log"
(
  id bigint NOT NULL,
  time timestamp(0) with time zone,
  action_name text NOT NULL,
  action_info text NOT NULL DEFAULT ''::text
);

insert into log(id,time,action_name,action_info) values ( 1, '2011-01-01', 'MAINTENANCE_START', 'maintenance01start');
insert into log(id,time,action_name,action_info) values ( 2, '2011-02-01', 'MAINTENANCE_START', 'maintenance02start');
insert into log(id,time,action_name,action_info) values ( 3, '2011-03-01', 'MAINTENANCE_START', 'maintenance03start');
insert into log(id,time,action_name,action_info) values ( 4, '2011-04-01', 'MAINTENANCE_START', 'maintenance04start');
insert into log(id,time,action_name,action_info) values ( 5, '2011-01-10', 'MAINTENANCE_STOP', 'maintenance01stop');
insert into log(id,time,action_name,action_info) values ( 6, '2011-02-10', 'MAINTENANCE_STOP', 'maintenance02stop');
insert into log(id,time,action_name,action_info) values ( 7, '2011-03-10', 'MAINTENANCE_STOP', 'maintenance03stop');
--insert into log(id,time,action_name,action_info) values ( 8, '2011-04-10', 'MAINTENANCE_STOP', 'maintenance04stop');
insert into log(id,time,action_name,action_info) values ( 9, '2011-02-05', 'DEVICE_DEFECT', 'maintenance02defect');
insert into log(id,time,action_name,action_info) values ( 10, '2011-03-05', 'DEVICE_REPAIRED', 'maintenance03repaired');

select 
  maintenance.start as start
, maintenance.stop as stop
, count (device_action.*) as device_actions
from (select 
  l_start.time as start
  , (select time 
      from log l_stop 
      where l_stop.time > l_start.time 
      and l_stop.action_name = 'MAINTENANCE_STOP'
      order by time asc limit 1) as stop
  from log l_start
  where l_start.action_name='MAINTENANCE_START' order by l_start.time asc) maintenance
left join log device_action
  on device_action.time > maintenance.start
  and device_action.time < maintenance.stop
  and device_action.action_name like 'DEVICE_%'
group by maintenance.start
  , maintenance.stop
order by maintenance.start asc
;

注意性能。如果 Postgres 没有优化嵌套查询,则需要 O(n^2) 时间。

如果可以的话:

  1. 改变结构。例如。一个表 DEVICE_MAINTENANCES 具有维护 ID,第二个表 DEVICE_MAINTENANCE_ACTIONS 具有外键 DEVICE_MAINTENANCES.ID。查询将更简单、更快捷。
  2. 如果不是,则将time 视为主键(隐式索引)
  3. 如果没有,请在time 列上创建索引。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-11
    • 2013-09-01
    • 1970-01-01
    • 2013-05-30
    • 1970-01-01
    • 1970-01-01
    • 2011-05-31
    • 1970-01-01
    相关资源
    最近更新 更多