2013-07-09 2 views
2

J'ai une table STARTSTOPfirebird - auto se joindre à une table

ACTION DATA     ID_PPSTARTSTOPPOZ 
0 2013-03-18 08:38:00 10451 
1 2013-03-18 09:00:00 10453 
0 2013-03-18 09:50:00 10466 
1 2013-03-18 10:38:00 10467 
0 2013-03-19 11:54:00 10499 
1 2013-03-19 12:32:00 10505 

Action 0 -> COMMENCEZ ACTION Action 1 -> ARRET ACTION DATA est un horodatage d'action

Je voudrais exécuter une instruction select qui renvoie des enregistrements quelque chose comme:

ACTION_1 ACTION_2 DURATION 
10451  10453  22 
10466  10466  48 
      ... 

OU résumé pour toutes la durée des actions dans une ligne. Est-il faisable avec une seule requête de base de données? (Sans créer de tables supplémentaires)

Répondre

1
select A1.ID_PPSTARTSTOPPOZ as Action_0, 
     A2.Action_1, 
     datediff (minute, A1.DATA ,A2.DATA) 

from STARTSTOP A1 
JOIN 
(
    select ID_PPSTARTSTOPPOZ as Action_1, 
     DATA, 
     (select max(ID_PPSTARTSTOPPOZ) 
      FROM STARTSTOP 
      where ID_PPSTARTSTOPPOZ<T.ID_PPSTARTSTOPPOZ 
       AND 
       ACTION=0) AS PREV_ACTION 
    from STARTSTOP T 
    where ACTION=1 

) A2 on A1.ID_PPSTARTSTOPPOZ=A2.PREV_ACTION 

where ACTION = 0 
order by A1.ID_PPSTARTSTOPPOZ 

DATEDIFF function

SQLFiddle Example for MSSQL but it has to work under Firebird too

+0

Merci. Cela fonctionne comme un charme. – zeno33

0

Cela pourrait se faire avec une seule sélection, mais algorithmiques EXECUTE BLOCK ferait beaucoup plus rapidement:

EXECUTE BLOCK 
    RETURNS (ACTION_1 INTEGER, ACTION_2 INTEGER, DURATION INTEGER) 
AS 
    DECLARE VARIABLE act INTEGER; 
    DECLARE VARIABLE act_id INTEGER; 
    DECLARE VARIABLE d TIMESTAMP = NULL; 
    DECLARE VARIABLE d1 TIMESTAMP = NULL; 
BEGIN 
    FOR 
    SELECT action, data, id_ppstartstoppoz 
    FROM startstop 
    ORDER BY data ASC 
    INTO :act, :d, :act_id 
    DO BEGIN 
    IF (:act = 0) THEN 
    BEGIN 
     d1 = :d; 
     action_1 = :act_id; 
    END ELSE 
    BEGIN 
     IF (NOT :d1 IS NULL) THEN 
     BEGIN 
     action_2 = :act_id; 
     duration = DATEDIFF(SECOND, :d1, :d); 
     SUSPEND; 
     d1 = NULL; 
     END 
    END 
    END 
END 
+0

Merci. Je vais essayer de le comparer avec la solution @valex – zeno33

0

Cette peut être fait de manière beaucoup plus simple

SELECT TAB1.ID AS ACTION_1,TAB2.ID AS ACTION_2, 
(TAB2.DATA_TS - TAB1.DATA_TS) MINUTE (4) TO SECOND(6) AS DURATION 
FROM 

(SELECT ID, DATA_TS , ROW_NUMBER() OVER (ORDER BY ID)AS RNUM FROM 
PROCESS WHERE ACTION=0 
)TAB1 

INNER JOIN 

(SELECT ID, DATA_TS , ROW_NUMBER() OVER (ORDER BY ID) AS RNUM FROM  
    PROCESS WHERE ACTION=1 
) TAB2 

ON (TAB1.RNUM=TAB2.RNUM) 
ORDER BY 1 

    ACTION_1 ACTION_2 DURATION 
    10,451 10,453  22:00.000000 
    10,466 10,467  48:00.000000 
    10,499 10,505  38:00.000000 
Questions connexes