请,有人可以帮助我,如何获取doc状态的信息...... 一般来说,我需要一段时间(开始日期,结束日期过滤器) 检查文件是活动(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中的示例。 我更改了Filter表以测试@start和@end
的不同值由于
答案 0 :(得分: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=#
答案 1 :(得分: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;