Eu tenho uma tabela que contém uma lista de objetos e quais requisitos eles atendem. Então, eu tenho uma tabela que contém uma lista de tarefas e quais requisitos um objeto deve atender para poder executar a tarefa. Gostaria de consultar: dada uma tarefa, mostre-me todos os objetos que podem executar essa tarefa e, dado um objeto, mostre-me todas as tarefas que esse objeto pode executar:
Exemplo:
tabela task_req
tasks | reqs
-----------------
taskA | req1
taskA | req2
taskA | req3
taskB | req4
taskB | req5
taskB | req6
Portanto, esta tabela diz que, para executar a tarefa A, são necessários os requisitos req1, req2 e req3.
tabela obj_reqs
object | reqs
----------------
obj1 | req3
obj1 | req4
obj2 | req1
obj2 | req2
obj2 | req3
obj2 | req4
Para que eu pudesse fazer a pergunta: quais objetos podem executar a tarefaA? A resposta deve ser apenas uma linha:
tasks | objects
-------------------
taskA | object2
porque obj2 é o único que atende aos requisitos req1, req2, req3. Pergunta diferente: quais objetos podem executar a tarefa B? A resposta é nenhuma, porque não há objeto com os requisitos req4, req5, req6. A consulta deve lidar com lógica em que uma tarefa pode ser executada por vários objetos, retornando várias linhas.
A questão é: qual consulta faz isso?
Meu problema é que consegui encontrar essa consulta, mas me parece muito complicado. A consulta basicamente faz: A) junção interna da tabela task_reqs com a tabela obj_reqs, agrupa por tarefas e objs e conta requisitos distintos, B) seleciona tarefas, conta (distintas (reqs)) do task_reqs agrupa por tarefas, C) junta interna A e B na tarefa e na contagem (distinto (reqs)).
Certamente, existe uma maneira mais fácil de fazer essa consulta, certo?
Estou colando abaixo do código SQL para gerar as tabelas e minha 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');
e minha 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 retorna:
task | object | n_reqs
-------+--------+--------
taskA | obj2 | 3
Certamente há uma maneira mais simples.
distinct
é uma função. O fechamento de uma coluna usada entre parênteses não muda nada e é inútil. é o mesmo quedistinct
count(distinct (a))
count(distinct a)
Respostas:
Aqui está uma maneira mais simples possível:
Demo
fonte
Você pode fazer isso com uma junção cruzada das tabelas:
Veja a demonstração .
Resultados:
fonte
Sua consulta parece boa. Acredito que isso seja complicado, não importa como você o siga, pois os critérios de junção e / ou onde os predicados dependerão de ambos
req
e da contagem dereq
correspondências.As funções da janela podem reduzir o tempo de processamento aqui, pois você pode eliminar uma varredura de tabela da sua consulta original.
Se você tiver um índice
obj_reqs.req
, acho que você também achará essa consulta bastante rápida. Se você estiver interessado em apenas uma tarefa específica, poderá adicioná-la àWHERE
cláusula na subconsulta mais interna (trqs
).SQLFiddle aqui
Inverter essa lógica funciona para a pergunta 2
SQLFiddle aqui
fonte