2011-04-24 20 views
7

Supongamos que estoy almacenando events asociado con users en una tabla de la siguiente manera (con dt de pie en la fecha y hora del evento):Consulta de secuencias de filas en SQL

| dt | user | event | 
| 1 | 1 | A | 
| 2 | 1 | D | 
| 3 | 1 | B | 
| 4 | 1 | C | 
| 5 | 1 | B | 
| 6 | 2 | B | 
| 7 | 2 | B | 
| 8 | 2 | A | 
| 9 | 2 | A | 
| 10 | 2 | C | 

De tal manera que podríamos decir:

  • usuario 1 tiene un evento de secuencia de ADBCB
  • usuario 2 tiene evento de secuencia BBAAC

Los tipos de preguntas que quisiera responder sobre estos usuarios son muy fáciles de expresar como expresiones regulares en las secuencias de eventos, p. "¿Qué usuarios tienen una secuencia de eventos que coincida con A. * B?" o "¿qué usuarios tienen una secuencia de eventos que coincida con A [^ C] * B [^ C] * D?" etc.

¿Cuál sería una buena técnica de SQL u operador que podría usar para responder consultas similares sobre esta estructura de tabla?

¿Hay alguna forma de generar eficiente/dinámicamente una tabla de user -to- event-sequence que luego se pueda consultar con expresiones regulares?

Actualmente estoy usando Postgres, pero tengo curiosidad por saber si alguno de los más grandes DBMS como SQLServer u Oracle también tienen operadores especializados para esto.

Respuesta

5

Con Postgres 9.x esto es realmente muy fácil:

select userid, 
     string_agg(event, '' order by dt) as event_sequence 
from events 
group by userid; 

Usando este resultado ahora se puede aplicar una expresión regular en la event_sequence:

select * 
from (
    select userid, 
     string_agg(event, '' order by dt) as event_sequence 
    from events 
    group by userid 
) t 
where event_sequence ~ 'A.*B' 

Con Postgres 8.x que necesita para encontrar un reemplazo para la función string_agg() (solo google para eso, hay muchos ejemplos) y necesita una sub-selección para asegurar que el ordenamiento del agregado como 8.x no admite un order by en un agregado función.

+0

Excelente, ¡gracias! – nicolaskruchten

+0

Para MySQL, 'GROUP_CONCAT' ofrece una solución similar a' string_agg'. – patrickmdnet

1

no estoy en una computadora para escribir código para esta respuesta, pero aquí es cómo iba a ir sobre una solución basada en expresiones regulares en SQL Server:

  1. generar una cadena desde el conjunto de resultados. Algo como http://blog.sqlauthority.com/2009/11/25/sql-server-comma-separated-values-csv-from-table-column/ debería funcionar si omite la coma
  2. Ejecute su coincidencia de RegEx con la cadena resultante. Por desgracia, SQL Server no proporciona esta funcionalidad de forma nativa, sin embargo, se puede utilizar una función CLR para este fin como se describe en http://www.ideaexcursion.com/2009/08/18/sql-server-regular-expression-clr-udf/

En última instancia, debe proporcionarle la funcionalidad de SQL Server que sus peticiones pregunta original, sin embargo, , si está analizando un conjunto de datos muy grande, esto podría ser bastante lento y puede haber mejores formas de lograr lo que está buscando.

+0

En SQL Server para ciertos tipos de tareas, esperaría que esta sea la forma más eficiente (especialmente porque no tiene una forma fácil en el momento de hacer referencia a la "próxima" fila debido a que no se implementó completamente la cláusula 'over'). Un ejemplo aquí http://stackoverflow.com/q/5743467/513811 –

1

Para Oracle (versión 11g R2):

Por casualidad, si está utilizando Oracle DB 11g R2, tome mirar listagg. El siguiente código debería funcionar, pero no lo he probado. El punto es: puedes usar listagg.

SQL> select user, 
    2   listagg(event, '') 
    3   within group (order by dt) events 
    4  from users 
    5 group by user 
    6 order by dt 
    7 /

    USER EVENTS 
--------- -------------------- 
1   ADBCB 
2   BBAAC 

En versiones anteriores puede hacerlo con la cláusula CONNECT BY. Más detalles en listagg.

+1

buen punto sobre el listagg, siempre olvido que Oracle finalmente agregó eso. Pero la sintaxis es 'listagg (event, '') dentro del grupo (ordenar por dt)' (la palabra clave within es obligatoria) –

+0

@horse_with_no_name: Muchas gracias por la corrección. He modificado el SQL. – Guru

Cuestiones relacionadas