AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 71916
Accepted
brycemcd
brycemcd
Asked: 2014-07-20 17:42:13 +0800 CST2014-07-20 17:42:13 +0800 CST 2014-07-20 17:42:13 +0800 CST

Como fazer uma junção interna de algumas tabelas e uma junção externa de outras?

  • 772

Tenho certeza de que ficarei envergonhado com a resposta final, mas estive pesquisando e batendo minha cabeça contra a parede e não consigo descobrir.

Eu tenho quatro tabelas descritas abaixo. Estou tentando obter a consulta que mostra todos os produtos relacionados aos usuários (através da user_productstabela) E todas as categorias.

Definições de tabela

CREATE TEMPORARY TABLE categories (
   id INT PRIMARY KEY NOT NULL
   , cat_name TEXT
 );

 CREATE TEMPORARY TABLE products (
   id INT PRIMARY KEY NOT NULL
   , category_id INT
   , prod_name TEXT
 );

 CREATE TEMPORARY TABLE users (
   id INT PRIMARY KEY NOT NULL
   , user_name TEXT
 );

 CREATE TEMPORARY TABLE user_products (
   id INT PRIMARY KEY NOT NULL
   , product_id INT
   , user_id INT
   , quantity INT
 );      

instruções INSERT

INSERT INTO categories VALUES (1, 'cat1')
                             ,(2, 'cat2')
                             ,(3, 'cat3')
                             ,(4, 'cat4');

 INSERT INTO products VALUES (1, 1, 'prod1')
                            ,(2, 1, 'prod2')
                            ,(3, 2, 'prod3')
                            ,(4, 3, 'prod4')
                            ,(5, 4, 'prod4');

 INSERT INTO users VALUES (1, 'user1')
                         ,(2, 'user2')
                         ,(3, 'user3');

 INSERT INTO user_products VALUES (1, 1, 1, 4)
                                 ,(2, 2, 1, 3)
                                 ,(3, 3, 1, 3)
                                 ,(4, 2, 2, 3)
                                 ,(5, 2, 2, 2)
                                 ,(6, 5, 2, 2); 

Eu tentei várias opções, e isso certamente parece um cenário de junção externa. A consulta mais promissora QUE NÃO FUNCIONA é:

SELECT up.*, p.*, c.*, u.*
FROM user_products AS up
  JOIN users AS u ON u.id = up.user_id
  JOIN products AS p ON p.id = up.product_id
  RIGHT OUTER JOIN categories AS c ON c.id = p.category_id
WHERE u.id = 1 OR u.id IS NULL

Resultado da consulta acima

 id | product_id | user_id | quantity | id | category_id | prod_name | id | cat_name | id | user_name 
----+------------+---------+----------+----+-------------+-----------+----+----------+----+-----------
  1 |          1 |       1 |        4 |  1 |           1 | prod1     |  1 | cat1     |  1 | user1
  2 |          2 |       1 |        3 |  2 |           1 | prod2     |  1 | cat1     |  1 | user1
  3 |          3 |       1 |        3 |  3 |           2 | prod3     |  2 | cat2     |  1 | user1
    |            |         |          |    |             |           |  3 | cat3     |    | 

A razão pela qual não funciona é que ele não retorna 'cat4' da tabela de categorias. Obviamente, isso ocorre porque a WHEREcláusula está selecionando-o do conjunto de resultados. Não consigo obter um conjunto de resultados que inclua todas as categorias + os detalhes dos produtos e quantidades para os quais existem registros na tabela user_products especificada.

A consulta deve

  • retornar todas as categorias
  • dados de retorno preenchidos para informações do usuário se o usuário tiver esse produto (existe um registro em user_products)
  • não retornar linhas com outros IDs de usuário
postgresql join
  • 2 2 respostas
  • 814 Views

2 respostas

  • Voted
  1. Best Answer
    Erwin Brandstetter
    2014-07-21T17:49:57+08:002014-07-21T17:49:57+08:00

    Parece que você está procurando um arquivo FULL [OUTER] JOIN. Por documentação:

    JUNÇÃO EXTERNA COMPLETA

    Primeiro, uma junção interna é executada. Então, para cada linha em T1 que não satisfaça a condição de junção com qualquer linha em T2, uma linha unida é adicionada com valores nulos nas colunas de T2. Além disso, para cada linha de T2 que não satisfaça a condição de junção com qualquer linha em T1, uma linha unida com valores nulos nas colunas de T1 é adicionada.

    SELECT *
    FROM   users           u  
    JOIN   user_products   up ON u.id = up.user_id
                             AND u.id = 1
    JOIN   products        p ON p.id = up.product_id
    FULL   JOIN categories c ON c.id = p.category_id;
    

    Isso retorna todas as categorias e também todas as combinações de usuário-produto para o dado user_id.

    Se você estiver impondo integridade referencial com chaves estrangeiras e products.category_idfor definido NOT NULL, para que cada produto seja atribuído a uma categoria existente (não em sua pergunta), você poderá substituir FULL JOINpor RIGHT JOIN.

    Além disso, de qualquer forma, a condição para selecionar um usuário específico deve ser movida para uma subconsulta ou (mais simples) para uma JOINcondição entre as três primeiras tabelas. Deve ser aplicado antes da última tabela categoriesser unida.

    SQL Fiddle.

    • 3
  2. Andrew Wolfe
    2014-07-21T19:32:48+08:002014-07-21T19:32:48+08:00

    Acredito que você queira mostrar todas as categorias.

    Nesse caso, você precisará fazer todas as junções RIGHT OUTER JOINS.

    Por quê?

    1. A associatividade e precedência para operadores de junção externa são mal definidas e imprevisíveis
    2. Você precisa continuar 'externo' depois de começar. Como você está usando uma junção DIREITA, cada junção anterior também deve ser uma junção DIREITA. Caso contrário, os NULLs na tabela externa nunca se juntarão às tabelas product-user ou user, e isso também cortará suas categorias

    Observe que você provavelmente verá usuários repetidos assim que fizer isso funcionar, porque os usuários podem ser associados a vários produtos em várias categorias.

    Boa sorte!

    André Wolfe

    • 0

relate perguntas

  • Qual é a diferença entre um INNER JOIN e um OUTER JOIN?

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Como é a saída de uma instrução JOIN?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve