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 / 82710
Accepted
AlwaysLearningNewStuff
AlwaysLearningNewStuff
Asked: 2014-11-15 16:39:29 +0800 CST2014-11-15 16:39:29 +0800 CST 2014-11-15 16:39:29 +0800 CST

Não é possível converter este tipo de diagrama ER em tabelas SQL ou relacionais

  • 772

Eu me deparei com um problema durante o design do banco de dados. Deixe-me explicar do que se trata:

O contrato tem alguns atributos simples que o descrevem, podendo ter anexos e dinâmica de pagamento.

Portanto, decidi fazer a tabela principal Contractse coloquei atributos simples como colunas.

A dinâmica de pagamento é um atributo complexo da Contractstabela. Pode ter nenhum, um ou vários valores. Pesquisando na Internet aprendi que isso se chama atributo multivalorado , e encontrei este exemplo que parece ilustrar muito bem o meu caso (Dinâmica de pagamento é equivalente à tabela Hobbies no exemplo vinculado).

Quanto aos Anexos, é um atributo complexo de Contract. O contrato pode ter muitos deles, um ou nenhum.

Anexo tem exatamente os mesmos atributos simples do contrato, podendo também ter Dinâmica de pagamento. A relação do Anexo com a Dinâmica de pagamento é a mesma que a relação entre Contrato e Dinâmica de pagamento.

Resumindo, Anexo e contrato têm tudo igual, a única diferença é que Anexo é um atributo complexo de Contrato.

Usando isso como referência, fiz o esboço do meu diagrama ER:

insira a descrição da imagem aqui

Esta é a primeira vez que vejo este tipo de relacionamento, então peço à comunidade para me ajudar a converter este diagrama ER em SQL ou tabelas relacionais.

Peço desculpas por não fornecer mais informações, se você tiver mais solicitações, deixe um comentário e atualizarei minha postagem imediatamente.

Obrigado por sua compreensão e ajuda.

Atenciosamente.

database-design
  • 3 3 respostas
  • 2166 Views

3 respostas

  • Voted
  1. Best Answer
    Solomon Rutzky
    2014-11-16T12:33:09+08:002014-11-16T12:33:09+08:00

    Concordo que a abordagem de @MladenUzelac é provavelmente o padrão mais comum para essa situação, mas há uma falha teórica em potencial que pode se expor ao longo do tempo e dificultar a vida. Essa falha é: um Contrato , no final das contas, não é um Anexo . Claro, eu enfatizei "potencial" porque atualmente não estou a par se eles são ou não considerados a mesma coisa (ou seja, Contrato === Anexo). No entanto, até certo ponto, isso não mudaria minha recomendação de descobrir que eles são os mesmos. Qualquer coisa está sujeita a mudanças a qualquer momento, mesmo que altamente improvável, então ter a mesma natureza hoje não implica que eles sempre terão a mesma natureza, e muitas vezes as coisas crescem em direções diferentes. Então, sim, eles compartilham os mesmos atributos hoje e compartilham o mesmo relacionamento com a Dinâmica de Pagamento hoje; mas amanhã é outro dia e a natureza das coisas muda, mesmo por razões irracionais ;-).

    Não me interpretem mal: definitivamente há momentos em que uma entidade autorreferenciada é a solução apropriada, mas acho que isso requer que as entidades sejam da mesma natureza. Os dois exemplos mais comuns que consigo pensar são:

    • Funcionário / Gerente: Faz sentido ter um campo [ManagerID] (ou eu prefiro [ManagerUserID]) na tabela [Employee] que é um FK auto-referenciado de volta para [UserID]. Isso funciona porque um gerente é um empregado.

    • Departamentos: Em hierarquias corporativas/varejo, faz sentido ter um campo [ParentDepartmentID] na tabela [Department] que é um FK autorreferenciado de volta para [DepartmentID]. Isso funciona porque o Departamento "pai" é um Departamento.

    Em ambos os casos, o relacionamento entre pai e filho não é uma propriedade determinante primária dessas entidades. Em vez disso, o relacionamento é uma propriedade, assim como o nome da entidade. Em ambos os casos, o relacionamento não é crítico para a existência das entidades filhas, e as entidades definidas como "filhos" existem mesmo sem o relacionamento. Por outro lado, se um Anexo requer um Contrato para existir, bem, isso é algo bem diferente.

    O que importa é: só porque duas coisas parecem iguais não significa que sejam iguais.

    Armazenar duas entidades "semelhantes, mas diferentes" juntas, enquanto reduz uma certa quantidade de tabelas / junções / código, leva a algumas preocupações pragmáticas, mesmo que apenas em termos de armazenamento físico (ou seja, a camada de banco de dados).

    Trabalhei durante anos em um sistema, construído antes de chegar lá, no qual esse padrão foi usado várias vezes e para situações quase idênticas ao que está sendo descrito aqui. Não tenho certeza se as entidades tinham exatamente os mesmos atributos no dia 1, mas ao longo do tempo, pelo menos, elas começaram a divergir e assumir propriedades diferentes umas das outras. Em alguns casos foram adicionados campos que eram apropriados para uma das entidades, mas não para outra, então só tínhamos que saber quando um campo NULL era apropriado para aquele tipo de linha, ou se era um bug. Outras vezes, uma abordagem de "atributo multivalorado" foi adotada com a estrutura sendo efetivamente: [EntityID], [AttributeID], [AttributeValue].

    Como esperado, para obter uma lista de entidades "pai", consultaríamos com WHERE ParentEntityID IS NULL. E para obter uma lista de entidades "filhos" com as quais consultaríamosWHERE ParentEntityID IS NOT NULL. Ficou divertido quando precisávamos de ambas as entidades porque elas eram realmente uma propriedade de outra entidade primária, então precisávamos mostrar ambas como propriedades separadas da entidade primária. O que foi divertido foi como essa junção de auto-referência prejudicou o desempenho (embora seja possível que uma ligeira mudança na estratégia de indexação possa ter consertado isso). Mas ficou superdivertido quando colocamos esse EntityID em outras entidades como FKs, e só queríamos fazer referência a um desses dois tipos de entidade, mas nem sempre era garantido que queríamos a entidade "filho" (embora esse fosse o entidade mais comum para se referir). No final, quando comecei a criar novas tabelas e refatorar as antigas, incluí o nome da entidade no nome do campo FK na entidade relacionada, apenas para "autodocumentar" para quem procura nas tabelas e precisa criar novas consultas. E, em alguns casos, adicionei dois campos FK, um para cada tipo de entidade, apenas para evitar essa junção automática cara (e era seguro desnormalizar, pois o relacionamento pai-filho nunca poderia mudar depois de criado).

    Então, eu começaria indo na mesma direção que @Peter em termos de tabelas separadas para Contrato e Anexo (mesmo que sejam estruturas idênticas ou quase idênticas), mas abordaria o tratamento de seu relacionamento com a Dinâmica de Pagamento diferentemente. Parece que me lembro de ter tentado os dois campos FK diferentes no passado e não ter gostado muito de como isso aconteceu. No mínimo, parece menos gerenciável ao longo do tempo, à medida que outras entidades são adicionadas que podem se relacionar com a Dinâmica de Pagamento e você precisa continuar adicionando FKs de volta aos novos pais. E você também precisa ter um CHECK CONSTRAINT na tabela garantindo que um, e apenas um, desses campos FK seja NÃO NULO.

    Em vez disso, eu criaria uma ponte/tabela de relacionamento separada para cada um dos Anexos e Contratos para se relacionar com a Dinâmica de Pagamento . Sim, quando forem adicionadas novas entidades que possam se relacionar com a Dinâmica de Pagamento você precisará adicionar novas tabelas de ponte/relacionamento, mas de alguma forma me sinto melhor com isso porque não está alterando a estrutura da Dinâmica de Pagamento : a entidade Dinâmica de Pagamento é o mesmo se 1 ou 100 entidades se relacionam com ele.

    (o SQL abaixo usa a semântica do Microsoft SQL Server T-SQL)

    Principais Entidades

    CREATE TABLE SchemaName.[Contract]
    (
      ContractID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
      ContractName VARCHAR(50) NOT NULL,
      ContractDetails NVARCHAR(MAX) NULL
    );
    
    CREATE TABLE SchemaName.Annex
    (
      AnnexID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
      ContractID INT NOT NULL REFERENCES SchemaName.[Contract] (ContractID),
      AnnexName VARCHAR(50) NOT NULL,
      AnnexDetails NVARCHAR(MAX) NULL
    );
    

    Dinâmica de Pagamento

    A tabela [DynamicsOfPaymentType] é uma tabela de pesquisa que assume que as "dinâmicas" são propriedades nomeadas, possivelmente imitando uma enumeração na camada do aplicativo. Eu escolhi TINYINT (0 - 255) porque normalmente a maioria das coisas tem menos de 255 propriedades/atributos distintos. Se precisar de mais de 255, vá para o próximo tamanho maior. Mas não vá além do necessário, pois esse campo é copiado nas tabelas de relacionamento, que podem ficar grandes, especialmente com muitos contratos e anexos , cada um com várias entradas DynamicOfPayment .

    Observe que o PK em DynamicsOfPayment é uma chave composta de [DynamicsOfPaymentID] e [DynamicsOfPaymentTypeID]. Embora tecnicamente apenas o campo [DynamicsOfPaymentID] seja necessário no PK, pois é garantido como único, ter o campo [DynamicsOfPaymentTypeID] nos permite enviar essa propriedade para a tabela de relacionamento para uso na restrição de cada entidade para ter apenas uma instância de qualquer Propriedade DynamicsOfPayment . Por favor, veja as notas na próxima seção para mais detalhes.

    CREATE TABLE SchemaName.DynamicsOfPaymentType
    (
      DynamicsOfPaymentTypeID TINYINT NOT NULL PRIMARY KEY, -- SMALLINT if > 255 are possible
      DynamicsOfPaymentType VARCHAR(50) NOT NULL
    );
    
    CREATE TABLE SchemaName.DynamicsOfPayment
    (
      DynamicsOfPaymentID INT IDENTITY(1, 1) NOT NULL,
      DynamicsOfPaymentTypeID TINYINT NOT NULL REFERENCES
                              SchemaName.[DynamicsOfPaymentType] (DynamicsOfPaymentTypeID),
      Value NVARCHAR(MAX) NULL,
      PRIMARY KEY (DynamicsOfPaymentID, DynamicsOfPaymentTypeID)
    );
    

    Entidade principal para relacionamentos de Dinâmica de Pagamento

    Observe que o PK de ambas as tabelas de relacionamento é uma chave composta composta pelo ID da entidade principal e o campo [DynamicsOfPaymentTypeID] -- não o campo [DynamicsOfPaymentID]. O motivo, conforme mencionado nas notas das seções anteriores, é impor uma única instância de qualquer propriedade DynamicsOfPayment específica para cada entidade principal. Se uma entidade pode ter várias instâncias de um DynamicsOfPaymentpropriedade, então é uma simples questão de ajustar o PK nessa tabela de relacionamento específica para ser uma chave composta composta pelo ID da entidade principal e o campo [DynamicsOfPaymentID] (ou, se preferir, ambos [DynamicsOfPaymentTypeID] e [DynamicsOfPaymentID ] Campos). Como você pode ver, esse modelo pode permitir não apenas que os relacionamentos imponham instâncias singulares de propriedades relacionadas OU que os relacionamentos aceitem várias propriedades relacionadas, mas também permite misturar os dois, pois as tabelas de relacionamento não precisam usar o mesma combinação de campos para seu PK: alguns relacionamentos podem ser restritos enquanto outros não. Portanto, talvez o Anexo esteja limitado a uma única instância de qualquer propriedade DynamicsOfPayment específica , mas o Contratoé permitido ter várias instâncias de uma propriedade específica.

    CREATE TABLE SchemaName.[ContractXDynamicsOfPayment]
    (
      ContractID INT NOT NULL,
      DynamicsOfPaymentID INT NOT NULL,
      DynamicsOfPaymentTypeID TINYINT NOT NULL,
      PRIMARY KEY (ContractID, DynamicsOfPaymentTypeID),
      FOREIGN KEY (ContractID) REFERENCES SchemaName.[Contract] (ContractID),
      FOREIGN KEY (DynamicsOfPaymentID, DynamicsOfPaymentTypeID) REFERENCES
                  SchemaName.[DynamicsOfPayment] (DynamicsOfPaymentID, DynamicsOfPaymentTypeID)
    );
    
    CREATE TABLE SchemaName.[AnnexXDynamicsOfPayment]
    (
      AnnexID INT NOT NULL,
      DynamicsOfPaymentID INT NOT NULL,
      DynamicsOfPaymentTypeID TINYINT NOT NULL,
      PRIMARY KEY (AnnexID, DynamicsOfPaymentTypeID),
      FOREIGN KEY (AnnexID) REFERENCES SchemaName.[Annex] (AnnexID),
      FOREIGN KEY (DynamicsOfPaymentID, DynamicsOfPaymentTypeID) REFERENCES
                  SchemaName.[DynamicsOfPayment] (DynamicsOfPaymentID, DynamicsOfPaymentTypeID)
    );
    

    dicas profissionais

    1. Sim, haverá um pouco mais de tabelas, junções e código de aplicativo usando este modelo. Mas lembre-se de que refatorar o código do aplicativo é muitomais fácil do que refatorar tabelas, especialmente quando o aplicativo estiver ativo e os dados estiverem lá. Tome um pouco mais de tempo agora para codificar isso e economize muitas, muitas horas ao longo dos anos tentando fazer alterações em modelos mais simples, ou conforme os projetos surgirem em alguns anos, apenas decidindo colocar hacks / band - ajuda porque o negócio não vai demorar 10 a 20 (ou mais) horas para fazer alterações no modelo simplificado que economizou de 1 a 2 horas agora. Acredite em mim, programadores/arquitetos de banco de dados não são baratos (pelo menos não hoje em dia) e meus empregadores gastaram uma quantidade notória de tempo e dinheiro - na forma de meu salário (e dos salários de meus colegas de trabalho de banco de dados) - para para refatorar escolhas ruins de design que economizaram talvez até 1 dia do tempo inicial de desenvolvimento,

    2. Você pode coordenar a limpeza das tabelas de relacionamento marcando o FK como ON DELETE CASCADE. A sintaxe pode diferir um pouco entre os RDBMSs, mas eu esperaria que a maioria, se não todos, suportasse exclusões em cascata. Desta forma, se você deletar uma entrada Dinâmica de Pagamento , não precisa se preocupar com sua entrada em nenhuma das tabelas de relacionamento.

    3. Dependendo de qual RDBMS você usa, você pode até coordenar a criação dos registros de relacionamento. O Microsoft SQL Server possui uma cláusula OUTPUT muito legal que retorna as alterações feitas por uma operação DML. Portanto, você pode inserir um registro em [DynamicsOfPayment] e, dentro do contexto dessa operação (e, portanto, transação), você pode fazer a inserção na tabela de relacionamento. Suponha que você tenha um procedimento de inserção que aceite um parâmetro extra para @ContractID que não seja inicialmente necessário para a tabela [DynamicOfPayment]. Pode ser usado da seguinte forma:

      INSERT INTO SchemaName.[DynamicsOfPayment] (DynamicsOfPaymentTypeID, Value)
      OUTPUT @ContractID,
             INSERTED.DynamicsOfPaymentID, -- server-generated auto-increment field
             INSERTED.DynamicsOfPaymentTypeID
      INTO   SchemaName.[ContractXDynamicsOfPayment]
             (ContractID, DynamicsOfPaymentID, DynamicsOfPaymentTypeID)
      VALUES (@DynamicsOfPaymentTypeID, @Value);
      

      Agora você só precisa de dois procedimentos armazenados (já que cada um precisa referenciar uma tabela de relacionamento diferente):

      • DynamicsOfPayment_CreateForContract (@DynamicsOfPaymentTypeID, @Value, @ContractID)
      • DynamicsOfPayment_CreateForAnnex (@DynamicsOfPaymentTypeID, @Value, @AnnexID)
    • 4
  2. Mladen Uzelac
    2014-11-16T06:39:18+08:002014-11-16T06:39:18+08:00

    Parece que é melhor que o contrato tenha auto-junção para contrato e anexo (estrutura hierárquica).
    A nomenclatura do contrato e do anexo pode ser diferente, e id e self_id podem ser diferentes.

    create table contract(
       id serial primary key,
       self_id int,
       document_id text,
       constraint contract_self_fk foreign key(self_id) references contract(id)
    );
    
    create table dynamics_of_payment(
        id serial primary key,
        contract_id int,
        constraint dynamics_of_payment_contract_fk foreing key(contract_id) references contract(id)
     );
    

    Uma vez que o PostgreSQL suporta Writeable Common Table Expression (CTE), você pode atualizar, inserir, inserir e excluir valores.

    Indicarei os guias que lhe explicarão mais:
    Ótimo vídeo explicando a estrutura recursiva
    Expressões de tabela comuns no PostgreSQL - Documento oficial
    Consultas recursivas com postgres
    Recursivo 3
    Estrutura em árvore com PostgreSQL

    Aqui está um tutorial da Oracle sobre esse problema:
    Oracle e CTE

    Vou demonstrar como você pode preservar o pedido facilmente de contrato e anexos.
    Ao armazenar valores na tabela Contrato, siga este padrão:

    (id, self_id, document_id)
      1,   1,       contract xxx
      2,   1,       annexx xxx_01
      3,   2,       annexx xxx_02
      4,   3,       annexx xxx_03
    

    Portanto, quando você tiver uma consulta recursiva, poderá obter facilmente os documentos oficiais solicitados.

    E aqui está um pequeno curso gratuito sobre estrutura recursiva com SQL: https://class.stanford.edu/courses/DB/Recursion/SelfPaced/about

    • 2
  3. Sir Swears-a-lot
    2014-11-16T01:25:16+08:002014-11-16T01:25:16+08:00

    Eu criaria 3 tabelas:

    Contrato: id do contrato (pkey) Attrib 1 Attrib 2 etc.

    Anexo: ID do anexo (pkey) ID do contrato (fkey) Attrib 1 Attrib 2 etc.

    Dinâmica: ID do pagamento (pkey) ID do contrato (fkey) ID do anexo (fkey) Atrib 1 Atributo 2 etc.

    Pelo que entendi sua descrição, isso permitiria que as entradas na tabela dinâmica se relacionassem a um contrato, anexo ou ambos.

    • 0

relate perguntas

  • Os índices filtrados podem ajudar a melhorar as consultas baseadas em uma hora inserida ou isso deve ser evitado?

  • Qual é a diferença entre os tipos de dados MySQL VARCHAR e TEXT?

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

  • Armazenar vs calcular valores agregados

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

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