计算行中的值也在上一行中的行
Count rows where value in row is also in previous row
我想得到一个计数,其中一行中的值的内容也在前一行中。
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 行。
除了 "SELECT * FROM table WHERE"
之外,我什至不知道从哪里开始这个查询
这可以通过 window 函数完成(在 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
如果您没有递增的列,您可以使用 dense_rank()
:
生成一个
select
item,
sum(case when new_id = lag_new_id + 1 then 1 else 0 end) cnt_consecutive
from (
select
t.*,
lag(new_id) over(partition by item order by new_id) lag_new_id
from (
select
t.*,
dense_rank() over(order by id) new_id
from (
select id, item1 item from mytable
union all select id, item2 from mytable
union all select id, item3 from mytable
) t
) t
) t
group by item
order by item
在this DB Fiddle中,两个查询return:
item | cnt_consecutive
:---- | --------------:
Bird | 1
Cat | 2
Dog | 0
Horse | 3
Rat | 0
首先,使用 SKU 的所有可用唯一值创建 table:
CREATE TABLE results(
id VARCHAR(255) NOT NULL PRIMARY KEY
);
-- All fields should be listed here one-by-one.
INSERT IGNORE INTO results (select Item1 from example);
INSERT IGNORE INTO results (select Item2 from example);
INSERT IGNORE INTO results (select Item3 from example);
前一行可以通过左连接主 table 再次与自身获得,即 LEFT JOIN example AS previous ON previous.id + 1 = example.id
.
之后,我们必须检查示例 table 中当前行和上一行中是否存在每个唯一结果,最后得到:
SELECT
r.*,
SUM(
CASE WHEN r.id IN (
prv.Item1, prv.Item2, prv.Item3 -- All fields should be listed here.
) THEN 1 ELSE 0 END
) AS total
FROM
results AS r
LEFT JOIN
example AS cur ON r.id IN (
cur.Item1, cur.Item2, cur.Item3 -- All fields should be listed here.
)
LEFT JOIN
example AS prv ON prv.id + 1 = cur.id
GROUP BY
r.id
ORDER BY
cur.id
;
我看到@frost-nzcr4 的建议非常好,我正在做我自己的版本与昨天非常相似。但是,我正在做的方法有点不同,因为我没有专门创建一个 table 来存储唯一值。相反,我在做类似@GMB UNION
子查询,结果是这样的:
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;
Fiddle 这里:https://www.db-fiddle.com/f/bUUEsaeyPpAMfR2bK1VpBb/2
如您所见,这与 frost 的建议完全相似,只是稍作修改。在子查询 allitem
中,只要插入了新值,值就会更新,因此您不需要不断地将新的唯一数据插入到单独的 table 中。
此外,此查询通常会在上面的 MySQL v5.7 上出现 this is incompatible with sql_mode=only_full_group_by
错误,除非您删除 sql_mode。
我想得到一个计数,其中一行中的值的内容也在前一行中。
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 行。
除了 "SELECT * FROM table WHERE"
之外,我什至不知道从哪里开始这个查询这可以通过 window 函数完成(在 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
如果您没有递增的列,您可以使用 dense_rank()
:
select
item,
sum(case when new_id = lag_new_id + 1 then 1 else 0 end) cnt_consecutive
from (
select
t.*,
lag(new_id) over(partition by item order by new_id) lag_new_id
from (
select
t.*,
dense_rank() over(order by id) new_id
from (
select id, item1 item from mytable
union all select id, item2 from mytable
union all select id, item3 from mytable
) t
) t
) t
group by item
order by item
在this DB Fiddle中,两个查询return:
item | cnt_consecutive :---- | --------------: Bird | 1 Cat | 2 Dog | 0 Horse | 3 Rat | 0
首先,使用 SKU 的所有可用唯一值创建 table:
CREATE TABLE results(
id VARCHAR(255) NOT NULL PRIMARY KEY
);
-- All fields should be listed here one-by-one.
INSERT IGNORE INTO results (select Item1 from example);
INSERT IGNORE INTO results (select Item2 from example);
INSERT IGNORE INTO results (select Item3 from example);
前一行可以通过左连接主 table 再次与自身获得,即 LEFT JOIN example AS previous ON previous.id + 1 = example.id
.
之后,我们必须检查示例 table 中当前行和上一行中是否存在每个唯一结果,最后得到:
SELECT
r.*,
SUM(
CASE WHEN r.id IN (
prv.Item1, prv.Item2, prv.Item3 -- All fields should be listed here.
) THEN 1 ELSE 0 END
) AS total
FROM
results AS r
LEFT JOIN
example AS cur ON r.id IN (
cur.Item1, cur.Item2, cur.Item3 -- All fields should be listed here.
)
LEFT JOIN
example AS prv ON prv.id + 1 = cur.id
GROUP BY
r.id
ORDER BY
cur.id
;
我看到@frost-nzcr4 的建议非常好,我正在做我自己的版本与昨天非常相似。但是,我正在做的方法有点不同,因为我没有专门创建一个 table 来存储唯一值。相反,我在做类似@GMB UNION
子查询,结果是这样的:
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;
Fiddle 这里:https://www.db-fiddle.com/f/bUUEsaeyPpAMfR2bK1VpBb/2
如您所见,这与 frost 的建议完全相似,只是稍作修改。在子查询 allitem
中,只要插入了新值,值就会更新,因此您不需要不断地将新的唯一数据插入到单独的 table 中。
此外,此查询通常会在上面的 MySQL v5.7 上出现 this is incompatible with sql_mode=only_full_group_by
错误,除非您删除 sql_mode。