2008-09-17 35 views
2

我有這個問題,因爲我剛剛發現這個網站,我決定把它發佈在這裏。讓我們說,我有一個表的時間戳和一個給定的「對象」(通用含義,而不是OOP對象)的狀態;有沒有一種最佳的方式來計算一個狀態和另一個(或相同)狀態(我稱之爲「旅行」)的下一次出現之間的時間與單個SQL語句(內部SELECTs和UNION不計算在內)之間的時間?例如:對於以下情況,初始和完成之間的行程時間爲6天,但在初始和複審之間爲2天。關係數據庫中的旅行時間計算?

2008-08-01 13:30:00 - 初始
2008-08-02 13:30:00 - 工作
2008-08-03 13:30:00 - 回顧
2008- 08-04 13:30:00 - 工作
2008-08-05 13:30:00 - 評論
2008-08-06 13:30:00 - 接受
2008-08-07 13:30:00 - 完成

不需要是通用的,只是說什麼SGBD你的s如果不是通用的,解決方案是特定的。

回答

0

我不認爲你可以用一條SQL語句得到答案,因爲你試圖從許多記錄中獲得一個結果。在SQL中實現這一點的唯一方法是獲取兩個不同記錄的時間戳字段並計算差異(datediff)。因此,需要聯合或內聯合。

0

我不確定我是否完全理解這個問題,但是您可以執行類似於以下內容的操作,即一次讀取表格,然後使用派生表格來計算它。 SQL Server代碼:

CREATE TABLE #testing 
(
    eventdatetime datetime NOT NULL, 
    state varchar(10) NOT NULL 
) 

INSERT INTO #testing (
    eventdatetime, 
    state 
) 
SELECT '20080801 13:30:00', 'Initial' UNION ALL 
SELECT '20080802 13:30:00', 'Work' UNION ALL 
SELECT '20080803 13:30:00', 'Review' UNION ALL 
SELECT '20080804 13:30:00', 'Work' UNION ALL 
SELECT '20080805 13:30:00', 'Review' UNION ALL 
SELECT '20080806 13:30:00', 'Accepted' UNION ALL 
SELECT '20080807 13:30:00', 'Done' 

SELECT DATEDIFF(dd, Initial, Review) 
FROM (
SELECT MIN(CASE WHEN state='Initial' THEN eventdatetime END) AS Initial, 
     MIN(CASE WHEN state='Review' THEN eventdatetime END) AS Review 
FROM #testing 
) AS A 

DROP TABLE #testing 
0
create table A (
    At datetime not null, 
    State varchar(20) not null 
) 
go 
insert into A(At,State) 
select '2008-08-01T13:30:00','Initial' union all 
select '2008-08-02T13:30:00','Work' union all 
select '2008-08-03T13:30:00','Review' union all 
select '2008-08-04T13:30:00','Work' union all 
select '2008-08-05T13:30:00','Review' union all 
select '2008-08-06T13:30:00','Accepted' union all 
select '2008-08-07T13:30:00','Done' 
go 
--Find trip time from Initial to Done 
select DATEDIFF(day,t1.At,t2.At) 
from 
    A t1 
     inner join 
    A t2 
     on 
      t1.State = 'Initial' and 
      t2.State = 'Review' and 
      t1.At < t2.At 
     left join 
    A t3 
     on 
      t3.State = 'Initial' and 
      t3.At > t1.At and 
      t4.At < t2.At 
     left join 
    A t4 
     on 
      t4.State = 'Review' and 
      t4.At < t2.At and 
      t4.At > t1.At 
where 
    t3.At is null and 
    t4.At is null 

沒有說是否加入被允許。加入到t3和t4(以及它們的比較)可以讓你說出是否需要最早或最新的開始和結束狀態(在這種情況下,我要求最新的「初始」和最早的「評論」)

在真正的代碼,我開始和結束的狀態將參數

編輯:哎呀,需要包括「t3.At < t2.At」和「t4.At> t1.At」,要解決的一些奇怪的序列(例如,如果我們刪除了第二個「審閱」,然後從「工作」查詢到「審閱」,則原始查詢將失敗)

0

如果您有序列號以及時間戳:在大多數RDBMS中,您可以創建一個自動增量列d不會更改任何INSERT語句。然後你加入表其自身的副本來獲得增量

select after.moment - before.moment, before.state, after.state 
from object_states before, object_states after 
where after.sequence + 1 = before.sequence 

(其中SQL語法的細節將根據該數據庫系統而異)。

0
-- Oracle SQl 

    CREATE TABLE ObjectState 
    (
     startdate date NOT NULL, 
     state varchar2(10) NOT NULL 
    ); 



    insert into ObjectState 
    select to_date('01-Aug-2008 13:30:00','dd-Mon-rrrr hh24:mi:ss'),'Initial' union all 
    select to_date('02-Aug-2008 13:30:00','dd-Mon-rrrr hh24:mi:ss'),'Work' union all 
    select to_date('03-Aug-2008 13:30:00','dd-Mon-rrrr hh24:mi:ss'),'Review' union all 
    select to_date('04-Aug-2008 13:30:00','dd-Mon-rrrr hh24:mi:ss'),'Work' union all 
    select to_date('05-Aug-2008 13:30:00','dd-Mon-rrrr hh24:mi:ss'),'Review' union all 
    select to_date('06-Aug-2008 13:30:00','dd-Mon-rrrr hh24:mi:ss'),'Accepted' union all 
    select to_date('07-Aug-2008 13:30:00','dd-Mon-rrrr hh24:mi:ss'),'Done'; 

-- Days in between two states 

    select o2.startdate - o1.startdate as days 
    from ObjectState o1, ObjectState o2 
    where o1.state = 'Initial' 
    and o2.state = 'Review'; 
0

我認爲你的步驟(您的行程中的每個記錄可以被看作是一個步驟)可以被地方組合在一起作爲同一活動的一部分。然後,可以將你的信息就可以了數據,例如:

SELECT Min(Tbl_Step.dateTimeStep) as tripBegin, _ 
     Max(Tbl_Step.dateTimeStep) as tripEnd _ 
FROM 
     Tbl_Step 
WHERE 
     id_Activity = 'AAAAAAA' 

利用這個原理,你就可以計算出樣的活動等的步數等聚集。但是你不會找到一種SQL方法來計算兩步之間的差距這樣的值,因爲這樣的數據不屬於第一步或第2步。一些報告工具使用他們所稱的「運行總和」來計算這些中間數據。根據您的目標,這可能是您的解決方案。

1

以下是使用分析函數的Oracle方法。

with data as (
SELECT 1 trip_id, to_date('20080801 13:30:00','YYYYMMDD HH24:mi:ss') dt, 'Initial' step from dual UNION ALL 
SELECT 1 trip_id, to_date('20080802 13:30:00','YYYYMMDD HH24:mi:ss') dt, 'Work'  step from dual UNION ALL 
SELECT 1 trip_id, to_date('20080803 13:30:00','YYYYMMDD HH24:mi:ss') dt, 'Review' step from dual UNION ALL 
SELECT 1 trip_id, to_date('20080804 13:30:00','YYYYMMDD HH24:mi:ss') dt, 'Work'  step from dual UNION ALL 
SELECT 1 trip_id, to_date('20080805 13:30:00','YYYYMMDD HH24:mi:ss') dt, 'Review' step from dual UNION ALL 
SELECT 1 trip_id, to_date('20080806 13:30:00','YYYYMMDD HH24:mi:ss') dt, 'Accepted' step from dual UNION ALL 
SELECT 1 trip_id, to_date('20080807 13:30:00','YYYYMMDD HH24:mi:ss') dt, 'Done'  step from dual) 
select trip_id, 
     step, 
     dt - lag(dt) over (partition by trip_id order by dt) trip_time 
from data 
/


1 Initial 
1 Work  1 
1 Review  1 
1 Work  1 
1 Review  1 
1 Accepted 1 
1 Done  1 

這些在傳統上我們可能使用自連接的情況下非常常用。

1

PostgreSQL的語法:

DROP TABLE ObjectState; 
CREATE TABLE ObjectState (
    object_id integer not null,--foreign key 
    event_time timestamp NOT NULL, 
    state varchar(10) NOT NULL, 
    --Other fields 
    CONSTRAINT pk_ObjectState PRIMARY KEY (object_id,event_time) 
); 

對於給定的狀態,查找第一個如下因素給定類型的狀態

select parent.object_id,parent.event_time,parent.state,min(child.event_time) as ch_event_time,min(child.event_time)-parent.event_time as step_time 
from 
    ObjectState parent 
    join ObjectState child on (parent.object_id=child.object_id and parent.event_time<child.event_time) 
where 
    --Starting state 
    parent.object_id=1 and parent.event_time=to_timestamp('01-Aug-2008 13:30:00','dd-Mon-yyyy hh24:mi:ss') 
    --needed state 
    and child.state='Review' 
group by parent.object_id,parent.event_time,parent.state; 

此查詢不是最短的更多鈔票,但它應該是很容易理解和使用部分其他查詢:

列出事件及其持續時間給定o bject

select parent.object_id,parent.event_time,parent.state,min(child.event_time) as ch_event_time, 
     CASE WHEN parent.state<>'Done' and min(child.event_time) is null THEN (select localtimestamp)-parent.event_time ELSE min(child.event_time)-parent.event_time END as step_time 
from 
    ObjectState parent 
    left outer join ObjectState child on (parent.object_id=child.object_id and parent.event_time<child.event_time) 
where parent.object_id=4  
group by parent.object_id,parent.event_time,parent.state 
order by parent.object_id,parent.event_time,parent.state; 

列表當前狀態爲未 「完成」

select states.object_id,states.event_time,states.state,(select localtimestamp)-states.event_time as step_time 
from 
    (select parent.object_id,parent.event_time,parent.state,min(child.event_time) as ch_event_time,min(child.event_time)-parent.event_time as step_time 
    from 
     ObjectState parent 
     left outer join ObjectState child on (parent.object_id=child.object_id and parent.event_time<child.event_time)  
    group by parent.object_id,parent.event_time,parent.state) states 
where  
    states.object_id not in (select object_id from ObjectState where state='Done') 
    and ch_event_time is null; 

測試數據

insert into ObjectState (object_id,event_time,state) 
select 1,to_timestamp('01-Aug-2008 13:30:00','dd-Mon-yyyy hh24:mi:ss'),'Initial' union all 
select 1,to_timestamp('02-Aug-2008 13:40:00','dd-Mon-yyyy hh24:mi:ss'),'Work' union all 
select 1,to_timestamp('03-Aug-2008 13:50:00','dd-Mon-yyyy hh24:mi:ss'),'Review' union all 
select 1,to_timestamp('04-Aug-2008 14:30:00','dd-Mon-yyyy hh24:mi:ss'),'Work' union all 
select 1,to_timestamp('04-Aug-2008 16:20:00','dd-Mon-yyyy hh24:mi:ss'),'Review' union all 
select 1,to_timestamp('06-Aug-2008 18:00:00','dd-Mon-yyyy hh24:mi:ss'),'Accepted' union all 
select 1,to_timestamp('07-Aug-2008 21:30:00','dd-Mon-yyyy hh24:mi:ss'),'Done'; 


insert into ObjectState (object_id,event_time,state) 
select 2,to_timestamp('01-Aug-2008 13:30:00','dd-Mon-yyyy hh24:mi:ss'),'Initial' union all 
select 2,to_timestamp('02-Aug-2008 13:40:00','dd-Mon-yyyy hh24:mi:ss'),'Work' union all 
select 2,to_timestamp('07-Aug-2008 13:50:00','dd-Mon-yyyy hh24:mi:ss'),'Review' union all 
select 2,to_timestamp('14-Aug-2008 14:30:00','dd-Mon-yyyy hh24:mi:ss'),'Work' union all 
select 2,to_timestamp('15-Aug-2008 16:20:00','dd-Mon-yyyy hh24:mi:ss'),'Review' union all 
select 2,to_timestamp('16-Aug-2008 18:02:00','dd-Mon-yyyy hh24:mi:ss'),'Accepted' union all 
select 2,to_timestamp('17-Aug-2008 22:10:00','dd-Mon-yyyy hh24:mi:ss'),'Done'; 

insert into ObjectState (object_id,event_time,state) 
select 3,to_timestamp('12-Sep-2008 13:30:00','dd-Mon-yyyy hh24:mi:ss'),'Initial' union all 
select 3,to_timestamp('13-Sep-2008 13:40:00','dd-Mon-yyyy hh24:mi:ss'),'Work' union all 
select 3,to_timestamp('14-Sep-2008 13:50:00','dd-Mon-yyyy hh24:mi:ss'),'Review' union all 
select 3,to_timestamp('15-Sep-2008 14:30:00','dd-Mon-yyyy hh24:mi:ss'),'Work' union all 
select 3,to_timestamp('16-Sep-2008 16:20:00','dd-Mon-yyyy hh24:mi:ss'),'Review'; 


insert into ObjectState (object_id,event_time,state) 
select 4,to_timestamp('21-Aug-2008 03:10:00','dd-Mon-yyyy hh24:mi:ss'),'Initial' union all 
select 4,to_timestamp('22-Aug-2008 03:40:00','dd-Mon-yyyy hh24:mi:ss'),'Work' union all 
select 4,to_timestamp('23-Aug-2008 03:20:00','dd-Mon-yyyy hh24:mi:ss'),'Review' union all 
select 4,to_timestamp('24-Aug-2008 04:30:00','dd-Mon-yyyy hh24:mi:ss'),'Work'; 
0

我試圖做到這一點在MySQL的對象。您將需要使用一個變量,因爲在MySQL的無等級的功能,所以它會是這樣的:

set @trip1 = 0; set @trip2 = 0; 
SELECT trip1.`date` as startdate, datediff(trip2.`date`, trip1.`date`) length_of_trip 
FROM 
(SELECT @trip1 := @trip1 + 1 as rank1, `date` from trip where state='Initial') as trip1 
INNER JOIN 
(SELECT @trip2 := @trip2 + 1 as rank2, `date` from trip where state='Done') as trip2 
ON rank1 = rank2; 

我假設你要計算「初始」和「完成」狀態之間的時間。

+---------------------+----------------+ 
| startdate   | length_of_trip | 
+---------------------+----------------+ 
| 2008-08-01 13:30:00 |    6 | 
+---------------------+----------------+ 
0

好吧,這是一個有點超出有點怪,但是我建了一個Web應用程序來跟蹤我妻子的收縮,我們生了一個孩子之前,這樣我可以從作品看,當它越來越接近時間去醫院。無論如何,我很容易以兩種觀點來構建這個基本的東西。

create table contractions time_date timestamp primary key; 

create view contraction_time as 
SELECT a.time_date, max(b.prev_time) AS prev_time 
    FROM contractions a, (SELECT contractions.time_date AS prev_time 
      FROM contractions) b 
    WHERE b.prev_time < a.time_date 
    GROUP BY a.time_date; 

create view time_between as 
SELECT contraction_time.time_date, contraction_time.prev_time, contraction_time.time_date - contraction_time.prev_time 
    FROM contraction_time; 

這可以作爲一個子查詢來實現明顯爲好,但我用其他的東西中間的意見爲好,所以這個結果不錯。