【问题标题】:How do I count rows so that consecutive occurence of data counts as 1?如何计算行数以使连续出现的数据计为 1?
【发布时间】:2020-03-03 10:40:07
【问题描述】:

该场景是我试图计算表中数据的出现次数,但我想将连续出现次数计为 1。这是一个示例。

输入:

|item    |statusid|
|--------|--------|
| pencil | A      |
| pencil | B      |
| pencil | C      |
| pencil | A      |-Counts
| pencil | A      |-as one
| pencil | B      |
| pencil | A      |
| eraser | D      |-Counts
| eraser | D      |-as one
| eraser | E      |
| eraser | F      |
| eraser | D      |
| eraser | E      |
| eraser | F      |

我将如何在 SQL Server 中使用存储过程来输出如下内容:

输出:

|item    |statusid|occurence|
|--------|--------|---------|
| pencil | A      |  3      |
| pencil | B      |  2      |
| pencil | C      |  1      |
| eraser | D      |  2      |
| eraser | E      |  2      |
| eraser | F      |  2      |

编辑:该表假定有一个日期时间列可用于对行进行排序。

【问题讨论】:

  • 问题是你需要一些东西来定义订单。您的示例中没有任何内容可以定义行的顺序。
  • 让我们从基础开始。这个样本集是否准确到您正在处理的内容,如果不是,您可以使其更准确。你都尝试了些什么。什么有效,什么无效。这些都是发布问题时有用的项目。

标签: sql sql-server database


【解决方案1】:

带有lag()窗口功能:

select [item], [statusid], count(*) occurence 
from (
  select *, 
    lag([item]) over (order by (select null)) previtem,
    lag([statusid]) over (order by (select null)) prevstatusid
  from tablename
) t
where [item] <> previtem or [statusid] <> prevstatusid or (previtem is null and prevstatusid is null)
group by [item], [statusid] 

请参阅demo
结果:

> item   | statusid | occurence
> :----- | :------- | --------:
> pencil | A        |         3
> pencil | B        |         2
> pencil | C        |         1
> eraser | D        |         2
> eraser | E        |         2
> eraser | F        |         2

注意:检查@SeanLange 的 cmets 之一中的链接。
此代码适用于您发布的示例数据以及相对较小的表,但不适用于非常大的表。
在任何情况下,您都需要一列来确定行的顺序。

【讨论】:

  • 这适用于小样本,因为默认顺序恰好与插入行的顺序相同。除非您有可以依靠的列进行排序,否则这不适用于真实的桌子。
  • 要求是关于插入的行。对于此要求,此代码确实有效。
  • 不,它没有。它偶然地适用于这个小数据集。 OP 没有任何东西可用作订单依据,因此您使用了 SELECT NULL。这只发生在这里,因为桌子非常小。但这依赖于按特定顺序返回的数据,如果没有要排序的列,您无法确保这一点。这与本文中解释的问题相同。 blogs.msdn.microsoft.com/conor_cunningham_msft/2008/08/27/…
  • @SeanLange 您发布的链接非常有趣且有用。另一个证据表明,对这种情况采取理所当然的解决方案会导致不可预测的结果。我将编辑以提及问题。
  • 如果 OP 听取有关使用列来订购此解决方案的建议,效果会很好。如果他们不......好吧......他们已经被警告了。
【解决方案2】:
with cte as
 (
   select item, statusid,
      -- tag consecutive rows with the same status
      case when lag(statusid) 
                over (partition by item
                      order by whatever) = statusid -- same status
           then 0 -- remove or
           else 1 -- keep in next step
      end as flag
   from mytable
 )
select item, statusid, count(*)
from cte
where flag = 1 -- now remove those rows
group by item, statusid

【讨论】:

  • 这只是理论上有点工作。但是您的 LAG 函数没有 ORDER BY 。而且 OP 没有任何东西可以用来定义行顺序。
  • @SeanLange:当然,我忘记了ORDER BY。如果你是正确的并且没有列可以排序,那么 OP 注定要失败:-)
  • 你好。我不包括您可以订购的列。无论如何,这帮助我解决了我的问题。非常感谢。
猜你喜欢
  • 2021-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-04
相关资源
最近更新 更多