Mysql Regex查询找到略有不同的重复项

时间:2015-06-17 16:29:14

标签: php mysql regex

我有一个表,它有一些列,如ID,名称等。还有一个包含JSON对象的列。由于一个错误,有些行被复制了。我一直在尝试编写一个查找所有重复项的查询。

JSON示例:

    {"flowId":"63","nodeId":2,"triggerLogId":"39397","modelId":"146",...}

我希望能够找到上述内容的副本,其中一切都是相同的,除了“triggerLogId”可以是两个不同的数字。

可能重复的JSON示例:

    {"flowId":"63","nodeId":2,"triggerLogId":"56217","modelId":"146",...}

如果两个行上的triggerLogId相同,我想出了一些查询来执行此操作,但我似乎无法找到可用于比较两列的任何正则表达式。

据我所知,MySQL没有正则表达式反向引用,所以我不能使用它们。这在纯MySQL中甚至可能吗? flowId和modelId可以是各种数字,因此列出一些不会起作用。

搜索了大部分Stack溢出问题以及大量谷歌搜索结果,希望有人能够知道我无法找到的内容。 :P

我最终还是要使用PHP吗?

编辑(表格结构):

id ----- int(11)自动增量
type-- varchar(20)
time-- bigint(20)NULL
data-- text

1 个答案:

答案 0 :(得分:2)

这不是一个答案。这有望帮助某人或您自己找到答案。

使用此查询,您可以将数据值“转换”为不同的列。

SELECT id,type,time,flowId,nodeId,triggerLogId,modelId FROM
(
SELECT *,
SUBSTR(data,LOCATE('flowId',data)+LENGTH('flowId')+2, LOCATE(',',data,LOCATE('flowId',data)+LENGTH('flowId')+3) - (LOCATE('flowId',data)+LENGTH('flowId')+2)) as flowId,
SUBSTR(data,LOCATE('nodeId',data)+LENGTH('nodeId')+2, LOCATE(',',data,LOCATE('nodeId',data)+LENGTH('nodeId')+3) - (LOCATE('nodeId',data)+LENGTH('nodeId')+2)) as nodeId,
SUBSTR(data,LOCATE('triggerLogId',data)+LENGTH('triggerLogId')+2, LOCATE(',',data,LOCATE('triggerLogId',data)+LENGTH('triggerLogId')+3) - (LOCATE('triggerLogId',data)+LENGTH('triggerLogId')+2)) as triggerLogId,
SUBSTR(data,LOCATE('modelId',data)+LENGTH('modelId')+2, LOCATE('}',data,LOCATE('modelId',data)+LENGTH('modelId')+3) - (LOCATE('modelId',data)+LENGTH('modelId')+2)) as modelId
FROM `my_table`
)
as foo

我会继续尝试找到问题的答案并更新我的答案。

<强>更新

这会解决您的问题吗?

SELECT CAST(GROUP_CONCAT(id) AS CHAR(1000)) as duplicated_rows
FROM `test`
GROUP BY CONCAT(SUBSTR(data,LOCATE('flowId',data)+LENGTH('flowId')+2, LOCATE(',',data,LOCATE('flowId',data)+LENGTH('flowId')+3) - (LOCATE('flowId',data)+LENGTH('flowId')+2)),
                                SUBSTR(data,LOCATE('nodeId',data)+LENGTH('nodeId')+2, LOCATE(',',data,LOCATE('nodeId',data)+LENGTH('nodeId')+3) - (LOCATE('nodeId',data)+LENGTH('nodeId')+2)),
                                SUBSTR(data,LOCATE('modelId',data)+LENGTH('modelId')+2, LOCATE('}',data,LOCATE('modelId',data)+LENGTH('modelId')+3) - (LOCATE('modelId',data)+LENGTH('modelId')+2)))
HAVING COUNT(*) > 1

DELETE DUPLICATES

我甚至不接近成为MySQL的专家,所以可能(最肯定)这甚至都不是最好的答案。要删除重复的行并保留最后一行(即只留下ID最高的行),我们需要两个步骤:

  1. 使用此查询获取我们要删除的ID列表:

    SELECT GROUP_CONCAT(delete_rows)为delete_ids FROM(SELECT SUBSTR(GROUP_CONCAT(id),1,(LENGTH(GROUP_CONCAT(id)) - LOCATE(',',REVERSE(GROUP_CONCAT(id)))))作为delete_rows                 从测试                 GROUP BY CONCAT(SUBSTR(数据,LOCATE('flowId',数据)+ LENGTH('flowId')+ 2,LOCATE(',',data,LOCATE('flowId',data)+ LENGTH('flowId')+ 3) - (LOCATE('flowId',data)+ LENGTH('flowId')+ 2)),SUBSTR(data,LOCATE('nodeId',data)+ LENGTH('nodeId')+ 2,LOCATE(', ',data,LOCATE('nodeId',data)+ LENGTH('nodeId')+ 3) - (LOCATE('nodeId',data)+ LENGTH('nodeId')+ 2)),SUBSTR(data,LOCATE( 'modelId',data)+ LENGTH('modelId')+ 2,LOCATE('}',data,LOCATE('modelId',data)+ LENGTH('modelId')+ 3) - (LOCATE('modelId',数据)+ LENGTH('modelId')+ 2)))                 有计数(*)&gt; 1)如foo GROUP BY'';

  2. 该查询将返回(1,5,7,8,10)之类的ID列表。在下一个查询中复制该列表:

    DELETE FROM test WHERE id IN <copy_list_here>

  3. 最终更新

    我找到了一种只使用一个查询即可完成此任务的方法。

    DELETE FROM test WHERE FIND_IN_SET(id,
    (SELECT GROUP_CONCAT(delete_rows) as delete_ids 
    FROM ( SELECT SUBSTR(GROUP_CONCAT(id),1,(LENGTH(GROUP_CONCAT(id)) - LOCATE(',',REVERSE(GROUP_CONCAT(id))))) as delete_rows 
                    FROM test 
                    GROUP BY CONCAT(SUBSTR(data,LOCATE('flowId',data)+LENGTH('flowId')+2, LOCATE(',',data,LOCATE('flowId',data)+LENGTH('flowId')+3) - (LOCATE('flowId',data)+LENGTH('flowId')+2)), SUBSTR(data,LOCATE('nodeId',data)+LENGTH('nodeId')+2, LOCATE(',',data,LOCATE('nodeId',data)+LENGTH('nodeId')+3) - (LOCATE('nodeId',data)+LENGTH('nodeId')+2)), SUBSTR(data,LOCATE('modelId',data)+LENGTH('modelId')+2, LOCATE('}',data,LOCATE('modelId',data)+LENGTH('modelId')+3) - (LOCATE('modelId',data)+LENGTH('modelId')+2)) ) 
                    HAVING COUNT(*) > 1) as foo 
    GROUP BY ''
    ));