Tengo una tabla que contiene una lista de objetos y qué requisitos cumplen. Luego tengo una tabla que contiene una lista de tareas y qué requisitos debe cumplir un objeto para poder realizar la tarea. Me gustaría consultar: dada una tarea, muéstrame todos los objetos que pueden realizar esa tarea, y dado un objeto, muéstrame todas las tareas que ese objeto puede realizar:
Ejemplo:
tabla task_req
tasks | reqs
-----------------
taskA | req1
taskA | req2
taskA | req3
taskB | req4
taskB | req5
taskB | req6
Entonces, esta tabla dice que para realizar la tarea A, se necesitan los requisitos req1, req2 y req3.
tabla obj_reqs
object | reqs
----------------
obj1 | req3
obj1 | req4
obj2 | req1
obj2 | req2
obj2 | req3
obj2 | req4
Entonces podría hacer la pregunta: ¿qué objetos pueden realizar la tarea A? La respuesta debería ser solo una fila:
tasks | objects
-------------------
taskA | object2
porque obj2 es el único que cumple los requisitos req1, req2, req3. Pregunta diferente: ¿qué objetos pueden realizar la tarea B? La respuesta es ninguna, porque no hay ningún objeto con los requisitos req4, req5, req6. La consulta debe ser lógica de manejo donde una tarea puede ser realizada por múltiples objetos devolviendo múltiples filas.
La pregunta es: ¿qué consulta hace esto?
Mi problema es que he logrado encontrar esa consulta, pero me parece demasiado complicado. La consulta básicamente hace: A) tabla de unión interna task_reqs con tabla obj_reqs, grupo por tareas y objs y cuenta requisitos distintos, B) selecciona tareas, cuenta (distinto (reqs)) del grupo task_reqs por tareas, C) unión interna A y B tanto en la tarea como en el recuento (distinto (requisitos)).
Seguramente hay una manera más fácil de hacer esta consulta, ¿verdad?
Estoy pegando debajo del código SQL para generar las tablas y mi consulta.
create table task_reqs (task varchar, req varchar);
create table obj_reqs (object varchar, req varchar);
insert into task_reqs values ('taskA', 'req1');
insert into task_reqs values ('taskA', 'req2');
insert into task_reqs values ('taskA', 'req3');
insert into task_reqs values ('taskB', 'req4');
insert into task_reqs values ('taskB', 'req5');
insert into task_reqs values ('taskB', 'req6');
insert into obj_reqs values ('obj1','req1');
insert into obj_reqs values ('obj1','req3');
insert into obj_reqs values ('obj2','req1');
insert into obj_reqs values ('obj2','req2');
insert into obj_reqs values ('obj2','req3');
insert into obj_reqs values ('obj2','req4');
y mi consulta:
select t.task,t.object,n.n_reqs
from (
select task,object,count(distinct(obj_reqs.req)) as n_reqs
from task_reqs
inner join obj_reqs on task_reqs.req=obj_reqs.req
group by task,object
) t
inner join (
select task,count(distinct(req)) as n_reqs
from task_reqs
group by task
) n
on n.n_reqs=t.n_reqs and n.task=t.task;
que devuelve:
task | object | n_reqs
-------+--------+--------
taskA | obj2 | 3
Seguramente hay una manera más simple.
distinct
es una función. El encerrar una columna utilizada entre paréntesis no cambiará nada y es inútil. es lo mismo quedistinct
count(distinct (a))
count(distinct a)
Respuestas:
Aquí hay una posible forma más simple:
Manifestación
fuente
Puede hacerlo con una combinación cruzada de las tablas:
Ver la demo .
Resultados:
fuente
Tu consulta parece estar bien. Creo que esto será complicado, sin importar cómo lo persigas, ya que los criterios de unión y / o dónde los predicados dependerán de ambos
req
y del recuento dereq
coincidencias.Las funciones de ventana pueden reducir el tiempo de procesamiento aquí, ya que puede eliminar un escaneo de tabla de su consulta original.
Si tiene un índice
obj_reqs.req
, creo que esta consulta también es bastante rápida. Si solo le interesa una tarea en particular, puede agregarla a laWHERE
cláusula en la subconsulta más interna (trqs
).SQLFiddle aquí
Invertir esta lógica funciona para la pregunta 2
SQLFiddle aquí
fuente