TransWikia.com

Problema consultas avançadas MYSQL

Stack Overflow em Português Asked by INOVAARTE TECNOLOGIA on December 11, 2021

Então, estou com um dúvida, de como fazer uma consulta relacionadas entre 3 tabelas, sendo:

Tabela 1:

Nome: tb_os    
Campos: id_os, id_cliente, valor_os    

Tabela 2:

Nome: tb_clientes    
Campos: id_cliente, endereco_cliente, tel_cliente


Tabela 3:

Nome: tb_status_os    
Campos: id_status_os, id_os, status_os

A tabela de número 3, conterá pelo menos, 3 status amarrados a uma os, podendo ser: Aberto, Bancada, Liberado.

Qual a dúvida?

Preciso fazer uma consulta relacionando as 3 tabelas, porém, por conta da tabela tb_status_os, será retornado para cada consulta 3 linhas ou registros, o que preciso é agrupar em uma linha para cada O.S. (tabela 1), sendo que o resultado trazido da tabela 3, seja somente o último, sendo os status atual.

Tentei de inúmeras formas, segue a que cheguei mais próximo:

SELECT * FROM tb_os AS a

INNER JOIN tb_clientes AS b USING(id_os)

INNER JOIN tb_status_os AS c ON  c.ids_os =

(

    SELECT MAX(id_os) FROM tb_status_os

    ORDER BY id_status_os DESC

)

GROUP BY a.id_os;

Retorna os registros agrupados corretamente, porém não retorna o último registro da tabela 3 ( ex.: Liberado), para cada 1 da tabela 1, retorna sempre o primeiro da tabela 3 (ex.: Aberto).

Poderiam me ajudar neste sentido?

Obrigado!

2 Answers

Boa parceiro, tem uma forma que bolei aqui para outras situações que deve servir para a sua :)

usa group_concat e poe um order by id desc, e usa substring_index para pegar o primeiro registro :D O pulo do gato é isso aqui: SUBSTRING_INDEX(GROUP_CONCAT(status_os order by id_status_os desc),',',1)

SELECT 
a.*, 
b.*,
SUBSTRING_INDEX(GROUP_CONCAT(status_os order by id_status_os desc),',',1) as status_atual
FROM tb_os AS a
INNER JOIN tb_clientes AS b USING(id_cliente)
INNER JOIN tb_status_os AS c ON  USING(c.ids_os) 
GROUP BY a.id_os;

Answered by Allan de Sá on December 11, 2021

Para solucionar esse tipo de problema de uma forma clara é necessário realizar o cruzamento com a tabela status_os duas vezes, porque?

Na primeira etapa você irá trazer todos os campos e trazer o MAX(cd_status) nessa etapa se você já trouxer a descrição o GROUP BY não irá funcionar:

  SELECT a.id_os, a.id_cliente, cli.endereco_cliente, cli.tel_cliente,
  a.valor_os, MAX(sta.id_status_os) AS cd_ultimo_status

  FROM tb_os AS os

  INNER JOIN tb_clientes AS cli
    ON cli.id_cliente = os.id_cliente

  INNER JOIN tb_status_os AS sta
    ON sta.id_os = os.id_os

  GROUP BY a.id_os, a.id_cliente, cli.endereco_cliente, cli.tel_cliente,
  a.valor_os

Depois disso utilize o conceito de SUBSELECT (sub-consulta) para cruzar novamente com a tabela status_os somente para trazer a descrição da do status os:

SELECT res.* sta_desc.status_os
FROM (SELECT a.id_os, a.id_cliente, cli.endereco_cliente, cli.tel_cliente,
      a.valor_os, MAX(sta.id_status_os) AS cd_ultimo_status

      FROM tb_os AS os

      INNER JOIN tb_clientes AS cli
        ON cli.id_cliente = os.id_cliente

      INNER JOIN tb_status_os AS sta
        ON sta.id_os = os.id_os

      GROUP BY a.id_os, a.id_cliente, cli.endereco_cliente, cli.tel_cliente,
      a.valor_os
      
) res

INNER JOIN tb_status_os AS sta_desc
        ON sta_desc.id_os = res.id_os

Simulei seu caso de maneira simples para você entender melhor o conceito:

SELECT tot.*, sta.status

FROM (
      SELECT res.cd_os, MAX(cd_status) AS cd_status
      FROM (SELECT 1 as cd_os, 1 AS cd_status, 'aberto' AS status
            FROM DUAL 
            UNION ALL
            SELECT 1 as cd_os, 2 AS cd_status, 'fechado' AS status
            FROM DUAL ) res
      GROUP BY res.cd_os) tot


INNER JOIN (SELECT 1 AS cd_status, 'aberto' AS status
            FROM DUAL 
            UNION ALL
            SELECT 2 AS cd_status, 'fechado' AS status
            FROM DUAL) sta
            
ON sta.cd_status = tot.cd_status

No primeiro SELECT traz os dois valores, no segundo eu trago o MAX(cd_status), crio um SUBSELECT e depois cruzo com a tabela sta para trazer a descrição.

Obs.: Sempre que criar um SUBSELECT que precise cruzar a mesma tabela varias vezes, utilize apelidos diferentes para a "mesma" tabela para evitar conflitos.

Answered by Heitor Scalabrini on December 11, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP