Pregunta

Estoy buscando una sola consulta que puede convertir la siguiente información en la tabla

name:time    :state
a   :10:00 AM:login
b   :10:05 AM:login
a   :10:06 AM:chatting
a   :10:08 AM:Idle
b   :10:11 AM:chatting
a   :10:10 AM:Logout
b   :10:12 AM:Logout

a algo como esto (dado el intervalo de tiempo de 10 AM a 10:15 de la mañana como a la consulta período)

name: State    :Duration
a   : chatting :2 Minutes 
a   : Idle     :2 Minutes
b   : chatting :1 Minute

Se puede hacer esto SÓLO con SQL?Estoy usando Informix versión 11.5

¿Fue útil?

Solución

Se puede hacer en una única instrucción SQL.Aquí está la prueba.

El programa de instalación

CREATE TEMP TABLE eventtable
(
    name CHAR(3) NOT NULL,
    time DATETIME HOUR TO MINUTE NOT NULL,
    state CHAR(8) NOT NULL
);

INSERT INTO eventtable(name, time, state) VALUES('a', '10:00', 'login');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:05', 'login');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:06', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:08', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:11', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:10', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:12', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:01', 'login');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:02', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:03', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:04', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:05', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:06', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:07', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:08', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:09', 'login');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:11', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:12', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:13', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:14', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:15', 'Logout');

Consulta correcto

Tenga en cuenta las condiciones.La tabla de resultados que se deben excluir los períodos entre 'login' y el primer evento de otra índole;además, se debe excluir el período entre 'Logout' y el próximo evento (presumiblemente un 'login').La auto-join entre la tabla de la nombre columna y, a continuación, el asimétrico de unirse en la tiempo columna (usando '<') garantiza que los eventos son en orden de tiempo.NO EXISTE sub-seleccione asegura que sólo adyacentes eventos son considerados.El uso de ENTRE Y en la sub-consulta es un error, ya que incluye los puntos finales y es crucial que r1.time y r2.time están excluidos de la gama;me tomó un par de minutos para encontrar el bug (la consulta se ejecutó, pero no devuelve filas, pero por qué?)!

SELECT r1.name, r1.state, r2.TIME - r1.TIME AS duration
    FROM eventtable r1, eventtable r2
    WHERE r1.name = r2.name
      AND r1.time < r2.time
      AND r1.state != 'login'
      AND r1.state != 'Logout'
      AND r1.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND r2.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND NOT EXISTS (SELECT 1 FROM eventtable r3
                            WHERE r3.time > r1.time AND r3.time < r2.time
                      AND r3.name = r1.name
                      AND r3.name = r2.name);

Esto produce la respuesta:

name state      duration
a    chatting   0:02
a    Idle       0:02
b    chatting   0:01

c    chatting   0:01
c    Idle       0:01
c    Idle       0:01
c    Idle       0:01
c    chatting   0:01
c    Idle       0:01
c    chatting   0:01
c    Idle       0:01

La 'duración' de valor es un INTERVALO de HORAS A MINUTOS;si desea un valor en cuestión de minutos, usted tiene que convertir con un elenco (utilizando 4 de la precisión para permitir intervalos de hasta 1440 minutos, o 1 día;los datos son ambiguos por más marcos de tiempo):

(r2.time - r1.time)::INTERVAL MINUTE(4) TO MINUTE

O:

CAST (r2.time - r1.time AS INTERVAL MINUTE(4) TO MINUTE)

IBM Informix Dynamic Server (IDS) tiene muy detallado notaciones para las constantes de tiempo.En SQL Estándar, puede utilizar el TIEMPO como el tipo y el TIEMPO '10:00:00', como un valor, pero los segundos serían necesarias en estricto estándar de SQL.Los IDENTIFICADORES de no proporcionar exacta de los tipos que la gente quiere - como DATETIME HORAS A MINUTOS.También le escribe el INTERVALO de MINUTOS(4) en SQL estándar;la 'MINUTO' debería ser opcional.

Consulta incorrecta

En mi comentario a Ray Hidayat la respuesta, me señaló que EXISTE la sub-consulta es necesaria para asegurar que los eventos bajo consideración son contiguos - no hay intervenir en eventos.Aquí la misma consulta con el inicio y el final de los tiempos agrega a la salida, y la cláusula EXISTS falta (y la "duración" se ha cambiado por 'lapso'):

SELECT r1.name, r1.state, r2.TIME - r1.TIME AS lapse,
       r1.time AS start, r2.time AS end
    FROM eventtable r1, eventtable r2
    WHERE r1.name = r2.name
      AND r1.time < r2.time
      AND r1.state != 'login'
      AND r1.state != 'Logout'
      AND r1.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND r2.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE;

Esto produce la respuesta:

name state     lapse start end
a    chatting   0:04 10:06 10:10
a    chatting   0:02 10:06 10:08
a    Idle       0:02 10:08 10:10
b    chatting   0:01 10:11 10:12
c    chatting   0:13 10:02 10:15
c    chatting   0:12 10:02 10:14
c    chatting   0:11 10:02 10:13
c    chatting   0:10 10:02 10:12
c    chatting   0:09 10:02 10:11
c    chatting   0:07 10:02 10:09
c    chatting   0:06 10:02 10:08
c    chatting   0:05 10:02 10:07
c    chatting   0:04 10:02 10:06
c    chatting   0:03 10:02 10:05
c    chatting   0:02 10:02 10:04
c    chatting   0:01 10:02 10:03
c    Idle       0:12 10:03 10:15
c    Idle       0:11 10:03 10:14
c    Idle       0:10 10:03 10:13
c    Idle       0:09 10:03 10:12
c    Idle       0:08 10:03 10:11
c    Idle       0:06 10:03 10:09
c    Idle       0:05 10:03 10:08
c    Idle       0:04 10:03 10:07
c    Idle       0:03 10:03 10:06
c    Idle       0:02 10:03 10:05
c    Idle       0:01 10:03 10:04
c    Idle       0:10 10:05 10:15
c    Idle       0:09 10:05 10:14
c    Idle       0:08 10:05 10:13
c    Idle       0:07 10:05 10:12
c    Idle       0:06 10:05 10:11
c    Idle       0:04 10:05 10:09
c    Idle       0:03 10:05 10:08
c    Idle       0:02 10:05 10:07
c    Idle       0:01 10:05 10:06
c    Idle       0:08 10:07 10:15
c    Idle       0:07 10:07 10:14
c    Idle       0:06 10:07 10:13
c    Idle       0:05 10:07 10:12
c    Idle       0:04 10:07 10:11
c    Idle       0:02 10:07 10:09
c    Idle       0:01 10:07 10:08
c    chatting   0:04 10:11 10:15
c    chatting   0:03 10:11 10:14
c    chatting   0:02 10:11 10:13
c    chatting   0:01 10:11 10:12
c    Idle       0:03 10:12 10:15
c    Idle       0:02 10:12 10:14
c    Idle       0:01 10:12 10:13
c    chatting   0:02 10:13 10:15
c    chatting   0:01 10:13 10:14
c    Idle       0:01 10:14 10:15

Esto muestra cómo cada elegibles fila de inicio para el usuario 'c' es emparejado con cada elegibles final de la fila, dando muchos falsos filas de datos.NO EXISTE una sub-consulta es un tema común cuando se trata con el tiempo basado en las consultas.Usted puede encontrar información acerca de estas operaciones en Snodgrass del "Tiempo de desarrollo de Aplicaciones Orientadas en SQL"(PDF disponible en línea en la URL), y en la Fecha, Darwen y Lorentzos "Temporal de los Datos y el Modelo Relacional".

Otros consejos

Estoy bastante seguro de que se puede hacer usando solo SQL, me llevará bastante tiempo encontrar una consulta para usted, la editaré cuando termine. Los pasos básicos que creo serían primero calcular la cantidad de tiempo que toma cada uno (hecho tomando cada entrada y uniéndola a la siguiente entrada y restando para encontrar la diferencia horaria), luego se obtendrá fácilmente un grupo simple por una cláusula con una suma en la forma que has descrito.

Editar: Aquí lo que se me ocurrió

SELECT l.userid, l.state, SUM(t.minutes) AS duration
FROM Log l 
INNER JOIN (
    SELECT l1.id, (l2.time - l1.time) AS minutes
    FROM Log l1, Log l2
    WHERE l2.time == ( 
        -- find the next entry --
        SELECT TOP 1 ls.time
        FROM Log ls
        WHERE ls.Time > l1.Time && ls.userid = l1.userid
        ORDER BY ls.Time
    )
) t ON l.id == t.id
GROUP BY l.userid, l.state
ORDER BY l.userid

Esto es semi-pseudocódigo, inventé todos los nombres de tablas y cosas, y no podrá restar una vez de otra, probablemente usará la función DATEDIFF. Además de eso, creo que eso es lo esencial. Creo que SQL es uno de los lenguajes más sorprendentes, puedes hacer casi cualquier cosa con poco código.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top