Jump to content
Ruben Santos

Consulta dupla SQL na mesma tabela

Recommended Posts

Ruben Santos

Boa tarde,
Sou novo no fórum e tambem em programação SQL, no entanto não desisto de procurar soluções e tentar aprender cada vez mais e melhor.

Venho aqui pedir ajuda sobre o seguinte assunto:

y06ZJ.png


Estou trabalhando com Access e a tabela em questão apresenta as operações realizadas (tempo de trabalho) no caso de ter interrupção, a interrupção tem a durabilidade desde o fim da operação até ao inicio da proxima operação

Então sobre esta tabela, faço a seguinte pesquisa para saber, quantas interrupções tenho e a que horas interromperam:

Dei o nome de "Inicio_interrupcoes"

SELECT dbo_opr.cod_gpt, dbo_opr.cod_pt, dbo_opr.un_pt, dbo_opr.data_ini, dbo_opr.data_fim, dbo_opr.cod_interrup, *
FROM dbo_opr
WHERE (((dbo_opr.cod_interrup) Is Not Null));

Este comando, executa corretamente, retornando todos os registos em que cod.interrup seja não nulo.

Seguindo agora o código onde preciso milagrosamente de ajuda:

SELECT inicio_interrupcoes.cod_gpt, inicio_interrupcoes.cod_pt, inicio_interrupcoes.un_pt, inicio_interrupcoes.data_fim, inicio_interrupcoes.cod_interrup
FROM dbo_opr INNER JOIN inicio_interrupcoes ON (dbo_opr.cod_gpt = inicio_interrupcoes.cod_gpt) AND (dbo_opr.cod_pt = inicio_interrupcoes.cod_pt)
GROUP BY inicio_interrupcoes.cod_gpt, inicio_interrupcoes.cod_pt, inicio_interrupcoes.un_pt, inicio_interrupcoes.data_fim, inicio_interrupcoes.cod_interrup, dbo_opr.data_ini
HAVING (((dbo_opr.data_ini)>[inicio_interrupcoes].[data_fim]));


Passando agora a explicar o que preciso:

Na primeira consulta "Inicio_Interrupcoes" pesquiso todas os registos que contenham o campo "cod_interrup" preenchido.

Na segunda consulta respeitando os campos "cod_gpt" e "cod_pt", pretendo obter a data de inicio da proxima operação que nesta consulta representa o fim da interrupção.

Segue exemplo básico:
considerem linha 2 e linha 3 da imagem:
Linha 2 representa produção -> Inicio = 10/01/2019 08:21:13
                               Fim = 10/01/2019 12:54:30

Como o registo tem "Cod_interrup" considero que "10/01/2019 12:54:30" representa o inicio da interrupcão e o proximo inicio neste caso "10/01/2019 14:04:53" será o fim da interrupção e inicio da Produção.


Alguem me pode dar uma força neste assunto?

Obrigado, ficarei muito grato.

Share this post


Link to post
Share on other sites
Ruben Santos

Precisava mesmo de ajuda neste tópico, estou com imensas dificuldades e sem nenhuma luz.

Share this post


Link to post
Share on other sites
Ricardo Voigt

Olá,

primeira dúvida, neste teu caso, pode haver mais de uma interrupção? ou no máximo uma interrupção ?

Minha primeira sugestão seria criar uma coluna "chave primária" numerada e sequencial.

Assim, eu também tentaria transformar a coluna "cod_interrup" em uma "chave estrangeira", cujo valor apontaria para a "próxima linha lógica" da mesma tabela...

Algo assim:

cod	data_ini		data_fim			cod_interrup
1	09/01/2019 15:48	09/01/2019 16:41	null
2	10/01/2019 08:21	10/01/2019 12:54	3
3	10/01/2019 14:04	10/01/2019 16:48	null
4	11/01/2019 08:12	11/01/2019 12:52	5
5	11/01/2019 14:14	11/01/2019 16:50	null
6	14/01/2019 08:43	14/01/2019 12:57	7
7	14/01/2019 14:04	null			null

Quanto ao comando select que busca os dados (não tenho certeza quanto ao Access pois não utilizo) acho que seria necessário fazer "left join" para buscar a provável "data_ini"...

O comando select ficaria mais ou menos assim...

select a_ini.data_ini, a_fim.data_ini, a_fim.data_fim
from dbo_opr a_fim
 left join dbo_opr a_ini on (a_ini.cod_interrup = a_fim.cod)
where a_fim.data_fim is not null
  and a_fim.cod_interrup is null

Assim:

existe a certeza de quando uma tarefa termina (a_fim) com a condição "a_fim.cod_interrup is null";

e se a condição "a_ini.data_ini is null" significa que NÃO houve interrupção.

E abaixo, o resultado que eu obtive aqui testando/simulando no MYSQL:

a_ini.data_ini		a_fim.data_ini		a_fim.data_fim
NULL				09/01/2019 15:48	09/01/2019 16:41
10/01/2019 08:21	10/01/2019 14:04	10/01/2019 16:48
11/01/2019 08:12	11/01/2019 14:14	11/01/2019 16:50

Espero ter ajudado... 

Atenciosamente,

Ricardo

Share this post


Link to post
Share on other sites
Cerzedelo

Em  primeiro lugar, o concelho que dou, é em vez de criar uma query tao complexa, ir fazendo por partes.

Em segundo, não percebi, o porque de um inner join, quando só está a fazer select a campos de uma tabela.

Em terceiro, o Access tinha uma ferramenta gráfica para fazer as querys, e depois apresentava os comandos em sql. 

O que provavelmente precisará e de fazer uma subquery, i. e.,  um select dentro de outro select.. Ver http://www.criarweb.com/artigos/subconsultas-em-sql.html

Share this post


Link to post
Share on other sites
Ruben Santos

Boa tarde Ricardo Voigt e Cerzedelo,

Obrigado pelas respostas, em primeiro lugar agradeço imenso ao Ricardo pelo exemplo, infelizmente não é o que procuro.

E respondendo ás questões: Sim, terá várias interrupções.

Agradeço também ao Cerzedelo, também pela resposta, esta penso aproximar-se bastante do que preciso.

Passando a explicar:

Considerem a seguinte tabela:

Tabela "dbo_opr"

h4RGgCz.png

Ver Melhor

 

Considerem que esta tabela é os registos de produção.

Se olharem para a linha 2 sei que a produção é desde "10/01/2019 08:21:13" até "10/01/2019 12:54:30" ao finalizar colocou "Cod_Interrup"

E sei que a próxima produção começou em "10/01/2019 14:04:53" independentemente do final desta próxima operação, já consigo saber quanto tempo durou a minha interrupção.

Preciso de obter o tempo de interrupção da seguinte maneira: Data_fim (registo 2) - Data_Ini (registo 3)

Não preciso de obter o resultado para já, apenas de listar as datas.

Tenho uma consulta que me retorna os registos que tenham "Cod_Interrup"

SELECT dbo_opr.cod_gpt, dbo_opr.cod_pt, dbo_opr.un_pt, dbo_opr.data_ini, dbo_opr.data_fim, dbo_opr.cod_interrup
FROM dbo_opr
WHERE (((dbo_opr.cod_interrup) Is Not Null));
 

Após esta consulta tenho todos os registos que contenham "Cod_Interrup" guardada na consulta "Inicio_Interrup"

O resultado será mais ou menos isto:

MEjRpzw.png

Ver Melhor

Faltando agora a segunda consulta em que tenho imensas dificuldades pelo seguinte:

Pretendo fazer uma consulta á mesma tabela para me retornar o campo "Data_Ini"

Neste caso a consulta tem as seguintes condições:

dbo_opr.cod_gpt = inicio_Interrup.cod_gpt

dbo_opr.cod_pt = inicio_Interrup.cod_pt

e será a primeira "Data_Ini" > "Data_fim"

 

Se considerarmos a tabela Inicial o resultado para a consulta que pretendo será o seguinte:

Data_Fim = "10/01/2019 12:54:30" (linha2)       <- Na minha consulta representa o inicio da interrupção porque tem o código "Cod_Interrup"

Data_Ini = "10/01/2019 14:04:53" (linha3)         <- Na minha consulta representa o fim da interrupção porque voltou a entrar em funcionamento.

h4RGgCz.png

Ver Melhor

Penso que a solução mais próxima do que preciso, será uma subconsulta, porém não estou a conseguir fazer.

Agradeço desde já a ajuda e disponibilidade de todos

Share this post


Link to post
Share on other sites
Ruben Santos

Boa tarde,

Quase que já consegui obter o resultado que pretendo, contudo falta apenas limitar os resultados:

SELECT DISTINCTROW dbo_opr.num_ordem, dbo_opr.num_operario, dbo_opr.cod_gpt, dbo_opr.cod_pt, dbo_opr.un_pt, dbo_opr.data_fim, dbo_opr.cod_interrup, dbo_opr_1.data_ini
FROM dbo_opr LEFT JOIN dbo_opr AS dbo_opr_1 ON (dbo_opr.num_ordem = dbo_opr_1.num_ordem) AND (dbo_opr.num_oper = dbo_opr_1.num_oper) AND (dbo_opr.cod_pt = dbo_opr_1.cod_pt) AND (dbo_opr.cod_gpt = dbo_opr_1.cod_gpt)
GROUP BY dbo_opr.num_ordem, dbo_opr.num_operario, dbo_opr.cod_gpt, dbo_opr.cod_pt, dbo_opr.un_pt, dbo_opr.data_fim, dbo_opr.cod_interrup, dbo_opr_1.data_ini
HAVING (((dbo_opr.cod_interrup) Is Not Null) AND ((dbo_opr_1.data_ini)>[dbo_opr].[data_fim]))
ORDER BY dbo_opr.data_fim;

O resultado é o seguinte:

BEr7xFN.png

Ver Melhor

Preciso agora de ajuda para limitar o campo "Data_ini" a apenas 1 resultado superior a "Data_fim"

Está a retornar todos os registos correspondentes, contudo preciso que me retorne apenas o primeiro.

Obrigado, Rúben Santos

Share this post


Link to post
Share on other sites
Joaanaa.93

Exprimenta assim:

Select Top 1 From (SELECT DISTINCTROW dbo_opr.num_ordem, dbo_opr.num_operario, dbo_opr.cod_gpt, dbo_opr.cod_pt, dbo_opr.un_pt, dbo_opr.data_fim, dbo_opr.cod_interrup, dbo_opr_1.data_ini FROM dbo_opr LEFT JOIN dbo_opr AS dbo_opr_1 ON (dbo_opr.num_ordem = dbo_opr_1.num_ordem) AND (dbo_opr.num_oper = dbo_opr_1.num_oper) AND (dbo_opr.cod_pt = dbo_opr_1.cod_pt) AND (dbo_opr.cod_gpt = dbo_opr_1.cod_gpt) GROUP BY dbo_opr.num_ordem, dbo_opr.num_operario, dbo_opr.cod_gpt, dbo_opr.cod_pt, dbo_opr.un_pt, dbo_opr.data_fim, dbo_opr.cod_interrup, dbo_opr_1.data_ini HAVING (((dbo_opr.cod_interrup) Is Not Null) AND ((dbo_opr_1.data_ini)>[dbo_opr].[data_fim])) ORDER BY dbo_opr.data_fim) Where Data_ini > Data:fim;

Edited by Joaanaa.93

Share this post


Link to post
Share on other sites
Ruben Santos

Boa Tarde Joana,

Já testei e dá erro na execução do primeiro Select, mesmo assim penso que isso limitaria toda a consulta ao primeiro registo, ou seja apresentaria apenas o primeiro registo de toda a consulta, preciso limitar os dados que seleciono da tabela ALIAS "dbo_opr_1".

 

Obrigado pela tentativa de ajuda :D

Share this post


Link to post
Share on other sites
Ruben Santos

Será que a solução passa por converter o meu código em 1 select + (select limit 1)?

 

Ou seja Um select limit 1 dentro de outro select?

Será que alguem me pode ajudar a converter?

Share this post


Link to post
Share on other sites
Joaanaa.93
16 horas atrás, Ruben Santos disse:

Boa Tarde Joana,

Já testei e dá erro na execução do primeiro Select, mesmo assim penso que isso limitaria toda a consulta ao primeiro registo, ou seja apresentaria apenas o primeiro registo de toda a consulta, preciso limitar os dados que seleciono da tabela ALIAS "dbo_opr_1".

 

Obrigado pela tentativa de ajuda :D

Mas o limite não é quando a data de inicio é superior a data de fim?

Eu não testei, mete o erro aqui

Edited by Joaanaa.93

Share this post


Link to post
Share on other sites
Ruben Santos

Boas,

 

Sim, já consegui resolver com a criação de um ALIAS, ficou mais ou menos assim:

Inicio_Interrupcoes    -> Busca todas as operações que contenham "cod_interrup"

SELECT dbo_opr.tipo_ordem, dbo_opr.num_ordem, dbo_opr.num_oper, dbo_opr.num_operario, dbo_opr.cod_gpt, dbo_opr.cod_pt, dbo_opr.un_pt, dbo_opr.data_fim, dbo_opr.cod_interrup
FROM dbo_opr
WHERE (((dbo_opr.cod_interrup) Is Not Null));

Interrupcoes

SELECT inicio_interrupcoes.tipo_ordem, inicio_interrupcoes.num_ordem, inicio_interrupcoes.num_oper, inicio_interrupcoes.num_operario, inicio_interrupcoes.cod_gpt, inicio_interrupcoes.cod_pt, inicio_interrupcoes.un_pt, inicio_interrupcoes.data_fim, inicio_interrupcoes.cod_interrup, (SELECT top 1 operacoes.data_ini FROM dbo_opr as operacoes WHERE (operacoes.cod_gpt=inicio_interrupcoes.cod_gpt) AND (operacoes.cod_pt=inicio_interrupcoes.cod_pt) AND (operacoes.un_pt=inicio_interrupcoes.un_pt) AND (operacoes.data_ini > inicio_interrupcoes.data_fim);) AS data_ini
FROM inicio_interrupcoes
ORDER BY inicio_interrupcoes.data_fim;

Isto faz o restante código que busca a primeira data_ini que seja superior á data_fim.

 

Obrigado pela ajuda de todos.

Podem marcar o tópico como resolvido, no entanto podem deixar a solução para que possa audar outras pessoas com a mesma dificuldade.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.