2011-03-07 43 views
1

标签信息我有一个表(MySQL的)与标签不同片段在coloumnsSQL查询来从单个表

table snippets 
--------------- 
Id title source tag 
1 "title" "srouce code" "Zend, Smarty" 
2 "title2" "srouce code2" "Zend jquery" 
3 "title3" "srouce code3" "doctrine" 

我想要做一个选择语句,这样我就可以建立一个标签云我的网站。

Zend(2), smarty(1), jquery(1), doctrine(1) 

记住每日新闻并不总是受到空间sperated,一些产品关键词之间用逗号(,)隔开

然后我需要一个查询具体产品关键词获取的所有记录。我认为我可以使用类似的东西,直到有更好的解决方案。

Select * from snippets where tag like "%ZEND%" 

请寻求优化的解决方案。

+0

当标记为负时做任何一条评论....这个问题有什么问题吗? – Developer 2011-03-07 11:35:26

回答

1

创建三张表!

table snippets 
id | title | source_code 
1 "title" "srouce code" 
2 "title2" "srouce code2" 
3 "title3" "srouce code3" 

table tags 
id | tag 
1 "zend" 
2 "smarty" 
3 "doctrine" 
4 "jquery" 

table snippets_tags 
id | snippet_id | tag_id 
1  1   1 
2  1   2 
3  2   1 
4  2   4 
5  3   3 

提示:小写的标签,因为“Zend公司”和“Zend的”相同

现在你的标签云查询应该像

SELECT tags.name, COUNT(snippets_tags.id) AS snippet_count 
    FROM tags LEFT JOIN snippets_tags ON snippets_tags.tag_id = tags.id 
     GROUP BY tags.id 

给你一个结果像

name | snippet_count 
zend   2 
smarty  1 
doctrine  1 
jquery  1 

要选择属于某个标记的所有代码段:

SELECT snippets.* FROM snippets, tags, snippets_tags 
    WHERE 
    snippets_tags.snippets_id = snippet.id AND 
    snippets_tags.tag_id = tags.id AND 
    tags.name LIKE '%zend%' 
+0

,这是很正常化。有没有办法在SQL中,我可以与现有的表结构,因为每一件事情已经做得很糟糕。不想花太多时间来改变整个结构。是否有任何SQL查询可以完成现有结构的工作。感谢您的帮助雪橇。我真的很有趣。 – Developer 2011-03-07 12:14:02

+0

如果性能无关紧要,您可以使用正则表达式: 'SELECT * FROM tags WHERE name REGEXP“(^ | [,] +)zend($ | [,] +)”'只让您获得“zend”标签像“zendalicous”不匹配!但是“blabla,zend,something”或者“blabla zend,blabla”会匹配。 [详细了解模式匹配](http://dev.mysql.com/doc/refman/5.0/en/pattern-matching.html) – sled 2011-03-07 12:24:49

0

首先,您必须用'#'等固定的“分隔符”字符替换'''空格等所有字符。你可以使用临时表。

然后,您必须创建一个循环遍历字段并搜索和计数单个标签的函数。

+0

是否有任何的SQL解决方案?我知道这不是存储在单个表格中的最佳方式。但这正是预定员所做的。所以我必须解决这个问题。 – Developer 2011-03-07 11:41:48

1

你有没有想过将源代码和标签分离到不同的表中?

Source Table 
ID, Title, Source 
1 "t1" "sc" 
2 "t2" "sc" 
3 "t3" "sc" 

Tag Table 
ID, Tag 
1 "Zend" 
2 "Smarty" 
3 "jquery" 
4 "doctrine" 

SourceTagLink Table 
SourceID, TagID 
1   1 
1   2 
2   1 
2   3 
3   4 

你有,你可以选择,或添加标签唯一列表的方式。 你不会做任何字符串解析,所以你的选择会更快。与您在本网站上为您的帖子分配标签的方式类似。

编辑
这是我用一个多值的字符串转换成表格与它写一个列的函数MSSQL,但你应该能够将其转换到MySQL

CREATE FUNCTION [dbo].[ParseString](@String NVARCHAR(4000), @Delimiter CHAR(1)=',') 
      RETURNS @Result TABLE(tokens NVARCHAR(4000)) 
    AS 
    BEGIN 
     -- We will be seearching for the index of each occurrence of the given 
     -- delimiter in the string provided, and will be extracting the characters 
     -- between them as tokens. 
     DECLARE @delimiterIndex INT 
     DECLARE @token NVARCHAR(4000) 

     -- Try to find the first delimiter, and continue until no more can be found. 
     SET @delimiterIndex = CHARINDEX(@Delimiter, @String) 
     WHILE (@delimiterIndex > 0) 
     BEGIN 
      -- We have found a delimiter, so extract the text to the left of it 
      -- as a token, and insert it into the resulting table. 
      SET @token = LEFT(@String, @delimiterIndex-1) 
      INSERT INTO @Result(tokens) VALUES (LTRIM(RTRIM(@token))) 

      -- Chop the extracted token and this delimiter from our search string, 
      -- and look for the next delimiter. 
      SET @String = RIGHT(@String, LEN(@String)[email protected]) 
      SET @delimiterIndex = CHARINDEX(@Delimiter, @String) 
     END 
     -- We have no more delimiters, so place the remainder of the string 
     -- into the result as our last token. 
     SET @token = @String 
     INSERT INTO @Result(tokens) VALUES (LTRIM(RTRIM(@token))) 
     RETURN 
    END 

基本上你怎么称呼它像

ParseString('this be a test', ' ') 
it will return a single column table 

this  
be 
a 
test 

ParseString('this:be a test', ':') 
returns 

this 
be a test 

你可以在更新触发器添加一个调用该函数来填充新表,以帮助您做出选择更加容易。一旦触发建成,只是做类似下面

Update yourTable 
Set Title = Title 

,填补火扳机和填充新表,让你的一切更容易在不影响现有代码的简单更新。当然,你需要用一个单一的替换所有已知的定界符来使其工作。
添加或修改的任何新记录都会自动激发触发器。

+0

这可能是标准化表格的最佳方法。但我不想改变表格的结构,因为它可能会使其他模块不稳定。这是唯一的方法吗?或者我可以解决一些SQL查询。 – Developer 2011-03-07 11:48:57

+0

请参阅编辑回答 – 2011-03-07 12:13:43