Jump to content
  • 0
Didyo

LEFT JOIN com operador IN (1,2,4,5,7)

Question

Olá pessoal, não sei se é possível mas minha ideia seria usar o operador IN dentro de um JOIN 
substituindo o "=".
Ex: Teria uma tabela itens_cardapio (car_id, car_nome, car_bebidas)
e outra tabela > bebidas (b_id, b_nome)

Sei que poderia relaciona n:m tendo uma tabela tipo itens_cardapio_has_bebidas (fk_car_id, fk_b_id) porém queria fazer diferente pois para o que quero isso geraria muitas linhas na tabela de junção.

Gostaria que o campo car_bebidas na 1ª tabela armazenasse os ids das bebidas da 2ª tabela. Ex. car_bebidas=1,2,5,6,9,11
e na consulta ficaria algo do tipo:
SELECT i.* , GROUP_CONCAT(b.b_nome) FROM itens_cardapio i 
INNER JOIN bebidas b ON (b.b_id IN i.car_bebidas)

Tentei também algo tipo 

SELECT i.* , (SELECT b.nome FROM bebidas b WHERE b.b_id IN i.car_bebidas) FROM itens_cardapio i 

Usei algumas variação com GROUP BY e GROUP_CONCAT,...

Consegui obter resultados como:
- a primeira bebida de cada item do cardápio
- repetir várias vezes cada bebida por item,
e outros, mas nenhum 100% correto.

Se no IN usar os números dos ids das bebidas manualmente, ao invés de puxar de um campo, ele busca as bebidas pedidas,
porém não fica dinâmico, pois é sempre os mesmos números de modo a todos itens do cardápio ficaram com (coca-cola,sprite,fanta) por exemplo.

Se tiverem alguma ideia agradeço.

  • +1 1

Share this post


Link to post
Share on other sites

3 answers to this question

Recommended Posts

  • 0

Olá pessoal, consegui solucionar o problema de 2 formas.

Minha ideia era relacionar 2 tabelas de um cardápio, exemplo (itens e bebidas) sem usar relacionamento n:m, mas armazenando os ids das bebidas em um campo "lista_bebidas".

 

Para quem desejar,  ao invés de usar o operador IN no JOIN ON,
basta usar o FIND_IN_SET com GROUP_CONCAT e GROUP BY
para agrupar os resultados por linha.

 

Tabela cardapio_itens (* apenas demonstrativo)

id  ||    item_nome    ||   lista_bebidas 

1   ||     refri 300ml    ||  1,2,4,5

2   ||     refri 600ml    ||  2,3,5

 

Tabela cardapio_bebidas (* apenas demonstrativo)

 id ||    nome_bebida  

1   ||   cola

2   ||   guaraná

3   ||   uva

4   ||   laranja

5   ||   limão

 

Solução 1 - com uso de JOIN: (minha preferida)

SELECT i.*, GROUP_CONCAT(b.nome_bebida) as bebidas FROM cardapio_itens i 

LEFT JOIN cardapio_bebidas b ON FIND_IN_SET(b.id, i.lista_bebidas) 

GROUP BY i.id       

 

Resultado:

1   ||    refri 300ml    ||     cola, guaraná, laranja, limão

2   ||    refri 600ml    ||     guaraná, uva, limão  

 

Solução 2 - com uso de Subquery: 

SELECT i.*, (SELECT GROUP_CONCAT(b.nome_bebida) as bebidas FROM cardapio_bebidas b WHERE  FIND_IN_SET(b.id, i.lista_bebidas)  ORDER BY b.nome_bebida ASC)   FROM cardapio_itens i 

 

Essa escolha foi para evitar um grande número de linhas em uma tabela de ligação n:m, devido a serem vários restaurantes e bares com várias bebidas em tamanhos diferentes.

Sei que para uma questão de integridade,... a melhor opção seria a terceira tabela n:m. Se o esperado fosse apenas alguns milhares de linhas até usaria n:m com uma tabela de junção itens_has_bebidas.

 

Obrigado a todos

Share this post


Link to post
Share on other sites
  • 0

 

lista_bebidas  passou a ser uma chave estrangeira?

 

Se você deletar um item como limão por exemplo isso seria fácil de atualizar em todos os registros de refri na tabela cardapio_itens ?

 

 

Share this post


Link to post
Share on other sites
  • 0
4 horas atrás, Bergs disse:

 

lista_bebidas  passou a ser uma chave estrangeira?

 

Se você deletar um item como limão por exemplo isso seria fácil de atualizar em todos os registros de refri na tabela cardapio_itens ?

 

 

Olá Bergs, nesse caso específico não usei como chave estrangeira. A necessidade e objetivo são outros.
Sei que se usa-se n:m seria mais prático e fácil de garantir a integridade.  

 

No exemplo que usei, é claro que se limão tiver escrito errado (lemãoo) na tabela cardapio_bebidas e for corrigido (UPDATE),
automaticamente a correção afetará todas as linhas que tenham limão em cardapio_itens.
pois nessa tabela, embora em um único campo, estão armazenados apenas os IDs das bebidas.

 

Também seria importante cuidar para não permitir que limão seja removido da tabela cardapio_bebidas 
caso esteja em alguma linha em cardapio_itens.

Poderia usar uma TRIGGER com uma validação antes de a linha ser removida (BEFORE DELETE).

Use um campo (quantidade) para controlar quantos itens usam a bebida limão e só permita que seja removida caso a quantidade seja 0;

 

Se desejar que quando nenhum cliente possuir mais a bebida limão,
a mesma seja removida da lista em cardapio_bebidas
poderia usar um campo quantidade (qnt) na tabela cardapio_bebidas
e usar UPDATE quando a bebida é inserida ou removida em cardapio_itens.

Depois, se a quantidade for 0, você pode remover a bebida da lista.


Para otimizar esses processos poderia usar TRIGGER no UPDATE da tabela cardapio_bebidas, 
onde, quando qnt=0 , DELETE. 

 

Na situação que estou usando, em (cardapio_bebidas) um usuário não poderá excluir uma bebida (exemplo: limão),

pois a mesma poderá estar sendo usada por outros restaurantes e bares.

Esta tabela apenas armazena todas opções disponíveis de bebidas

sendo que o usuário pode apenas incluir novas bebidas, sendo que cada bebida é única UNIQUE.

 

No entanto o usuário pode remover a bebida limão de sua lista de bebidas (cola, limão, laranja)  que está armazenada apenas os ids (1,3,4) das mesmas em um campo na tabela cardapio_itens.  Mas lembrando, limão não será removido da tabela cardapio_bebidas pois outros usuários poderão ter essa bebida.

 

No meu caso não deverá haver a necessidade de excluir uma bebida se a quantidade for 0,
apenas se ela não existir ou se o nome estiver escrito errado. 

 

Isso porque serão armazenadas as principais marcas com suas variações (coca-cola, pepsi, coca-cola zero,...)  em torno de 40 no máximo 60 registros 
e no caso das demais marcas serão armazenadas apenas os sabores (limão, guaraná, limão zero, laranja,...) em torno de mais uns 50 registros. Total uns 100 registros apenas. 

 

Mesmo se colocar todos refrigerantes com marca e sabor  seria no máximo 300 a 400 registros. 

Vamos supor que dê 5 ou 10 Mil registros incluindo cervejas, vinhos, espumantes,...  
Não acredito que manter tais registro apenas para consulta irá prejudicar muito o banco de dados pois usam indÍces (PRIMARI KEY).

 

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

  • Similar Content

    • By MarcosxEduardo
      Olá.
      Eu instalei um site na minha hospedagem.
      Criei a DB e o usuário, dando todas as permissões e conectei essa DB ao site.
       
      Mas quando vou entrar aparece a seguinte mensagem:
      Fatal error: Call to undefined function mysqli_connect() in /home2/public_html/database/DB.php on line 34
       
      alguém sabe que possa ser ?
       
    • By Rogério Orlando
      Na SQL abaixo, quando consulto as tabelas, os registros se repetem, apresentando mais do que realmente existem.
      Alguém pode auxiliar no que está errado ou o que falta para que a select retorne apenas um registro para cada documento?
      Esclareço que todas as tabelas tem um campo "documento", porém ele não é chave e no retorno trouxe todos os campos de todas as tabelas e não apenas as dá SQL:
       
       
      select so01.documento,so01.digito,so01.nome,so01.regional,so01.situacao,so01.observacao,so01.n_spprev,so01.averbacao, so02.endereco, so02.numero, so02.bairro,so02.cidade,so02.cep,so02.estado,so02.aniversario, so03.rg, so03.cpf, so03.email, so04.estado_civil, so04.agencia,so04.dg_agencia,so04.conta,so04.dg_conta,so04.banco,so04.ddd,so04.telefone,so04.nascimento, so04.admissao,so04.demissao_seg,so04.admor,so04.ddd_cel,so04.celular from so03 inner join so01 ON so01.documento= so03.documento inner join so02 ON so02.documento= so03.documento inner join so04 ON so04.documento=so03.documento where so01.documento="68" and so01.digito="0"  
       
    • By Camilavip
      Queria saber como fazer esse select e quando eu trazer um estado ele já puxa as cidades contidos nele, e ao escolher a cidade ele trazer os bairros. Consegui pela internet mas só com estados e cidades. no caso em 2 níveis, e eu precisaria em 3, faço pelo mysqli
       
      Em estados no banco está assim
      CREATE TABLE `estados` ( `id_estado` int(10) NOT NULL, `estado` varchar(30) NOT NULL ) ENGINE=Aria DEFAULT CHARSET=latin1; -- -- Extraindo dados da tabela `estados` -- INSERT INTO `estados` (`id_estado`, `estado`) VALUES (1, 'Rio de Janeiro'), (2, 'Minas Gerais'); Cidades
      CREATE TABLE `cidades` ( `id_cidade` int(10) NOT NULL, `id_estado` int(10) NOT NULL, `cidade` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Extraindo dados da tabela `cidades` -- INSERT INTO `cidades` (`id_cidade`, `id_estado`, `cidade`) VALUES (1, 1, 'Rio de Janeiro'), (2, 2, 'Belo Horizonte'); E bairros
      CREATE TABLE `bairros` ( `id_bairro` int(10) NOT NULL, `id_cidade` int(10) NOT NULL, `bairro` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Extraindo dados da tabela `bairros` -- INSERT INTO `bairros` (`id_bairro`, `id_cidade`, `bairro`) VALUES (1, 1, 'Centro'), (2, 1, 'Tijuca'), (3, 1, 'Leblon'), (4, 2, 'Pampulha');  
    • By danilo759
      Estou com uma dúvida, em uma tabelinha é cadastrado a data em uma coluna e a hora em outra coluna, então para "juntar" podemos usar CONCAT() no SELECT. Tudo certo...
       
      SELECT id, CONCAT(data_ini, ' ', hora_ini) as inicio FROM tabela

      Retorna como esperado:

       

      Minha dúvida é, se eu quiser exibir o horário de término para ficar assim como seria a consulta? Lembrando que não existe as colunas data_final e horario_final.

      2020-09-13 03:00:00 2020-09-13 04:00:00
      2020-09-13 04:00:00 2020-09-13 05:00:00
      2020-09-13 05:00:00 ....
    • By slaoxx
      Não conseguir obter êxito, minha sintaxe foi a seguinte:
       
      CREATE FUNCTION precomed ()
      RETURNS decimal
      SELECT AVG(preco_cd);
       
      SELECT precomed ();
       
×

Important Information

Ao usar o fórum, você concorda com nossos Terms of Use.