Question

Je voudrais savoir quelle est la structure de données / stratégie de stockage que je devrais utiliser pour ce problème.

Chaque entrée de données dans la base de données consiste en une liste de plusieurs articles commandés, tels que A-B-C-D, où A, B, C, D sont des éléments différents.

Supposons que j'ai 3 entrées dans une base de données,

A-B-C-D

E-F-G

G-H-B-A

Lorsque l'utilisateur est entré quelques éléments désordonnées, je dois trouver l'entrée ordonnée correspondant (ies) de la base de données. Par exemple, si l'utilisateur entre A, B, G, H, je veux revenir G-H-B-A de la base de données à l'utilisateur.

Quelle devrait être ma stratégie de stockage des données?

Était-ce utile?

La solution

Vous êtes mieux stocker les éléments commandés et désordonnées séparément, sinon vous devrez rechercher sur toutes les permutations des éléments commandés, ce qui serait du temps.

Essayez ceci:

/* Create a table to track your items (A, B, C, etc.). It contains all possible elements */
CREATE TABLE [Items](
    [Value] [char](1) NOT NULL,
 CONSTRAINT [PK_Items] PRIMARY KEY CLUSTERED ([Value]))

/* Create a table to track their grouping and stated ordering */
CREATE TABLE [Groups](
    [ID] [int] NOT NULL,
    [Order] [text] NOT NULL,
 CONSTRAINT [PK_Groups] PRIMARY KEY CLUSTERED ([ID]))

/* Create a mapping table to associate them */
CREATE TABLE [ItemsToGroups](
    [Item] [char](1) NOT NULL,
    [Group] [int] NOT NULL
)

ALTER TABLE [ItemsToGroups]  WITH CHECK ADD CONSTRAINT [FK_ItemsToGroups_Groups] FOREIGN KEY([Group])
REFERENCES [Groups] ([ID])

ALTER TABLE [ItemsToGroups] CHECK CONSTRAINT [FK_ItemsToGroups_Groups]

ALTER TABLE [ItemsToGroups]  WITH CHECK ADD CONSTRAINT [FK_ItemsToGroups_Items] FOREIGN KEY([Item])
REFERENCES [Items] ([Value])

ALTER TABLE [ItemsToGroups] CHECK CONSTRAINT [FK_ItemsToGroups_Items]

/* Populate your tables. 
   Items should have eight rows: A, B, C,...H
   Groups should have three rows: 1:ABCD, 2:EFG, 3:GHBA
   Items to groups should have eleven rows: A:1, B:1,...A:3 */

/* You will want to pass in a table of values, so set up a table-valued parameter
   First, create a type to support your input list */
CREATE TYPE ItemList AS TABLE (e char(1) NOT NULL PRIMARY KEY)
DECLARE @Input ItemList
GO

/* Create a stored procedure for your query */
CREATE PROCEDURE SelectOrderedGroup @Input ItemList READONLY AS
    SELECT *
    FROM Groups
    WHERE Groups.ID NOT IN (
        SELECT [Group]
        FROM ItemsToGroups
        WHERE Item NOT IN (SELECT e FROM @Input)
    )
GO

/* Now when you want to query them: */
DECLARE @MyList ItemList
INSERT @MyList(e) VALUES('G'),('H'),('B'),('A')
EXEC SelectOrderedGroup @MyList

Le ci-dessus retournera 3: GHBA, comme vous voulez. Si vous passez DRASA vous récupérerez 1: ABCD, encore une fois comme vous cherchez. Si vous passez en C, vous récupérerez rien, car aucun groupe se compose de seulement C.

Vous voudrez probablement utiliser un paramètre pour votre entrée, comme indiqué ci-dessus, mais vous pouvez convertir la finale SELECT à une liste simple et supprimer le type ItemList.

Autres conseils

Diviser les listes en éléments individuels et le travail à ce niveau.

Quelques tableaux:

listes

  • ID (PK)
  • séquence (les "A-B-C-D" entrées ci-dessus)
  • [tout ce]

éléments

  • ID (PK)
  • nom (valeur, mot, tout ce qui est logique)
  • [tout ce]

list_items

  • LIST_ID
  • ITEM_ID
  • [int ordinal, si "G-H-B-A" et "A-B-G-H" sont considérés comme des séquences différentes]

(PK composite list_id, item_id [, ordinal] sur celle-ci, un grand nombre de base: nombre relation)

Certaines données, il est donc plus clair que les tableaux représentent:

INSERT INTO items (ID, name) VALUES (1, 'A'), (2, 'B'), (3, 'G'), (4, 'H');
INSERT INTO lists (ID, sequence) VALUES (1, 'A-B-G-H');
INSERT INTO list_items (list_ID, item_ID) VALUES (1, 1), (1, 2), (1, 3), (1, 4);
INSERT INTO lists (ID, sequence) VALUES (2, 'B-A-G');
INSERT INTO list_items (list_ID, item_ID) VALUES (2, 2), (2, 1), (2, 3);

Et enfin, pour trouver des listes qui contiennent tous articles (A, B, G, H):

SELECT lists.sequence FROM lists
JOIN list_items ON lists.ID = list_items.list_ID
JOIN items AS i1 ON list_items.item_ID = i1.ID HAVING i1.name = 'A'
JOIN items AS i2 ON list_items.item_ID = i2.ID HAVING i2.name = 'B'
JOIN items AS i3 ON list_items.item_ID = i3.ID HAVING i3.name = 'G'
JOIN items AS i4 ON list_items.item_ID = i4.ID HAVING i4.name = 'H'

Cela devrait retourner des listes comme "A-B-G-H", "G-H-A-B", "H-A-T-B-A-G", etc, mais pas "B-U-G-H-U-T" (non A) ou "B-A-T-H" (pas G) - toutes les conditions doivent être remplies. Faire un « tout » recherche peut être un peu plus impliqué (écrire dans ma tête au cours du déjeuner, mais RIGHT JOIN seul entraînerait probablement toutes sortes de doublons et lenteur).

Il ne la carte des génomes ou redéfinissent le langage humain, mais devrait être acceptable pour un ensemble de données de bonne taille. De toute façon, il faut éviter le stockage de chaque liste en tant que varchar et faire des choses « de WHERE sequence LIKE '%A%' AND sequence LIKE '%B%' » à moins que vous ne pouvez absolument pas gérer le travail supplémentaire pour ajouter de nouvelles données.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top