1

请,有人可以帮助我,如何获取文档状态的信息...通常,我需要给定的时间段(开始日期,结束日期过滤器)来检查文档是活动(A)还是非活动(I)

Table Documents
ID  Doc    Date    Status
1   11    1.1.2012.  A
2   11    1.4.2012.  I
3   11    25.4.2012. A
4   11    1.6.2012.  I
5   22    18.4.2012. A
6   22    30.4.2012. I

Dynamic filters: @start,@end

Example: 
@start= 2.3.2012
@end=5.5.2012
Result should be 
11  2.3.-1.4. Status=A 
    1.4.-25.4 Status=I 
    25.4.-5.5. Status=A 
22  2.3.-18.4. 'not exist'
    18.4-30.4. Status=A 
    30.4.-5.5. Status=I 

    If filter is 
@start= 1.2.
@end= 28.2.
Result should be 
11 'A'  
22 'not exist'

If filter is 
@start= 18.4.
@end= 20.4.
Result should be 
11 'I'
22 'A'

编辑:

抱歉,我不想听起来像是“为我做”......我尝试过这样的事情

WITH a AS (
   SELECT documents.*,lag(date) OVER (PARTITION BY doc ORDER BY DATE) AS pre_date
 FROM documents ORDER BY DATE
)
SELECT a.* from a
WHERE (@start between a.pre_date AND a.date) AND (@end between a.pre_date AND a.date)

这不是我所需要的。这也是 sql fiddle sqlfiddlelink中的示例。我更改过滤器表以测试 @start 和 @end 的不同值

谢谢

4

2 回答 2

2

此查询似乎生成了您正在寻找的内容,使用您在 sqlfiddle 上定义的“过滤器”表。它不包括“不存在”行。我不确定你是否真的想要那个,或者你只是想表明它不存在。我假设后者。否则我猜过滤器表中的一些额外时间段将需要“联合”。

这个想法是首先创建一个时期,就像你试图用“滞后”做的那样,但是用“领先”来表示这个时期的结束是下一个时期的开始。可能想从领先中减去 1 天以使结束日期不包含在内,但我不想让这个更复杂。

  • 如果没有结束期,则使用过滤器结束期(合并)
  • 任何早于过滤器开始日期的开始日期都将上升到过滤器开始日期(最大)
  • 任何大于过滤器结束日期的结束日期都会减少到过滤器结束日期(最小)

询问:

SELECT id, doc, status, from_date, to_date
  FROM ( SELECT id, doc, status, GREATEST(d.date, f.start_date) AS from_date
               ,LEAST( COALESCE( lead(date) OVER (PARTITION BY doc ORDER BY date)
                                ,f.end_date
                               )
                       ,f.end_date ) AS to_date
           FROM documents d
               ,filter f
        ) d
  WHERE from_date < to_date
  ORDER BY doc, from_date;

设置:

CREATE TABLE documents(id int, doc int, date date, status varchar (1));

insert into documents values(1, 11, to_date('2012-01-01', 'yyyy-mm-dd'),'A');
insert into documents values(2, 11, to_date('2012-04-01', 'yyyy-mm-dd'),'I');
insert into documents values(3, 11, to_date('2012-04-25', 'yyyy-mm-dd'),'A');
insert into documents values(4, 11, to_date('2012-06-01', 'yyyy-mm-dd'),'I');
insert into documents values(5, 22, to_date('2012-04-18', 'yyyy-mm-dd'),'A');
insert into documents values(6, 22, to_date('2012-04-30', 'yyyy-mm-dd'),'I');

CREATE TABLE filter(start_date date, end_date date);

跑:

postgres=#     insert into filter values(to_date('2012-02-03', 'yyyy-mm-dd'), to_date('2012-05-05', 'yyyy-mm-dd'));
INSERT 0 1
postgres=#     SELECT id, doc, status, from_date, to_date
postgres-#       FROM ( SELECT id, doc, status, GREATEST(d.date, f.start_date) AS from_date
postgres(#                    ,LEAST( COALESCE( lead(date) OVER (PARTITION BY doc ORDER BY date)
postgres(#                                     ,f.end_date
postgres(#                                    )
postgres(#                            ,f.end_date ) AS to_date
postgres(#                FROM documents d
postgres(#                    ,filter f
postgres(#             ) d
postgres-#       WHERE from_date < to_date
postgres-#       ORDER BY doc, from_date
postgres-# ;
 id | doc | status | from_date  |  to_date
----+-----+--------+------------+------------
  1 |  11 | A      | 2012-02-03 | 2012-04-01
  2 |  11 | I      | 2012-04-01 | 2012-04-25
  3 |  11 | A      | 2012-04-25 | 2012-05-05
  5 |  22 | A      | 2012-04-18 | 2012-04-30
  6 |  22 | I      | 2012-04-30 | 2012-05-05
(5 rows)


postgres=#     truncate table filter;
TRUNCATE TABLE
postgres=#     insert into filter values(to_date('2012-01-02', 'yyyy-mm-dd'), to_date('2012-02-28', 'yyyy-mm-dd'));
INSERT 0 1
postgres=#     SELECT id, doc, status, from_date, to_date
postgres-#       FROM ( SELECT id, doc, status, GREATEST(d.date, f.start_date) AS from_date
postgres(#                    ,LEAST( COALESCE( lead(date) OVER (PARTITION BY doc ORDER BY date)
postgres(#                                     ,f.end_date
postgres(#                                    )
postgres(#                            ,f.end_date ) AS to_date
postgres(#                FROM documents d
postgres(#                    ,filter f
postgres(#             ) d
postgres-#       WHERE from_date < to_date
postgres-#       ORDER BY doc, from_date;
 id | doc | status | from_date  |  to_date
----+-----+--------+------------+------------
  1 |  11 | A      | 2012-01-02 | 2012-02-28
(1 row)


postgres=#     truncate table filter;
TRUNCATE TABLE
postgres=#     insert into filter values(to_date('2012-04-18', 'yyyy-mm-dd'), to_date('2012-04-20', 'yyyy-mm-dd'));
INSERT 0 1
postgres=#     SELECT id, doc, status, from_date, to_date
postgres-#       FROM ( SELECT id, doc, status, GREATEST(d.date, f.start_date) AS from_date
postgres(#                    ,LEAST( COALESCE( lead(date) OVER (PARTITION BY doc ORDER BY date)
postgres(#                                     ,f.end_date
postgres(#                                    )
postgres(#                            ,f.end_date ) AS to_date
postgres(#                FROM documents d
postgres(#                    ,filter f
postgres(#             ) d
postgres-#       WHERE from_date < to_date
postgres-#       ORDER BY doc, from_date;
 id | doc | status | from_date  |  to_date
----+-----+--------+------------+------------
  2 |  11 | I      | 2012-04-18 | 2012-04-20
  5 |  22 | A      | 2012-04-18 | 2012-04-20
(2 rows)


postgres=#
于 2012-06-22T02:01:50.897 回答
2

基本上,@Glenn 的回答涵盖了它。我投了赞成票。我仅发布此内容以展示其他详细信息 - 太多无法放入评论:

  • 使用多行INSERT语法。

  • 在CTE中提供过滤器,这比为此创建额外的表要方便得多。

  • 此查询可以一次处理多个过滤器。

  • 用于lead(date,1,'infinity')消除对COALESCE.

  • 演示一种不那么复杂的方式来输入日期文字 - ISO 8601 格式在任何'yyyy-mm-dd'语言环境中都是明确的:

    '2012-02-03'::date
    

    或者

    date '2012-02-03'
    

    代替:

    to_date('2012-02-03', 'yyyy-mm-dd')
    
  • 把它放在一个噪音更小、更易读的格式中

CREATE TEMP TABLE documents (id int, doc int, date date, status "char");

INSERT INTO documents VALUES
 (1,'11','2012-01-01','A')
,(2,'11','2012-04-01','I')
,(3,'11','2012-04-25','A')
,(4,'11','2012-06-01','I')
,(5,'22','2012-04-18','A')
,(6,'22','2012-04-30','I');

WITH filter(filter_id, start_date, end_date) AS( 
    VALUES
     (1, '2012-04-18'::date, '2012-04-20'::date)
    ,(2, '2012-03-02'::date, '2012-05-05'::date)
    )
    , d AS (
    SELECT doc, status, date AS d1
          ,lead(date,1,'infinity') OVER (PARTITION BY doc ORDER BY date) AS d2
    FROM   documents
    )
SELECT f.filter_id, d.doc
      ,GREATEST(f.start_date, d.d1) AS start
      ,LEAST(f.end_date, d.d2) AS end
      ,d.status
FROM   filter f, d
WHERE  f.start_date <= d.d2
AND    f.end_date   >= d.d1
ORDER  BY f.filter_id, d.doc, d.d1;
于 2012-06-23T22:57:06.207 回答