2008-11-26 3 views
2

J'ai deux tables simples dans ma base de données. Une table "carte" qui contient l'identifiant, le nom et le texte d'une carte, et une table "règles" qui contient l'identifiant de la carte, et un texte détaillant les décisions pour la carte.Comment créer une table/requête de référence croisée pour mes données?

Assez souvent dans le texte de règle, il y a une référence à une autre carte dans la base de données. Il est assez facile de trouver cela dans le texte, car chaque carte est encapsulée entre guillemets dans le texte. Il n'est pas rare d'avoir plusieurs cartes référencées dans le texte de la décision. Ce que je voudrais faire, c'est pouvoir créer une table de références croisées (ou une procédure si elle est suffisamment efficace) pour que lorsque je soumets une requête pour une carte, je puisse trouver tous les enregistrements de décision qui font directement référence la carte à travers l'Id et obtenir tous les enregistrements de décision où le nom de la carte est référencé dans le texte.

Quelle serait la meilleure façon d'aborder cela? Mon environnement est SQL 2005, mais toutes les solutions "DB agnostiques" sont largement acceptées ici.

Répondre

4

Cela semble être un problème relationnel assez simple et commun qui est résolu par une table de références croisées. Par exemple:

CREATE TABLE dbo.Cards (
    id  INT   NOT NULL, 
    name  VARCHAR(50) NOT NULL, 
    card_text VARCHAR(4000) NOT NULL, 
    CONSTRAINT PK_Cards PRIMARY KEY CLUSTERED (id) 
) 
GO 
CREATE TABLE dbo.Card_Rulings (
    card_id  INT   NOT NULL, 
    ruling_number INT   NOT NULL, 
    ruling_text VARCHAR(4000) NOT NULL, 
    CONSTRAINT PK_Card_Rulings PRIMARY KEY CLUSTERED (card_id, ruling_number) 
) 
GO 
CREATE TABLE dbo.Card_Ruling_Referenced_Cards (
    parent_card_id INT NOT NULL, 
    ruling_number  INT NOT NULL, 
    child_card_id  INT NOT NULL, 
    CONSTRAINT PK_Card_Ruling_Referenced_Cards PRIMARY KEY CLUSTERED (parent_card_id, ruling_number, child_card_id) 
) 
GO 
ALTER TABLE dbo.Card_Rulings 
ADD CONSTRAINT FK_CardRulings_Cards FOREIGN KEY (card_id) REFERENCES dbo.Cards(id) 
GO 
ALTER TABLE dbo.Card_Ruling_Referenced_Cards 
ADD CONSTRAINT FK_CardRulingReferencedCards_CardRulings FOREIGN KEY (parent_card_id, ruling_number) REFERENCES dbo.Card_Rulings (card_id, ruling_number) 
GO 
ALTER TABLE dbo.Card_Ruling_Referenced_Cards 
ADD CONSTRAINT FK_CardRulingReferencedCards_Cards FOREIGN KEY (child_card_id) REFERENCES dbo.Cards(id) 
GO 

Pour obtenir toutes les décisions de carte pour une carte:

SELECT * 
FROM dbo.Cards C 
INNER JOIN dbo.Card_Rulings CR ON CR.card_id = C.id 
WHERE C.id = @card_id 

Pour obtenir toutes les cartes référencées dans une décision rendue par une carte donnée:

SELECT C.* 
FROM dbo.Card_Rulings CR 
INNER JOIN dbo.Card_Ruling_Referenced_Cards CRRC ON CRRC.parent_card_id = CR.card_id 
INNER JOIN dbo.Cards C ON C.id = CRRC.child_card_id 
WHERE CR.card_id = @card_id 

C'était hors le dessus de ma tête et n'est pas testé, donc il pourrait y avoir des erreurs syntaxiques, etc

Votre front end serait responsable f ou maintenir les références. Ceci est probablement souhaitable car cela évite que quelqu'un oublie de mettre des guillemets autour d'un nom de carte dans un texte en vigueur, etc.

1

Je vous recommande de créer une autre table qui stocke vos références. Ensuite, créez un déclencheur d'insertion et de mise à jour qui maintient cette table. De cette façon, vous obtiendrez une requête plus rapide pour renvoyer les données que vous recherchez.

Je reconnais que le remplissage initial de cette table peut être un peu difficile, c'est pourquoi je montre ci-dessous quelques exemples de données (et de requêtes) que vous pouvez utiliser pour vous aider à démarrer.

Declare @Card Table(Id Int, Name VarChar(20), CardText VarChar(8000)) 

Declare @Ruling Table(CardId Int, CardRuling VarChar(8000)) 

Insert Into @Card Values(1, 'Card 1', 'This is the card ID = 1') 
Insert Into @Card Values(2, 'Card 2', 'This is the card id = 2.') 
Insert Into @Card Values(3, 'Card 3', 'This is the card id = 3.') 

Insert Into @Ruling Values(1, 'This is the ruling for 1 which references "2"') 
Insert Into @Ruling Values(2, 'This is the ruling for 2 which references nothing') 
Insert Into @Ruling Values(3, 'This is the ruling for 3 which references "1" and "2"') 

Declare @CardId Int 
Set @CardId = 1 

Select * 
From @Card As Card 
     Inner Join @Ruling As Ruling 
      On Card.Id = Ruling.CardId 
     Left Join @Card As CardReferences 
      On Ruling.CardRuling Like '%"' + Convert(VarChar(10), CardReferences.Id) + '"%' 

EDIT:

La raison pour laquelle je suggère une autre table est parce que vous serez probablement déçu par la performance de cette requête, en particulier pour les grandes tables.

Questions connexes