Come faccio a creare un vincolo di tabella per impedire valori duplicati su due colonne?

StackOverflow https://stackoverflow.com/questions/626609

  •  06-07-2019
  •  | 
  •  

Domanda

Ho la seguente tabella:

CREATE TABLE [dbo].[EntityAttributeRelship](
    [IdNmb] [int] IDENTITY(1,1) NOT NULL,
    [EntityIdNmb] [int] NOT NULL,
    [AttributeIdNmb] [int] NOT NULL,
    [IsActive] [bit] NOT NULL CONSTRAINT [DF_EntityAttributeRelship_IsActive]  DEFAULT ((0)),
CONSTRAINT [PK_EntityAttributeRelship] PRIMARY KEY CLUSTERED 
([IdNmb] ASC) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY]

Una parte dei dati nella tabella assomiglia a qualcosa del genere:

IdNmb    EntityIdNmb    AttributeIdNmb  IsActive
1        22             7               0
2        22             8               0
3        22             9               0
4        22             10              1

Voglio aggiungere un vincolo per assicurarmi che nessuno aggiunga o aggiorni un record con IsActive = 1, se esiste già un record per EntityIdNmb dove IsActive = 1.

Come posso farlo?

È stato utile?

Soluzione

Se si utilizza SQLServer è possibile creare una vista indicizzata in cluster.

CREATE VIEW dbo.VIEW_EntityAttributeRelship WITH SCHEMABINDING AS
SELECT EntityIdNmb 
FROM dbo.EntityAttributeRelship
WHERE IsActive = 1
GO

CREATE UNIQUE CLUSTERED INDEX UIX_VIEW_ENTITYATTRIBUTERELSHIP 
  ON dbo.VIEW_EntityAttributeRelship (EntityIdNmb)

Questo assicura che ci sia un solo EntityIdNmb nella tua tabella con IsActive = 1.

Altri suggerimenti

Sembra che tu debba implementare un trigger (supponendo che il tuo prodotto db lo supporti). Se si desidera solo una voce attiva e una inattiva, funzionerà un indice univoco. Altrimenti, dovrai scrivere una sorta di vincolo personalizzato o un trigger (probabilmente 2 - uno per gli inserti, uno per gli aggiornamenti) che assicuri di non avere 2 record con lo stesso ID in cui entrambi sono attivi.

Se stai usando MSSQL (penso che sia l'aspetto della tua sintassi), crea una vista che includa solo le righe con IsActive = 1, quindi inserisci un indice univoco su EntityIdNmb nella vista.

In PostgreSQL, con cui ho lavorato di più di recente, puoi creare un indice parziale: http://www.postgresql.org/docs/8.3/interactive/ indici-partial.html

Il problema con la scrittura del trigger è decidere se si desidera rifiutare il record, modificare il valore su 0 invece di uno o aggiornare il vecchio record su zero e lasciarlo come uno. Se si sta eliminando il record con il valore 1, è necessario modificare un altro record per essere quello attivo, come scegliere quale? Una volta che puoi definire ciò che vuoi fare all'interno del trigger, possiamo aiutarti a progettare meglio il processo.

Facciamo questi ultimi due passaggi per rendere qualsiasi indirizzo il principale indirizzo postale nel nostro database. La nostra regola aziendale è uno e solo un indirizzo può essere quello principale e se ci sono indirizzi uno deve essere contrassegnato come principale. La chiave di questo tipo di trigger è ricordare che inserimenti / aggiornamenti / eliminazioni possono verificarsi in batch (anche se questa non è la norma) e assicurarsi che il trigger funzioni in modo basato su set. Quando sono arrivato qui, il nostro ha implementato l'elaborazione multi-riga attraverso un cursore che è diventato un male quando ho dovuto aggiornare 200.000 indirizzi in un'importazione. (Nota per gli inesperti: non usare mai il cursore in un trigger!)

A cosa serviranno i record inattivi? Sono inutilizzati e semplicemente lì per tenere traccia dei record precedentemente attivi? In tal caso, sarebbe possibile dividere i dati in più tabelle? Qualcosa come ...

EntityAttributeRelship (IDNmb, EntityIDNmb, AttributeIDNmb)

EntityAttributeRelshipHistory (IDNmb, EntityIDNmb, AttributeIDNmb)

Se si trova nella tabella EntityAttributeRelship, è attivo. Se è nella tabella della cronologia, è stato attivato ad un certo punto e da allora è stato disattivato?

Se hai bisogno di tutto in una tabella, vorrei seguire il suggerimento di todd.run di usare un trigger.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top