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 / 135941
Accepted
yeln
yeln
Asked: 2016-04-21 07:05:05 +0800 CST2016-04-21 07:05:05 +0800 CST 2016-04-21 07:05:05 +0800 CST

Projetando uma estrutura de banco de dados de amizades: devo usar uma coluna de vários valores?

  • 772

Digamos que eu tenha uma tabela chamada User_FriendList, que possui as seguintes características:

CREATE TABLE User_FriendList (
    ID ...,
    User_ID...,
    FriendList_IDs...,
    CONSTRAINT User_Friendlist_PK PRIMARY KEY (ID)
);

E suponhamos que a referida tabela contenha os seguintes dados:

+----+---------+---------------------------+
 | Identificação | User_ID | Friendlist_IDs             |
 +----+---------+---------------------------+
 | 1 | 102 | 2:15:66:35:26:17: |
 +----+---------+---------------------------+
 | 2 | 114 | 1:12:63:33:24:16:102 |
 +----+---------+---------------------------+
 | 3 | 117 | 6:24:52:61:23:90:97:118 |
 +----+---------+---------------------------+

Nota: O “:” (dois pontos) é o delimitador ao explodir em PHP em um arquivo array.

Perguntas

Então:

  • Esta é uma maneira conveniente de “armazenar” o IDsde um FriendList?

  • Ou, em vez disso, devo ter linhas individuais com apenas um único FriendIdvalor em cada uma delas e, quando precisar recuperar todas as linhas de uma determinada lista , simplesmente realizar uma consulta como SELECT * FROM UserFriendList WHERE UserId = 1?

database-design foreign-key
  • 1 1 respostas
  • 20980 Views

1 respostas

  • Voted
  1. Best Answer
    MDCCL
    2016-04-21T08:56:04+08:002016-04-21T08:56:04+08:00

    Gerenciando uma informação individual

    Supondo que, no domínio do seu negócio,

    • um usuário pode ter zero-um-ou-muitos amigos ;
    • um amigo deve primeiro ser registrado como usuário ; e
    • você procurará e/ou adicionará e/ou removerá e/ou modificará valores únicos de uma lista de amigos ;

    então, cada dado específico reunido na Friendlist_IDscoluna de valores múltiplos representa uma informação separada que carrega um significado muito exato. Portanto, a referida coluna

    • envolve um grupo apropriado de restrições explícitas, e
    • seus valores têm o potencial de serem manipulados individualmente por meio de diversas operações relacionais (ou combinações delas).

    Resposta curta

    Conseqüentemente, você deve reter cada um dos Friendlist_IDsvalores em (a) uma coluna que aceita exclusivamente um único valor por linha em (b) uma tabela que representa o tipo de associação em nível conceitual que pode ocorrer entre Usuários , ou seja, uma Amizade —como Vou exemplificar nas seções seguintes—.

    Desta forma, você poderá tratar (i) a referida tabela como uma relação matemática e (ii) a referida coluna como um atributo de relação matemática —tanto quanto o MySQL e seu dialeto SQL permitirem, é claro—.

    Por quê?

    Porque o modelo relacional de dados , criado pelo Dr. E. F. Codd , exige tabelas compostas por colunas que contenham exatamente um valor do domínio ou tipo aplicável por linha; assim, declarar uma tabela com uma coluna que pode conter mais de um valor do domínio ou tipo em questão (1) não representa uma relação matemática e (2) não permitiria obter as vantagens propostas no referido referencial teórico.

    Modelando Amizades entre Usuários : Definindo primeiro as regras do ambiente de negócios

    Recomendo fortemente começar a estruturar um banco de dados delimitando — antes de tudo — o esquema conceitual correspondente em virtude da definição das regras de negócio relevantes que, entre outros fatores, devem descrever os tipos de inter-relações existentes entre os distintos aspectos de interesse, ou seja, , os tipos de entidades aplicáveis ​​e suas propriedades ; por exemplo:

    • Um usuário é identificado principalmente por seu UserId
    • Um usuário é identificado alternadamente pela combinação de seu nome , sobrenome , gênero e data de nascimento
    • Um usuário é identificado alternadamente por seu nome de usuário
    • Um usuário é o solicitante de zero-um-ou-muitos Friendships
    • Um usuário é o destinatário de zero-um-ou-muitos Friendships
    • Uma Amizade é identificada principalmente pela combinação de seu RequesterId e seu AddresseeId

    Diagrama IDEF1X expositivo

    Dessa forma, consegui derivar o diagrama IDEF1X 1 mostrado na Figura 1 , que integra a maioria das regras formuladas anteriormente:

    Figura 1. Diagrama IDEF1X de Amizade do Usuário

    Conforme ilustrado, Solicitante e Destinatário são denotações que expressam os Papéis desempenhados pelos Usuários específicos que participam de uma determinada Amizade .

    Sendo assim, o tipo de entidade Friendship retrata um tipo de associação de razão de cardinalidade muitos-para-muitos (M:N) que pode envolver diferentes ocorrências de um mesmo tipo de entidade, ou seja, User . Como tal, é um exemplo da construção clássica conhecida como “lista de materiais” ou “explosão de peças”.


    1 Definição de integração para modelagem de informações ( IDEF1X ) é uma técnica altamente recomendável que foi estabelecida como padrão em dezembro de 1993 pelo Instituto Nacional de Padrões e Tecnologia (NIST) dos EUA. É solidamente baseado em (a) o material teórico inicial de autoria do único criador do modelo relacional, ou seja, Dr. EF Codd ; sobre (b) a visão entidade-relacionamento de dados, desenvolvida pelo Dr. PP Chen ; e também sobre (c) a Logical Database Design Technique, criada por Robert G. Brown.


    Projeto lógico ilustrativo de SQL-DDL

    Então, a partir do diagrama IDEF1X apresentado acima, declarar um arranjo DDL como o que segue é muito mais “natural”:

    -- You should determine which are the most fitting 
    -- data types and sizes for all the table columns 
    -- depending on your business context characteristics.
    
    -- At the physical level, you should make accurate tests 
    -- to define the mostconvenient INDEX strategies based on 
    -- the pertinent query tendencies.
    
    -- As one would expect, you are free to make use of 
    -- your preferred (or required) naming conventions. 
    
    CREATE TABLE UserProfile ( -- Represents an independent entity type.
        UserId          INT      NOT NULL,
        FirstName       CHAR(30) NOT NULL,
        LastName        CHAR(30) NOT NULL,
        BirthDate       DATE     NOT NULL,
        GenderCode      CHAR(3)  NOT NULL,
        Username        CHAR(20) NOT NULL,
        CreatedDateTime DATETIME NOT NULL,
        --
        CONSTRAINT UserProfile_PK  PRIMARY KEY (UserId),
        CONSTRAINT UserProfile_AK1 UNIQUE ( -- Composite ALTERNATE KEY.
            FirstName,
            LastName,
            GenderCode,
            BirthDate
        ),
        CONSTRAINT UserProfile_AK2 UNIQUE (Username) -- Single-column ALTERNATE KEY.
    );
    
    CREATE TABLE Friendship ( -- Stands for an associative entity type.
        RequesterId     INT      NOT NULL,
        AddresseeId     INT      NOT NULL, -- Fixed with a well-delimited data type.
        CreatedDateTime DATETIME NOT NULL,
        --
        CONSTRAINT Friendship_PK            PRIMARY KEY (RequesterId, AddresseeId), -- Composite PRIMARY KEY.
        CONSTRAINT FriendshipToRequester_FK FOREIGN KEY (RequesterId)
            REFERENCES UserProfile (UserId),
        CONSTRAINT FriendshipToAddressee_FK FOREIGN KEY (AddresseeId)
            REFERENCES UserProfile (UserId),
        CONSTRAINT FriendsAreDistinct_CK    CHECK       (RequesterId <> AddresseeId)
    );
    

    Desta forma:

    • cada tabela base representa um tipo de entidade individual;
    • cada coluna representa uma única propriedade do respectivo tipo de entidade;
    • um tipo de dado específico a é fixado para cada coluna de forma a garantir que todos os valores nela contidos pertençam a um conjunto particular e bem definido , seja ele INT, DATETIME, CHAR, etc.; e
    • múltiplas restrições b são configuradas (declarativamente) para garantir que as asserções na forma de linhas retidas em todas as tabelas atendam às regras de negócio determinadas no esquema conceitual.

    Vantagens de uma coluna de valor único

    Como demonstrado, você pode, por exemplo:

    • Aproveite a integridade referencial imposta pelo sistema de gerenciamento de banco de dados (DBMS para abreviação) para a Friendship.AddresseeIdcoluna, pois restringi-la como uma FOREIGN KEY (FK para abreviar) que faz uma referência à UserProfile.UserIdcoluna garante que todos os valores apontem para uma linha existente .

    • Crie uma PRIMARY KEY (PK) composta composta pela combinação de colunas (Friendship.RequesterId, Friendship.AddresseeId), ajudando a distinguir elegantemente todas as linhas INSERTadas e, naturalmente, proteger sua unicidade .

      Claro, isso significa que a anexação de uma coluna extra para valores substitutos atribuídos pelo sistema (por exemplo, uma configurada com a propriedade IDENTITY no Microsoft SQL Server ou com o atributo AUTO_INCREMENT no MySQL) e o ÍNDICE auxiliar é totalmente supérfluo .

    • Restrinja os valores retidos Friendship.AddresseeIda um tipo de dados preciso c (que deve corresponder, por exemplo, ao estabelecido para UserProfile.UserId, neste caso INT), deixando que o SGBD se encarregue da validação automática pertinente.

      Esse fator também pode ajudar a (a) utilizar as funções de tipo incorporadas correspondentes e (b) otimizar o uso do espaço em disco .

    • Otimize a recuperação de dados no nível físico configurando pequenos e rápidos ÍNDICES subordinados para a Friendship.AddresseeIdcoluna, pois esses elementos físicos podem auxiliar substancialmente na agilização das consultas que envolvem a referida coluna.

      Certamente, você pode, por exemplo, colocar um ÍNDICE de uma coluna para Friendship.AddresseeIdsozinho, um de várias colunas que engloba Friendship.RequesterIde Friendship.AddresseeId , ou ambos.

    • Evite a complexidade desnecessária introduzida pela “busca por” valores distintos que são coletados juntos dentro da mesma coluna (muito provavelmente duplicados, digitados incorretamente etc.), um curso de ação que acabaria por desacelerar o funcionamento do seu sistema, porque você têm que recorrer a métodos não relacionais que consomem tempo e recursos para realizar essa tarefa.

    Portanto, existem vários motivos que exigem uma análise cuidadosa do ambiente de negócios relevante para marcar o tipo d de cada coluna da tabela com precisão.

    Conforme exposto, o papel desempenhado pelo designer de banco de dados é fundamental para fazer o melhor uso de (i) os benefícios de nível lógico oferecidos pelo modelo relacional e (ii) os mecanismos físicos fornecidos pelo SGBD de escolha.


    a , b , c , d Evidentemente, ao trabalhar com plataformas SQL (por exemplo, Firebird e PostgreSQL ) que suportam a criação de DOMAIN (um recurso relacional distinto ), você pode declarar colunas que aceitam apenas valores que pertencem a seus respectivos (adequadamente restritos e às vezes compartilhado) DOMÍNIOS.


    Um ou mais programas aplicativos que compartilham o banco de dados em consideração

    Quando você tiver que empregar arraysno código do(s) programa(s) aplicativo(s) que acessa(m) o banco de dados, basta recuperar o(s) conjunto(s) de dados relevante(s) completo (s) e então “vinculá-lo(s) à estrutura de código em questão ou executar o processo(s) de aplicativo(s) associado(s) que deve(m) ocorrer.

    Outros benefícios das colunas de valor único: As extensões da estrutura do banco de dados são muito mais fáceis

    Outra vantagem de manter o AddresseeIdponto de dados em sua coluna reservada e devidamente tipada é que facilita consideravelmente a extensão da estrutura do banco de dados, conforme exemplificarei a seguir.

    Progressão do cenário: Incorporando o conceito de Friendship Status

    Uma vez que Friendships podem evoluir com o tempo, você pode ter que acompanhar tal fenômeno, então você teria que (1) expandir o esquema conceitual e (2) declarar mais algumas tabelas no layout lógico. Então, vamos organizar as próximas regras de negócio para delinear as novas incorporações:

    • Um Friendship mantém FriendshipStatuses de um para muitos
    • Um FriendshipStatus é identificado principalmente pela combinação de seu RequesterId , seu AddresseeId e seu SpecificDateTime
    • Um usuário especifica zero-um-ou-muitos FriendshipStatuses
    • Um Status classifica zero-um-ou-muitos FriendshipStatuses
    • Um Status é identificado principalmente por seu StatusCode
    • Um Status é identificado alternadamente por seu Nome

    Diagrama IDEF1X estendido

    Sucessivamente, o diagrama IDEF1X anterior pode ser estendido para incluir os novos tipos de entidades e tipos de inter-relacionamento descritos acima. Um diagrama representando os elementos anteriores associados aos novos é apresentado na Figura 2 :

    Figura 2. Diagrama de status de amizade IDEF1X

    Adições de estrutura lógica

    Depois, podemos alongar o layout DDL com as seguintes declarações:

    --
    CREATE TABLE MyStatus ( -- Denotes an independent entity type.
        StatusCode CHAR(1)  NOT NULL,
        Name       CHAR(30) NOT NULL,
        --
        CONSTRAINT MyStatus_PK PRIMARY KEY (StatusCode),
        CONSTRAINT MyStatus_AK UNIQUE      (Name) -- ALTERNATE KEY.
    ); 
    
    CREATE TABLE FriendshipStatus ( -- Represents an associative entity type.
        RequesterId       INT      NOT NULL,
        AddresseeId       INT      NOT NULL,
        SpecifiedDateTime DATETIME NOT NULL,
        StatusCode        CHAR(1)  NOT NULL,
        SpecifierId       INT      NOT NULL,
        --
        CONSTRAINT FriendshipStatus_PK             PRIMARY KEY (RequesterId, AddresseeId, SpecifiedDateTime), -- Composite PRIMARY KEY.
        CONSTRAINT FriendshipStatusToFriendship_FK FOREIGN KEY (RequesterId, AddresseeId)
            REFERENCES Friendship  (RequesterId, AddresseeId), -- Composite FOREIGN KEY.
        CONSTRAINT FriendshipStatusToMyStatus_FK   FOREIGN KEY (StatusCode)
            REFERENCES MyStatus    (StatusCode),
        CONSTRAINT FriendshipStatusToSpecifier_FK  FOREIGN KEY (SpecifierId)
            REFERENCES UserProfile (UserId),
        CONSTRAINT FriendsAreDifferent_CK          CHECK       (RequesterId <> AddresseeId)      
    );
    

    A criação deste design DDL, junto com o trecho anterior, foi testada neste db<>fiddle que roda no SQL Server 2019.

    Assim, toda vez que o Status de uma determinada Amizade precisar ser atualizado, os Usuários teriam apenas que INSERIR uma nova FriendshipStatuslinha, contendo:

    • os valores adequados RequesterIde AddresseeId—retirados da respectiva linha— Friendship;

    • o valor novo e significativo StatusCode—extraído de— MyStatus.StatusCode;

    • o instante exato da INSERção, ou seja, SpecifiedDateTime—de preferência usando uma função de servidor para que você possa recuperá-la e retê-la de maneira confiável—; e

    • o SpecifierIdvalor que indicaria o respectivo UserIdque inseriu o novo FriendshipStatusno sistema —idealmente, com o auxílio das facilidades de seu(s) app(s)—.

    Nesse sentido, vamos supor que a MyStatustabela inclua os seguintes dados — com valores PK que são (a) amigáveis ​​ao usuário final, programador de aplicativos e DBA e (b) pequenos e rápidos em termos de bytes no nível de implementação física —:

    +-——————————-+-—————————-+
     | Código de status | Nome       |
     +-——————————-+-—————————-+
     | R | solicitado |
     +------------+-----------+
     | A | Aceito |
     +------------+-----------+
     | D | Recusado |
     +------------+-----------+
     | B | bloqueado |
     +------------+-----------+
    

    Assim, a FriendshipStatustabela pode conter dados como mostrado abaixo:

    +-———————————-+-———————————-+-———————————————————— ———-+-——————————-+-———————————-+
     | ID do solicitante | ID do destinatário | DataDataEspecificada        | Código de status | EspecificadorId |
     +-———————————-+-———————————-+-———————————————————— ———-+-——————————-+-———————————-+
     | 1750 | 1748 | 01/04/2016 16:58:12.000 | R | 1750 |
     +-------------+-------------+---------------------- ----+------------+-------------+
     | 1750 | 1748 | 2016-04-02 09:13:08.000 | A | 1748 |
     +-------------+-------------+---------------------- ----+------------+-------------+
     | 1750 | 1748 | 2016-04-02 11:02:06.000 | B | 1748 |
     +-------------+-------------+---------------------- ----+------------+-------------+
    

    Como você pode ver, pode-se dizer que a FriendshipStatustabela serve para compor uma série temporal .


    Respostas aos comentários

    Manipulação de dados

    I know this is super old and maybe a dumb (sic) question but, I've been studying this and have been wondering how you'd go about simply getting a user's current friendship status with someone using the FriendshipStatus table. – @Timothy Fisher, on 2020-08-05 02:24:16Z

    First of all, there is nothing wrong with your question and, although this is a design Q & A and data manipulation is a separate and subsequent task, explaining how to get the current or most-recent Status of a given Friendship can definitely assist in showing the advantages of the proposed layout (and therefore it can help a future reader).

    Here the key is approaching the relevant data in terms of sets, since that is one of the main puroposes of adopting a relational frame of mind.

    Deriving the current Status of a Friendship

    Let us suppose that we are working with the following information in the FriendhipStatus table:

     +-———————————-+-———————————-+-———————————————————————-+-——————————-+-———————————-+
     | RequesterId | AddresseeId | SpecifiedDateTime       | StatusCode | SpecifierId |
     +-———————————-+-———————————-+-———————————————————————-+-——————————-+-———————————-+
     |        1750 |        1748 | 2016-04-01 16:58:12.000 | R          |        1750 |
     +-------------+-------------+-------------------------+------------+-------------+
     |        1750 |        1748 | 2016-04-02 09:13:08.000 | A          |        1748 |
     +-------------+-------------+-------------------------+------------+-------------+
     |        1750 |        1748 | 2016-04-02 11:02:06.000 | B          |        1748 |
     +-------------+-------------+-------------------------+------------+-------------+
     |        1825 |        4247 | 2016-05-11 16:28:03.000 | R          |        1825 |
     +-------------+-------------+-------------------------+------------+-------------+
     |        1825 |        4247 | 2016-05-11 19:18:09.000 | A          |        4247 |
     +-------------+-------------+-------------------------+------------+-------------+
     |        1748 |        5342 | 2016-06-11 11:13:05.000 | R          |        1748 |
     +-------------+-------------+-------------------------+------------+-------------+
     |        1748 |        5342 | 2016-06-12 19:03:07.000 | D          |        5342 |
     +-------------+-------------+-------------------------+------------+-------------+
     |        3691 |        1750 | 2016-06-20 16:28:05.000 | R          |        3691 |
     +-------------+-------------+-------------------------+------------+-------------+
     |        3691 |        1750 | 2016-06-20 16:51:10.000 | A          |        1750 |
     +-------------+-------------+-------------------------+------------+-------------+
     |        3691 |        1750 | 2016-06-21 08:05:05.000 | B          |        1750 |
     +-------------+-------------+-------------------------+------------+-------------+
    

    And say we want to obtain the current Status of the Friendship between the User primarily identified by the UserId 1750 and the User primarily identified by the UserId 1748.

    A very good option is employing what is commonly known as a subquery, i.e., a nested DML operation (in this case a SELECT):

    SELECT FS.StatusCode AS CurrentStatusCode
      FROM FriendshipStatus FS
     WHERE FS.RequesterId = 1750 --(a)
       AND FS.AddresseeId = 1748 --(b)
       AND FS.SpecifiedDateTime = (
                                      SELECT MAX(NestedFS.SpecifiedDateTime)
                                            FROM FriendshipStatus NestedFS
                                           WHERE NestedFS.RequesterId = FS.RequesterId
                                             AND NestedFS.AddresseeId = FS.AddresseeId
                                  );
    -- (a), (b) Those “fixed” values can of course be replaced by parameters.
    

    In this manner, we would be exclusively deriving the CurrentStatusCode —contextual alias for FriendshipStatus.StatusCode— in a scalar column in the main SELECT operation. The nested SELECT gets the latest FriendshipStatus.SpecifiedDateTime value —via the MAX() function— for the corresponding Friendship, i.e., the RequesterId and AddresseeId values assigned in the main SELECT, and these three values are in turn used as conditions in the main WHERE clause. As a result, we derive the following column and value for the Requester 1750 and the Addressee 1748:

     +-—————————————————-+
     | CurrentStatusCode |
     +-—————————————————-+
     | B                 |
     +-—————————————————-+
    

    Which means that one of the Friends involved blocked the other.

    And if you want to obtain more information about that Friendship along with the current Status, you simply have to incorporate more relevant columns to the main SELECT:

    SELECT FS.RequesterId,
           FS.AddresseeId,
           FS.SpecifiedDateTime,       
           FS.StatusCode AS CurrentStatusCode,
           FS.SpecifierId
      FROM FriendshipStatus FS
     WHERE FS.RequesterId = 1750
       AND FS.AddresseeId = 1748
       AND FS.SpecifiedDateTime = (
                                      SELECT MAX(NestedFS.SpecifiedDateTime)
                                            FROM FriendshipStatus NestedFS
                                           WHERE NestedFS.RequesterId = FS.RequesterId
                                             AND NestedFS.AddresseeId = FS.AddresseeId
                                  );
    

    Having all those data points you would know, e.g., who “blocked” who and when.

    Views

    If you are interested in simplifying future code regarding Status data retrieval (and make it more “readable”), you can create a view (i.e. a derived table) that, e.g., “hides” the subquery, and you can subsequently SELECT directly from said view.

    Physical-level settings

    Of course, in order to speed up data manipulation performance you have to take care of the design settings at the physical level of abstraction; e.g., the involved tables should be supported by single- and/or multi-column INDEXes, taking into account, e.g., the order of the columns involved in WHERE conditions. Then you should evaluate the data manipulation tendencies with respect to all the relevant INSERT, UPDATE, SELECT and DELETE operations.

    You could as well evaluate the implementation of “materialized” views.

    All the DML code samples shown above, the sample data and other relevant aspects are included in this db<>fiddle so that you can see these exercises “in action”.

    Data constraints

    It seems this would allow Friendships to be made from a user to themselves, e.g. RequesterId and AddresseeId being the same. Is it possible to prevent this on the DBMS side without triggers? Also, can an ON DELETE CASCADE be introduced to both FKs in the Friendship table, e.g. deleting it if a Friend on one side is deleted? I tried creating such a table but at least SQL Server rejected the table creation due to possible cyclic / multiple cascade paths. – @Ray, on 2022-03-26 15:54:22Z

    CHECK constraint

    Yes, you certainly can prevent the values retained in the columns Friendship.RequesterId and Friendship.AddresseeId from being identical in the same row without triggers (which, as you know, should be left as a very last resort). In this case I would make use of a CHECK constraint (that i just added to the DDL logical layout shown in prior sections), which allows handling this requirement declaratively (in contrast to the sub-optimal procedural option with TRIGGERs):

    CONSTRAINT FriendsAreDistinct_CK CHECK (RequesterId <> AddresseeId);
    

    So, if you want to INSERT, e.g., the row that follows:

    INSERT INTO Friendship 
        (RequesterId, AddresseeId, CreatedDateTime)
    VALUES
        (1750, 1750, '2022-03-31 16:58:12.000');
    

    …the DBMS (in your case SQL Server) should reject that row and throw a message like this one:

    Msg 547 Level 16 State 0 Line 2
    The INSERT statement conflicted with the CHECK constraint "FriendsAreDistinct_CK". The conflict occurred in database "Foo", table "dbo.Friendship".
    Msg 3621 Level 0 State 0 Line 2
    The statement has been terminated.
    

    Existence dependencies and TRANSACTIONs

    An important aspect that should be treated carefully when creating the database structure and the related constraints has to do with (1) the order in the creation of the tables and (2) the order of the creation of the constraints, since these factors are instrumental in the representation of the existence dependencies that take place in the business context of concern, so please make sure that you first create the “independent” tables, then continue creating the ones that depend on the existence and constraints of those and so on. As demonstrated in this db<>fiddle running on SQL Server 2019, no issue came about when creating the database structure and constraints.

    In that same regard, if you have to DELETE a row that has FK references, instead of using ON DELETE CASCADE actions (which tend to consume a lot of DBMS resources) I suggest that you carry out the required manipulation operations via TRANSACTIONs, and in order to optimize DBMS resources you also have to take into account the existence dependencies of the concerning data. In this way, you would first DELETE the “dependent” rows (in the conceptual hierarchy) and once all those “dependent” rows have been deleted then you carry out the DELETE of the “main” row of interest, all of this in a single TRANSACTION. Similar considerations apply for UPDATES, thus the data hierarchy also has to be respected in order to optimize the data manipulation processes at the physical level.

    Let us assume that due to a certain reason you have to DELETE a certain UserProfile and all of its related info, so you would proceed deleting

    1. all the related rows in the FriendshipStatus table, then
    2. all the related rows in the Friendship table, and after that
    3. the exact row of concern in the UserProfile table.

    All of the above in that specific order, inside the same TRANSACTION, so as to guarantee that all the operations are either committed or discarded as a single unit of work by the DBMS.

    Note: In agreement with the previous deliberations, it is very important to point out that all the INSERT, UPDATE and DELETE operations of a given database should be performed exclusively within TRANSACTIONs inside stored procedures which only some privileged database users can execute. This strategy optimizes data integrity protection in particular and database management in general.

    Further constraints

    Generally, in scenarios like the one discussed here, a designer has to set up further data constraints, but I am not going to address those aspects because it can be a very didactic endeavour for future readers, and as you know, constraints can change from one business context to the other.

    Additional considerations on the Friendship and FriendshipStatus tables

    Could you explain little bit more why do we need Friendship table? I imagine if user would like to request friendship with other user it would mean INSERT into FriendshipStatus table with status code R. Then if receiver accepts it then it is another insert with status code A. It seems all relevant data would be kept there - I am confused why do need to store combination of those user ids in another table? Isn't content of Friendship duplicated in FriendshipStatus? Basically if there is combination of userId1 and userId2 in FriendshipStatus it goes to Friendship table. Why? – @Piotr, on 2022-07-30 19:08:10Z

    If I address your inquiries here in the answer body I hit the “limit of 30000 characters” within just a few more paragraphs, and the comment box is not well suited for a proper reply (comments are meant to be transient, offer very poor formatting options, permit even fewer characters, etc.), therefore I have uploaded my reply to your questions in this external file.


    Relevant posts

    You might as well be interested in:

    • This answer in which I suggest a basic method to deal with a common many-to-many relationship between two dissimilar entity types.
    • O diagrama IDEF1X mostrado na Figura 1 que ilustra esta outra resposta . Preste atenção especial aos tipos de entidade denominados Casamento e Progênie , pois são mais dois exemplos de como lidar com o “Problema de Explosão de Peças”.
    • Este post apresenta uma breve deliberação sobre como manter diferentes informações em uma única coluna.
    • 31

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