Eu tenho 3 tabelas relevantes no meu banco de dados.
CREATE TABLE dbo.Group
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.User
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.Ticket
(
ID int NOT NULL,
Owner int NOT NULL,
Subject varchar(50) NULL
)
Os usuários pertencem a vários grupos. Isso é feito através de um relacionamento muitos para muitos, mas irrelevante neste caso. Um ticket pode pertencer a um grupo ou usuário, através do campo dbo.Ticket.Owner.
Qual seria a maneira MAIS CORRETA de descrever esse relacionamento entre um ticket e, opcionalmente, um usuário ou um grupo?
Eu estou pensando que eu deveria adicionar um sinalizador na tabela de tickets que diz que tipo possui.
sql-server
relational-database
Darthg8r
fonte
fonte
Respostas:
Você tem algumas opções, todas variando em "correção" e facilidade de uso. Como sempre, o design certo depende das suas necessidades.
Você pode simplesmente criar duas colunas no Ticket, OwnedByUserId e OwnedByGroupId, e ter chaves estrangeiras anuláveis em cada tabela.
Você pode criar tabelas de referência M: M, permitindo os relacionamentos ticket: usuário e ticket: grupo. Talvez no futuro você deseje permitir que um único ticket seja de propriedade de vários usuários ou grupos? Esse design não impõe que um ticket deva pertencer apenas a uma única entidade.
Você pode criar um grupo padrão para cada usuário e ter tickets simplesmente pertencentes a um grupo verdadeiro ou a um grupo padrão do usuário.
Ou (minha escolha) modele uma entidade que atue como base para usuários e grupos e tenha tickets pertencentes a essa entidade.
Aqui está um exemplo aproximado usando seu esquema publicado:
fonte
SELECT t.Subject AS ticketSubject, CASE WHEN u.Name IS NOT NULL THEN u.Name ELSE g.Name END AS ticketOwnerName FROM Ticket t INNER JOIN Party p ON t.Owner=p.PartyId LEFT OUTER JOIN User u ON u.ID=p.PartyId LEFT OUTER JOIN Group g on g.ID=p.PartyID;
No resultado, você teria todos os assuntos e nome do proprietário do ticket.A primeira opção na lista de @Nathan Skerl é o que foi implementado em um projeto com o qual trabalhei, onde um relacionamento semelhante foi estabelecido entre três tabelas. (Um deles referenciou outros dois, um de cada vez.)
Portanto, a tabela de referência tinha duas colunas de chave estrangeira e também havia uma restrição para garantir que exatamente uma tabela (não ambas, nem nenhuma) fosse referenciada por uma única linha.
Veja como ele pode parecer quando aplicado às suas tabelas:
Como você pode ver, a
Ticket
tabela possui duas colunasOwnerGroup
eOwnerUser
, ambas são chaves estrangeiras anuláveis. (As respectivas colunas nas outras duas tabelas são transformadas em chaves primárias de acordo.) ACK_Ticket_GroupUser
restrição de verificação garante que apenas uma das duas colunas de chave estrangeira contenha uma referência (a outra sendo NULL, é por isso que ambas precisam ser anuláveis).(A chave primária ativada
Ticket.ID
não é necessária para esta implementação específica, mas definitivamente não faria mal ter uma em uma tabela como essa.)fonte
RefID
,RefType
ondeRefType
é um identificador fixo da tabela de destino. Se você precisar de integridade, poderá fazer verificações na camada de gatilho ou aplicativo. A recuperação genérica é possível neste caso. O SQL deve permitir uma definição de FK assim, facilitando nossas vidas.Ainda outra opção é ter, em
Ticket
, uma coluna especificando o tipo de entidade proprietária (User
ouGroup
), a segunda coluna com referênciaUser
ouGroup
id e NÃO usar chaves estrangeiras, mas confiar em um gatilho para impor a integridade referencial.Duas vantagens que vejo aqui sobre o excelente modelo de Nathan (acima):
fonte
Outra abordagem é criar uma tabela de associação que contenha colunas para cada tipo de recurso em potencial. No seu exemplo, cada um dos dois tipos de proprietários existentes possui sua própria tabela (o que significa que você tem algo a referenciar). Se este for sempre o caso, você pode ter algo parecido com isto:
Com esta solução, você continuaria adicionando novas colunas ao adicionar novas entidades ao banco de dados e excluir e recriar o padrão de restrição de chave estrangeira mostrado por @Nathan Skerl. Esta solução é muito semelhante à @ Nathan Skerl, mas parece diferente (de acordo com a preferência).
Se você não tiver uma nova tabela para cada novo tipo de proprietário, talvez seja bom incluir um owner_type em vez de uma coluna de chave estrangeira para cada potencial proprietário:
Com o método acima, você pode adicionar quantos tipos de proprietários desejar. O Owner_ID não teria uma restrição de chave estrangeira, mas seria usado como uma referência para as outras tabelas. A desvantagem é que você teria que olhar para a tabela para ver o que o proprietário digita, pois não é imediatamente óbvio com base no esquema. Eu sugeriria isso apenas se você não conhecer os tipos de proprietário com antecedência e eles não estarão vinculados a outras tabelas. Se você conhece os tipos de proprietários de antemão, eu usaria uma solução como @ Nathan Skerl.
Desculpe se eu entendi errado o SQL, acabei de jogar isso juntos.
fonte
Eu acho que seria a maneira mais geral de representar o que você deseja, em vez de usar uma bandeira.
fonte