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 / 197244
Accepted
Daniel
Daniel
Asked: 2018-02-08 01:17:36 +0800 CST2018-02-08 01:17:36 +0800 CST 2018-02-08 01:17:36 +0800 CST

Precisa de ajuda com a consulta em três tabelas relacionadas

  • 772

Estou projetando um banco de dados para uma editora para rastrear o envio de revistas e também para manter um histórico dele.

Eu tenho três tabelas (simplificadas):

insira a descrição da imagem aqui

Subscriber
  id (pk)
  subscribers_number (unique)
  first_name
  last_name
  shipping_address
  last_payment

Shipping
  id (pk)
  date
  issue

ShippingAddress
  id (pk)
  shipping_id (fk)
  subscriber_id (fk)
  subscribers_number
  first_name
  last_name
  shipping_address

NonDeliveryReport
  id (pk)
  shipping_address_id (fk)
  reason
  resolved

Subscriberé uma lista de pessoas que pagam para receber uma edição mensal de sua revista. Nem todo assinante é elegível para receber a próxima edição. Para simplificar, um assinante recebe a próxima edição apenas se last_paymenta data estiver nos últimos 60 dias. Há mais algumas condições, mas falarei sobre isso mais tarde.

Quando a próxima edição estiver pronta para ser enviada, um Shippingserá criado.

Em seguida, selecionamos todos os Subscribers elegíveis e criamos um ShippingAddresspara cada um e copiamos o valor de subscribers_number, e first_namede para o novo . Fazemos isso para que tenhamos um histórico de envios imutável, mesmo que mude de endereço ou seja excluído do banco de dados. Para facilitar o uso, há uma chave estrangeira anulável além da cópia impressa do arquivo .last_nameshipping_addressSubscriberShippingAddressSubscribersubscriber_idsubscribers_number

Se a empresa de correio não puder entregar a um assinante ShippingAddress, eles retornarão um relatório de não entrega para nós. Para cada relatório, um NonDeliveryReporté criado e faz referência ao arquivo ShippingAddress.

Agora estamos chegando à parte importante da minha pergunta:

Quando criamos um Frete, temos que selecionar todos os Subscribers, que são elegíveis. Elegível é todo assinante, exceto qualquer um, que tenha um relatório de não entrega anexado a ele, que NÃO seja resolved. (Para simplificar, simplesmente ignoramos todas as outras condições.)

Então eu preciso de duas consultas:

  1. Selecione todas as assinaturas qualificadas.
  2. Selecione todos os assinantes que não são elegíveis.

A consulta nº 2 foi gerenciável e bastante fácil:

SELECT DISTINCT
  Subscriber.id
FROM Subscriber
  INNER JOIN ShippingAddress ON (Subscriber.id = ShippingAddress.subscriber_id)
  INNER JOIN NonDeliveryReport ON (ShippingAddress.id = NonDeliveryReport.shipping_address_id)
WHERE NonDeliveryReport.resolved IS NULL;

Mas as consultas que escrevi para o caso nº 1 sempre retornaram menos ou mais resultados do que o esperado. Estou preso nisso desde a semana passada e simplesmente não consigo fazê-lo funcionar. Espero que você possa me ajudar com isso.

Isso não faz parte da minha pergunta principal, mas quaisquer pensamentos (em forma de comentários, por favor) sobre o design do meu banco de dados são bem-vindos. Eu já estava pensando em adicionar um campo deliverable (bool)e Subscriberapenas preencher o valor programaticamente, ao importar os NDRs, mas estou hesitante porque isso provavelmente anularia o propósito da normalização do banco de dados.

Edit # 1: O fechamento que cheguei foi a seguinte consulta, mas ela retorna muitas linhas. *suspirar*

SELECT DISTINCT
  Subscriber.id
FROM Subscriber
  LEFT JOIN ShippingAddress ON (Subscriber.id = ShippingAddress.Subscriber_id)
  LEFT JOIN NonDeliveryReport ON (ShippingAddress.id = NonDeliveryReport.ShippingAddress_id)
WHERE NonDeliveryReport.korrigiert_am IS NOT NULL OR NonDeliveryReport.id IS NULL OR ShippingAddress.id IS NULL

Edit # 2: Depois de pensar ainda mais (eu não achava que isso fosse mais possível), encontrei uma solução.

Quando não qualificados são assinantes que têm um NDR aberto (resolvido IS NULL), então elegível é qualquer pessoa que não tenha NDR além de qualquer pessoa que tenha mais de 0 NDR não resolvido.

-- List of ELIGIBLE Subscribers
SELECT DISTINCT Subscriber.id
FROM Subscriber
LEFT JOIN ShippingAddress ON (Subscriber.id = ShippingAddress.subscriber_id)
WHERE ShippingAddress.id IS NULL OR Subscriber.id NOT IN
  (
    SELECT ShippingAddress.subscriber_id
    FROM ShippingAddress
    INNER JOIN NonDeliveryReport ON ShippingAddress.id = NonDeliveryReport.shipping_address_id
    WHERE (NonDeliveryReport.id IS NOT NULL AND NonDeliveryReport.resolved IS NULL)
    GROUP BY ShippingAddress.subscriber_id
  )
ORDER BY Subscriber.id;
database-design join
  • 4 4 respostas
  • 67 Views

4 respostas

  • Voted
  1. LJ01
    2018-02-08T02:26:32+08:002018-02-08T02:26:32+08:00

    Eu acredito que você está querendo algo um pouco assim;

    SELECT DISTINCT
    Subscriber.id
    FROM Subscriber
     INNER JOIN ShippingAddress ON (Subscriber.id = 
    ShippingAddress.subscriber_id)
      LEFT OUTER JOIN NonDeliveryReport ON (ShippingAddress.id = NonDeliveryReport.shipping_address_id)
    WHERE NonDeliveryReport.shipping_address_id IS NULL OR NonDeliveryReport.resolved IS NOT NULL;
    
    • 0
  2. Scott Hodgin - Retired
    2018-02-08T02:32:31+08:002018-02-08T02:32:31+08:00

    Você não forneceu nenhum dado de teste em sua pergunta, portanto, isso não foi totalmente testado. Você também não especificou uma plataforma RDBMS (SQL Server, Oracle, etc.). Eu usei o SQL Server e algumas expressões de tabela comuns.

    Seu inelegível é qualquer assinante em que havia um endereço não entregue E qualquer assinante em que o last_payment seja há mais de 60 dias. Eu usei um UNION(o que eliminará quaisquer duplicatas). Os assinantes elegíveis são qualquer pessoa que NÃO seja elegível.

    ;
    
    WITH SubscriberIneligible
    AS (
        SELECT Subscriber.id        --non-deliverable
        FROM Subscriber
        INNER JOIN ShippingAddress ON (Subscriber.id = ShippingAddress.subscriber_id)
        INNER JOIN NonDeliveryReport ON (ShippingAddress.id = NonDeliveryReport.shipping_address_id)
        WHERE NonDeliveryReport.resolved IS NULL
    
        UNION
    
        SELECT Subscriber.id        --last payment over 60 days
        FROM Subscriber
        WHERE Last_Payment < DATEADD(DAY, - 60, SYSDATETIME())
        )
        ,SubscriberEligible
    AS (
        SELECT Subscriber.id        --eligible subscribers
        FROM Subscriber s
        WHERE NOT EXISTS (
                SELECT *
                FROM SubscriberIneligible
                WHERE id = s.id
                )
        )
    SELECT *
        ,'N' AS Eligible
    FROM SubscriberIneligible
    
    UNION
    
    SELECT *
        ,'Y' AS Eligible
    FROM SubscriberEligible
    
    • 0
  3. KumarHarsh
    2018-02-08T02:32:50+08:002018-02-08T02:32:50+08:00

    IMHO, seu design de banco de dados é OK.Hope tipo de dados também estão ok.

    A tabela de envio não é muito clara. Explique a finalidade da coluna

    Não diga "But query 1 kills me". diga o problema exato. quanto tempo leva. se está dando a saída correta ou não, etc.

    BTW com seu design existente, você pode evitar distintos dessa maneira

    SELECT 
      Subscriber.id
    FROM dbo.Subscriber
    INNER JOIN dbo.ShippingAddress ON (Subscriber.id = ShippingAddress.subscriber_id)
    where exists(
    select shipping_address_id from NonDeliveryReport NDR
    WHERE ShippingAddress.subscriber_id= NDR.shipping_address_id AND
     NonDeliveryReport.resolved IS NULL
    )
    

    Eu já estava pensando em adicionar uma entrega de campo (bool) ao Assinante e apenas preencher o valor programaticamente, ao importar os NDRs, mas estou hesitante porque isso provavelmente anularia o propósito da normalização do banco de dados.

    seu pensamento está correto. você deve adicionar isDeliverable (bool)na tabela Assinante. Isso não anula o propósito da Normalização. Primeiramente devemos criar o banco de dados Normalize tanto quanto possível. Agora de acordo com a necessidade e volume de dados e frequência temos liberdade de DeNormalization. É muito recomendado pelo livro RDMS.

    Performance is Main Goal
    

    Caso o desempenho da consulta esteja prejudicando, você pode adicionar algumas colunas para desnormalizar e, portanto, reduzir a condição JOIN.

    você pode até introduzir shipping_id (fk) , subscriber_id (fk) in NonDeliveryReport table, mas depende muito do seu requisito de MIS, volume de dados

    • 0
  4. Best Answer
    Daniel
    2018-02-08T05:40:36+08:002018-02-08T05:40:36+08:00

    Esta é a solução certa.

    -- List of ELIGIBLE Subscribers
    SELECT DISTINCT Subscriber.id
    FROM Subscriber
    LEFT JOIN ShippingAddress ON (Subscriber.id = ShippingAddress.subscriber_id)
    WHERE ShippingAddress.id IS NULL OR Subscriber.id NOT IN
      (
        SELECT ShippingAddress.subscriber_id
        FROM ShippingAddress
        INNER JOIN NonDeliveryReport ON ShippingAddress.id = NonDeliveryReport.shipping_address_id
        WHERE (NonDeliveryReport.id IS NOT NULL AND NonDeliveryReport.resolved IS NULL)
        GROUP BY ShippingAddress.subscriber_id
      )
    ORDER BY Subscriber.id;
    
    • 0

relate perguntas

  • É melhor armazenar os valores calculados ou recalculá-los a pedido? [duplicado]

  • Armazenar vs calcular valores agregados

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

  • Quais são algumas maneiras de implementar um relacionamento muitos-para-muitos em um data warehouse?

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

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