2009-12-10 4 views
0

J'ai une colonne dans le tableau où ce nom de colonne est articles contient la valeur comme cetteproblème dans SQL Query

itemID items 
1  school,college 
2  place, country 
3  college,cricket 
4  School,us,college 
5  cricket,country,place 
6  football,tennis,place 
7  names,tennis,cricket 
8  sports,tennis 

Maintenant, je dois écrire une requête de recherche

Ex: si l'utilisateur types 'cricket' dans une zone de texte et clique sur le bouton que j'ai besoin de vérifier dans la colonne articles pour le cricket.

Dans le tableau I ont 3 lignes avec cricket dans les articles colonne (Itemid = 3, 5, 7)

Si les types d'utilisateur dans tennis,cricket je besoin d'obtenir les dossiers qui correspondent à l'un. Donc, je dois obtenir 5 rangs (ItemId = 3, 5, 6, 7, 8)

Comment écrire une requête pour cette exigence?

+0

Hmmm, ont déjà fait l'connectionnwith la base de données? – kiewic

+0

Qu'attendez-vous si l'utilisateur tape 'foot' ou 'enis' (une partie d'un mot)? –

+1

Une structure de table de forme non première normale- http://en.wikipedia.org/wiki/Database_normalization#Non-first_normal_form_.28NF.C2.B2_or_N1NF.29 – RichardOD

Répondre

1

Je pense que dans l'intérêt de la validité des données, il devrait être normalisé afin que vous divisiez les éléments dans une table séparée avec un élément sur chaque ligne.

Dans les deux cas, voici un échantillon de travail qui utilise une fonction définie par l'utilisateur de diviser la chaîne entrant dans une variable de table et utilise ensuite JOIN avec un LIKE

CREATE FUNCTION dbo.udf_ItemParse 
(
    @Input VARCHAR(8000), 
    @Delimeter char(1)='|' 
) 
RETURNS @ItemList TABLE 
(
    Item VARCHAR(50) , 
    Pos int 
) 
AS 
BEGIN 

DECLARE @Item varchar(50) 
DECLARE @StartPos int, @Length int 
DECLARE @Pos int 

SET @Pos = 0 

WHILE LEN(@Input) > 0 
BEGIN 
    SET @StartPos = CHARINDEX(@Delimeter, @Input) 
    IF @StartPos < 0 SET @StartPos = 0 
     SET @Length = LEN(@Input) - @StartPos - 1 

    IF @Length < 0 SET @Length = 0 
     IF @StartPos > 0 
     BEGIN 
      SET @Pos = @Pos + 1 
      SET @Item = SUBSTRING(@Input, 1, @StartPos - 1) 
      SET @Input = SUBSTRING(@Input, @StartPos + 1, LEN(@Input) - @StartPos) 
     END 
     ELSE 
     BEGIN 
      SET @Pos = @Pos+1 
      SET @Item = @Input 
      SET @Input = '' 
     END 

     INSERT @ItemList (Item, Pos) VALUES(@Item, @Pos) 
    END 
    RETURN 
END 
GO 
DECLARE @Itemstable TABLE 
(
    ItemId INT, 
    Items VarChar (1000) 
) 
INSERT INTO @Itemstable 
SELECT 1 itemID, 'school,college' items UNION 
SELECT 2, 'place, country' UNION 
SELECT 3, 'college,cricket' UNION 
SELECT 4, 'School,us,college' UNION 
SELECT 5, 'cricket,country,place' UNION 
SELECT 6, 'footbal,tenis,place' UNION 
SELECT 7, 'names,tenis,cricket' UNION 
SELECT 8, 'sports,tenis' 

DECLARE @SearchParameter VarChar (100) 
SET @SearchParameter = 'cricket' 

SELECT DISTINCT ItemsTable.* 
FROM @Itemstable ItemsTable 
    INNER JOIN udf_ItemParse (@SearchParameter, ',') udf 
     ON ItemsTable.Items LIKE '%' + udf.Item + '%' 


SET @SearchParameter = 'cricket,tenis' 

SELECT DISTINCT ItemsTable.* 
FROM @Itemstable ItemsTable 
    INNER JOIN udf_ItemParse (@SearchParameter, ',') udf 
     ON ItemsTable.Items LIKE '%' + udf.Item + '%' 
5

Vous devez commencer par la refonte de votre base de données car c'est une très mauvaise structure. Vous ne stockez JAMAIS une liste délimitée par des virgules dans un champ. Pensez d'abord aux champs waht dont vous avez besoin, puis concevez une base de données appropriée.

+4

** Jamais ** est un absolu et il s'avère qu'il y a toujours une exception (pour des raisons de pragmatisme sinon de pure science informatique). Alors que je suis d'accord qu'il est probable (mais pas certain) que le schéma peut et doit être amélioré, il est également possible de répondre à la question pour le schéma donné. Et oui, j'ai eu des cas où nous avons stocké des données délimitées soit pour éviter une complexité injustifiée, soit parce que c'était un cas limite et c'est comme ça que ça a fonctionné. – Murph

+0

@ Murph-like Forme non-première normale (NF² ou N1NF) - http://en.wikipedia.org/wiki/Database_normalization#Non-first_normal_form_.28NF.C2.B2_or_N1NF.29. C'est généralement une mauvaise idée cependant. – RichardOD

+0

@Murph: c'est une de ces choses que si vous devez demander, c'est trop cher. En d'autres termes, si vous n'en savez pas assez pour vous méfier du design, vous ne devriez pas l'utiliser du tout. –

1

Pour un seul élément:

SELECT itemID, items FROM MyTable WHERE items LIKE '%cricket%' 

Pour les articles multiples:

SELECT itemID, items FROM MyTable WHERE items LIKE '%tennis%' or items LIKE '%cricket%' 

Vous aurez besoin d'analyser l'entrée et les diviser et ajouter chaque élément à la requête:

items LIKE '%item1%' or items LIKE '%item2%' or items LIKE '%item3%' ... 
+0

Bien sûr, cela aura une performance horrible, mais étant donné que le mauvais design est le seul choix à moins que l'affiche ne puisse configurer l'indexation de texte intégral (ce qui dépend de la base de données qu'il utilise). – HLGEM

3

La très mauvaise structure de cette table (contenant plusieurs valeurs dans une colonne) est la raison pour laquelle vous faites face à ce problème. Votre meilleure option est de normaliser la table.

Mais si vous ne pouvez pas, vous pouvez utiliser l'opérateur « comme », avec un caractère générique

Select * From Table 
    Where items Like '%cricket%' 

ou

Select * From Table 
    Where items Like '%cricket%' 
    or items Like '%tenis%' 

Vous aurez besoin de construire dynamiquement ces requêtes SQL à partir de la entrées que l'utilisateur fait. L'autre alternative consiste à écrire du code sur le serveur pour transformer la liste de paramètres délimités par des virgules en une table table ou une table temporaire et ensuite s'y joindre.

+1

et qu'en est-il de ping-pong? – Peter

+0

ou ma place dans le pays –

0

Pourquoi exactement utiliser Pourquoi utilisez-vous une base de données? Je veux dire: vous n'utilisez clairement pas son potentiel. Si vous aimez utiliser des éléments séparés par des virgules, essayez un fichier.

2

Les valeurs délimitées dans les colonnes sont presque toujours une mauvaise conception de table. Fixez la structure de votre table.

Si pour une raison quelconque, vous ne parvenez pas à le faire, le mieux que vous pouvez espérer est la suivante:

SELECT * FROM [MyTable] WHERE items LIKE '%CRICKET%' 

C'est encore très mauvais, pour deux raisons importantes:

  1. Correct. Il retournera des valeurs que seulement contiennent le mot cricket. En utilisant votre exemple de tennis, que se passe-t-il si vous avez aussi un objet "chaussures de tennis"?
  2. Performances. Ce n'est pas sargable, ce qui signifie que la requête ne fonctionnera pas avec les index que vous pourriez avoir sur cette colonne. Cela signifie que votre requête sera probablement incroyablement lente.

Si vous avez besoin d'aide de fixation de cette structure, la solution consiste à ajouter une autre table — que nous appellerons TableItems — avec une colonne pour votre ItemID qui sera une clé étrangère à votre table originale et un champ item (singulier) pour chacune de vos valeurs d'article. Ensuite, vous pouvez joindre à cette table et correspondre exactement à une valeur de colonne. Si ces articles fonctionnent plus comme des catégories, où vous voulez des lignes avec l'article "Cricket" pour correspondre au même objet de cricket, vous voulez aussi une troisième table pour être une intersection entre votre table d'origine et l'autre que je viens de vous créer.

+0

en effet, d'où ma remarque «et qu'en est-il de ping-pong» – Peter

0

En MySQL, créer un index texte intégral sur votre table:

CREATE FULLTEXT INDEX fx_mytable_items ON mytable (items) 

et d'émettre cette requête:

SELECT * 
FROM mytable 
WHERE MATCH(items) AGAINST ('cricket tennis' IN BOOLEAN MODE)