Mysql 从单个表获取标记信息的sql查询

Mysql 从单个表获取标记信息的sql查询,mysql,sql,Mysql,Sql,我有一个Mysql表,其中有不同的代码片段,在一个冒号中有标签 table snippets --------------- Id title source tag 1 "title" "srouce code" "Zend, Smarty" 2 "title2" "srouce code2" "Zend jquery" 3 "title3" "srouce code3" "doctrine" 我想做一个select语句,这样我就可以在我的站点上构建一个标记云 Zend(2), s

我有一个Mysql表,其中有不同的代码片段,在一个冒号中有标签

table snippets
---------------
Id title source tag
1 "title"  "srouce code"  "Zend, Smarty"
2 "title2"  "srouce code2"  "Zend jquery"
3 "title3"  "srouce code3"  "doctrine"
我想做一个select语句,这样我就可以在我的站点上构建一个标记云

Zend(2), smarty(1), jquery(1), doctrine(1)
记住标记并不总是用空格表示,有些标记用逗号分隔

然后我需要一个查询来获取具有特定标记的所有记录。我想我可以使用类似的东西,直到有更好的解决方案

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

寻找优化的解决方案,请

首先,您必须将所有字符(如“,”空格等)替换为固定分隔符(如)。你可以用一张临时桌子


然后,您必须创建一个函数,该函数在字段上循环并搜索和统计单个标记。

您是否考虑过将源代码和标记分离到单独的表中

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)-@delimiterIndex)
            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
这将触发触发器并填充新表,并在不影响现有代码的情况下使一切变得更容易。当然,您需要将所有已知的测力仪更换为一个测力仪,以使其正常工作。 任何添加或修改的新记录都将自动触发。

创建三个表

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

当标记为否定时,是否有任何评论。。。。问题出了什么问题?有sql解决方案吗?我知道在一张桌子上储存不是最好的方式。但这正是先驱者所做的。所以我必须处理这个问题。这可能是规范化表的最好方法。但是我不想改变表的结构,因为它可能会使其他模块不稳定。这是唯一的办法吗?或者我可以处理一些sql查询。这是很好的规范化。sql中是否有一种方法可以使用现有的表结构,因为每件事都做得很糟糕。我不想花太多时间来改变整个结构。是否有任何sql查询可以使用现有结构执行此工作。谢谢你的帮助。我真的很感激。如果性能不重要,您可以使用正则表达式:从标记中选择*,其中name REGEXP^ |[,]+zend$|[,]+只获取zend标记,而zendalicous之类的标记是不匹配的!但是布拉布拉,赞德,或者布拉布拉,赞德,布拉布拉会匹配的。