问题在SQL查询

问题描述:

我的表,其中此列名项目有一个列包含这样问题在SQL查询

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 

值现在我需要写一个搜索查询

例如:如果用户将'板球'输入到文本框中,然后单击我需要检查板球项目的按钮。

在该表中我有3排,cricket柱(项目Id = 3,5,7)

如果tennis,cricket用户键入然后我需要得到匹配的任一个的记录。所以我需要得到5行(ItemId = 3,5,6,7,8)

如何为此需求编写查询?

+0

嗯,已经做了connectionnwith数据库? – kiewic 2009-12-10 14:39:37

+0

如果用户输入'foot'或'enis'(单词的一部分),你会期望什么? – 2009-12-10 14:44:51

+1

非第一范式表结构 - http://en.wikipedia.org/wiki/Database_normalization#Non-first_normal_form_.28NF.C2.B2_or_N1NF.29 – RichardOD 2009-12-10 14:45:55

我认为,为了提高数据的有效性,应该对其进行规范化处理,以便将项目拆分为一个单独的表格,并在每行中包含项目。

在这两种情况下,下面是一个使用用户定义的函数传入的字符串分割成表变量工作示例,然后使用JOINLIKE

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 + '%' 

你需要重新设计你的数据库启动因为这是一个非常糟糕的结构。你永远不要在一个字段中存储逗号分隔列表。首先考虑你需要的领域,然后设计一个合适的数据库。

+4

**从不**是绝对的,事实证明,总是有一个例外(由于实用主义的原因,如果不是纯粹的计算机科学)。虽然我同意其可能(尽管不确定)该模式可以并且应该改进,但它也可以回答给出的模式的问题。是的,我曾经有过存储分隔数据的情况,以避免不必要的复杂性,或者因为它是一个边缘案例,这就是它的工作方式。 – Murph 2009-12-10 14:47:23

+0

@ Murph-like非第一范式(NF²或N1NF) - http://en.wikipedia.org/wiki/Database_normalization#Non-first_normal_form_.28NF.C2.B2_or_N1NF.29。尽管如此,这通常是个坏主意。 – RichardOD 2009-12-10 14:49:15

+0

@Murph:这是其中一件事情,如果你不得不问,那就太贵了。换句话说,如果你还没有足够的知识来警惕设计,那么你根本不应该使用它。 – 2009-12-10 14:50:11

对于单个项目:

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

多个项目:

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

你需要分析输入和他们分裂和每个项目添加到查询:

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

这当然会有可怕的表现,但考虑到糟糕的设计是唯一的选择,除非海报可以设置全文索引(这取决于他使用的数据库)。 – HLGEM 2009-12-10 14:43:19

该表格的非常不好的结构(在一列中保存多个值)是您面临此问题的原因。你最好的选择是规范化表格。

但如果你不能,那么你可以使用“赞”操作符,使用通配符

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

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

您需要动态构造从这些SQL查询输入用户所做的。另一种方法是在服务器上编写代码,将逗号分隔的参数列表变成表变量或临时表,然后加入到它中。

+1

和tabletennis呢? – Peter 2009-12-10 14:43:31

+0

或我在国内 – 2009-12-10 14:55:11

为什么究竟是首先使用数据库?

我的意思是:你显然没有使用它的潜力。如果你喜欢使用逗号分隔的东西,请尝试一个文件。

列中的分隔值几乎总是坏表设计。 修复你的表格结构。

如果由于某种原因,你无法做到这一点,你可以期望的最好的是这样的:

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

这仍然是非常糟糕,有两个重要原因:

  1. 正确性。它会返回值只有包含这个词板球。用你的网球例子,如果你还有一个“网球鞋”项目呢?
  2. 表现。这不是可靠的,这意味着查询将不适用于您在该列上可能具有的任何索引。这意味着您的查询可能会是令人难以置信的缓慢

如果您需要帮助解决这个结构,解决的办法是增加另一个表—我们就叫它TableItems —为您的项目ID列,这将是一个外键到原来的表和字段item(单数)为您的每个项目值。然后,您可以将加入到该表中并准确地匹配列值。如果这些项目的工作方式与类别更相似,那么您希望在“Cricket”项目的行中匹配相同的板球项目,还需要第三个表格作为原始表格与另一个我刚刚拥有的项目之间的交集创建。

+0

的地方,因此我的'和乒乓球评论怎么样 – Peter 2009-12-10 14:46:31

MySQL,你的桌子上创建全文索引:

CREATE FULLTEXT INDEX fx_mytable_items ON mytable (items) 

,并发出此查询:

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