2011-03-01 8 views
2

J'ai besoin de stocker des séquences/listes dans la base de données (SQL Server 2008), puis de trouver l'ID d'une séquence particulière dans la base de données s'il en existe.Comment stocker et rechercher une séquence dans un SGBDR?

Par exemple, j'ai deux séquences:

Séquence 1: A, B, C Séquence 2: A, C, M, N

Actuellement, ils sont stockés dans le tableau suivant. (Je suis OK avec changement de la table si cela rend les choses plus faciles.)

seq_id token order 
1  A  0 
1  B  1 
1  C  2 
2  A  0 
2  C  1 
2  M  2 
2  N  3 

Je voudrais écrire une requête pour renvoyer l'identifiant d'une séquence donnée, par exemple "A, B, C", s'il y a une correspondance exacte. La longueur de la séquence est inconnue à l'avance. Je vous remercie!

Répondre

3

Qu'est-ce que vous avez besoin est appelé division relationnelle (voir Celko). La meilleure solution dépendra de votre moteur rdb. Si vous êtes en mesure de le faire - la solution la plus populaire serait:

  1. Express requête sous la forme d'une table (une table de A, B, C)
  2. intérieur se joindre à votre table à la table existante, groupe par seq_id, compter les éléments des groupes
  3. Utilisez compte pour filtrer les séquences qui ne sont pas exactes (ie. lors de la recherche a, B, C le nombre doit être 3)

Disons que vous avez un # table de requête contenant des jetons et des tris que vous souhaitez trouver (j'utilise tri au lieu de commander pour éviter les conflits avec les mots-clés réservés)

create table #query 
(
token nvarchar(1) 
,sort int 
) 

insert into #query select 'A',0 
insert into #query select 'B',1 
insert into #query select 'C',2 
go 

select seq_id 
from dbo.sequences s 
inner join #query q 
    on q.token = s.token 
     and q.sort = s.sort 
group by s.seq_id 
having count(*) = (select count(*) from #query) 

Renvoie le (s) identificateur (s) correspondant à votre requête. Dans les versions plus récentes de MsSql, on utilisait une variable de table au lieu de #query, mais la technique peut être appliquée universellement.

0

Pourquoi ne pas stocker tel quel:

seq_id token 
1  A,B,C  
2  A,C,M,N 

requête devient trivial

+0

Mon exemple est simplifié pour rendre la question courte. En réalité, je stocke le jeton (plus brisé en plus petites parties) dans une autre table et stocke son PK dans la colonne jeton. Si je stocke les PK aplatis, je crains que la valeur ne devienne invalide une fois que certains jetons sont supprimés dans une autre table. En outre, votre solution rendra d'autres requêtes plus difficiles, comme obtenir les 4 premiers jetons d'une séquence donnée, ou trouver des correspondances basées sur le premier jeton n. – hli

1

Qu'est-ce que vous avez besoin est une signature spécifique d'ordre pour chaque séquence. À l'aide de SQL Server 2008, vous pouvez utiliser la construction Pour le chemin Xml pour assembler une signature pour chaque séquence et les critères, puis les comparer l'un à l'autre. Évidemment, ce ne sera pas rapide. Vous pouvez améliorer considérablement la vitesse en stockant la signature dans la table appropriée pour chaque séquence au moment où ils sont enregistrés ou leur appartenance est modifiée (peut également utiliser un déclencheur). De plus, j'ai simplement utilisé la signature brute ici. Cependant, normalement, je serais enclin à utiliser un hachage de la valeur assemblée pour la signature en utilisant la fonction Hashbytes.

Declare @TestInputs Table (
          seq_id int not null 
          , token char(1) not null 
          , [order] int not null 
          ) 
Insert @TestInputs(seq_id, token, [order]) 
Values (1,'A',0) 
    , (1,'B',1) 
    , (1,'C',2) 
    , (2,'A',0) 
    , (2,'C',1) 
    , (2,'M',2) 
    , (2,'N',3); 

Declare @Criteria Table (
         token char(1) not null 
         , [order] int not null 
         ) 
Insert @Criteria(token, [order]) 
Values ('A',0) 
    , ('B',1) 
    , ('C',2); 

With Criteria As 
    (
    Select (
      Select '|' + Token 
      From @Criteria 
      Order By [order] 
      For Xml Path('') 
      ) As Signature 
    ) 
    , InputSignatures As 
    (
    Select T.seq_id 
     , (
      Select '|' + T1.Token 
      From @TestInputs As T1 
      Where T1.seq_id = T.seq_id 
      Order By T1.[order] 
      For Xml Path('') 
      ) As Signature 
    From @TestInputs As T 
    Group By T.seq_id 
    ) 
Select I.* 
From InputSignatures As I 
    Join Criteria As C 
     On C.Signature = I.Signature 
Questions connexes