Mysql 对行中的值也位于前一行的行进行计数

Mysql 对行中的值也位于前一行的行进行计数,mysql,sql,select,count,gaps-and-islands,Mysql,Sql,Select,Count,Gaps And Islands,我想得到一个计数,其中一行中的值的内容也在前一行中 Row | Item1 | Item2 | Item 3 | 1 | Dog | Cat | Rat 2 | Bird | Cat | Horse 3 | Horse | Dog | Rat 4 | Bird | Cat | Horse 5 | Horse | Bird | Cat 第2行将增加Cat的计数,因为Cat位于第1行和第2行 第3行会增加马的数量,因

我想得到一个计数,其中一行中的值的内容也在前一行中

   Row | Item1 | Item2 | Item 3 |
   1   | Dog   | Cat   | Rat
   2   | Bird  | Cat   | Horse
   3   | Horse | Dog   | Rat
   4   | Bird  | Cat   | Horse
   5   | Horse | Bird  | Cat
第2行将增加Cat的计数,因为Cat位于第1行和第2行

第3行会增加马的数量,因为马也在第2行

第4行会增加马的数量,因为马也在第3行

第5行将增加马和猫的数量,因为它们都出现在第4行

最多可以有100个项目或SKU,我可以在任何或所有字段上编制索引。在任何给定的时间都可能有1000到2000行


除了从表中选择*FROM,我甚至不知道从何处开始这个查询,而这可以通过MySQL 8.0中可用的窗口函数来完成

一个选项是取消打印结果集,然后使用lag检查以前的记录。假设ID始终增加1,则可以执行以下操作:

select
    item,
    sum(case when id = lag_id + 1 then 1 else 0 end) cnt_consecutive
from (
    select
        t.*,
        lag(id) over(partition by item order by id) lag_id
    from (
        select id, item1 item from mytable
        union all select id, item2 from mytable
        union all select id, item3 from mytable
    ) t
) t
group by item
order by item
如果没有递增列,则可以生成一个具有稠密_秩的列:

在中,两个查询都返回:

item | cnt_consecutive :---- | --------------: Bird | 1 Cat | 2 Dog | 0 Horse | 3 Rat | 0
首先,使用SKU的所有可用唯一值创建表:

创建表格结果 id VARCHAR255非空主键 ; -所有字段应在此处逐一列出。 将忽略插入结果中,从示例中选择Item1; 将忽略插入到结果中,从示例中选择Item2; 将忽略插入到结果中,从示例中选择Item3; 左联接主表可以通过自身再次获得上一行,即左联接示例与Previous.id+1=example.id上的上一行相同

之后,我们必须检查示例表中当前行和前一行中是否存在每个唯一的结果,最后得到以下结果:

选择 r、 *, 总和 当r.id在 prv.Item1、prv.Item2、prv.Item3-此处应列出所有字段。 然后1或0结束 总计 从…起 结果为r 左连接 示例为中r.id上的cur cur.Item1、cur.Item2、cur.Item3-此处应列出所有字段。 左连接 示例为prv.id+1=cur.id上的prv 分组 r、 身份证 订购人 当前id ;
参见工作示例

我看到@frost-nzcr4建议非常好,我自己的版本与昨天的版本非常相似。但是,我所采用的方法有点不同,因为我没有专门创建一个表来存储唯一的值。相反,我做了类似的@GMB UNION sub查询,结果是这样的:

SELECT B.row, A.allitem,
       SUM(CASE WHEN A.allitem IN (C.Item1, C.Item2, C.Item3) THEN 1 
           ELSE 0 END) AS total
FROM

-- this sub-query will be dynamic and UNION will eliminate any duplicate
    (SELECT item1 AS allitem FROM mytable UNION
     SELECT item2 FROM mytable UNION
     SELECT item3 FROM mytable) AS A

LEFT JOIN mytable AS B ON A.allitem IN (B.Item1, B.Item2, B.Item3)
LEFT JOIN mytable AS C ON C.row + 1 = B.row
GROUP BY  A.allitem
ORDER BY  B.row;
在这里拉小提琴:

正如您所看到的,这与弗罗斯特的建议非常相似,只是做了一些小的修改。在子查询中,只要插入了新值,allitem值就会被更新,因此您不需要一直将新的唯一数据插入到单独的表中


此外,除非您删除sql模式,否则此查询通常会得到与上面MySQL v5.7上的sql模式=仅完整组错误不兼容的结果

像Item1、Item2等列的设计很差。你应该有另一个表,每项1行。你运行的是哪个版本的MySQL?用这种设计做你想做的是可能的,但会非常详细,你需要100个条件。是的。认真考虑修改你的模式,如ITEM1,ITEM2等列是很差的设计,但有时你必须与你所给予的工作。GMB MySQL版本5.6.41-84.1我非常喜欢一些新功能,但是这个系统仍然运行5.6.41-84.1,因此我接受了另一个答案,因为它运行在这个旧服务器上。
SELECT B.row, A.allitem,
       SUM(CASE WHEN A.allitem IN (C.Item1, C.Item2, C.Item3) THEN 1 
           ELSE 0 END) AS total
FROM

-- this sub-query will be dynamic and UNION will eliminate any duplicate
    (SELECT item1 AS allitem FROM mytable UNION
     SELECT item2 FROM mytable UNION
     SELECT item3 FROM mytable) AS A

LEFT JOIN mytable AS B ON A.allitem IN (B.Item1, B.Item2, B.Item3)
LEFT JOIN mytable AS C ON C.row + 1 = B.row
GROUP BY  A.allitem
ORDER BY  B.row;