【问题标题】:How to sum records in partition for only part of records如何仅对部分记录求和分区中的记录
【发布时间】:2022-12-03 08:35:41
【问题描述】:

我正在为 SQL Server 中的窗口函数而苦苦挣扎。我有一个表,用于跟踪传输了多少记录。我写了一个查询来计算每个参数传输了多少行。然而,在某些时候必须重新发送记录(它们从最终位置被丢弃并重新发送)。所以,如果我继续我的旧查询,我会得到重复的值。

这是一个示例表:

parameter rows min_id max_id create_date status
A1 48 350 521 06.11.2022 sent
A1 48 350 521 06.11.2022 error
A1 78 1 350 05.11.2022 sent
A1 13 299 350 04.11.2022 sent
A1 50 100 299 03.11.2022 sent
A1 15 1 100 01.11.2022 sent
B2 87 800 1202 07.11.2022 sent
B2 187 1 800 06.11.2022 sent
B2 12 570 800 04.11.2022 sent
B2 120 320 570 03.11.2022 sent
B2 55 1 320 01.11.2022 sent

当 min_id 再次为 1 时,您可以了解何时重新发送表。

我想要达到的结果是:

parameter sum min_id max_id max_date
A1 126 1 521 06.11.2022
B2 274 1 1202 07.11.2022

到目前为止我能做什么(但导致重复结果):

SELECT * FROM
   (SELECT 
      parameter
      , sum(rows) over (partition by parameter) as sum
      , min_id
      , max_id
      , MAX(create_date) over (partition by parameter) as max_date
   FROM my_table) as s
WHERE create_date = max_date and status = 'sent'

我认为可能还需要添加一个窗口函数(嵌套窗口函数?),这将使从 min_id=1 开始的特定范围的分区具有最新的 create_date。但是,我没有这样做。谁能建议如何处理这个问题?

【问题讨论】:

  • 作为快速提示,您可以使用递归来执行此操作,或者使用条件窗口函数生成一个对每个“组”都相同的列,然后汇总

标签: sql sql-server window-functions


【解决方案1】:

您可以尝试使用 GROUP BY 子句而不是使用分区,因为您期望的输出可能在所有列中都有聚合。您可以尝试以下查询:

SELECT
   parameter, 
   SUM(rows) AS rows, 
   MIN(min_id) AS min_id,
   MAX(max_id) AS max_id,
   MAX(create_date) AS max_date 
FROM my_table
WHERE status = 'sent'
GROUP BY parameter

这将为您提供预期的输出。但是,如果您仍然想使用旧查询并且重复项是唯一的问题,您可以尝试在 SELECT 之后使用 DISTINCT 关键字来为您提供唯一记录。

【讨论】:

  • OP 需要解决比您的解决方案涵盖的问题更复杂的问题。
  • 哦,是的,我看到总和不正确。以参数 B2 为例,您能否告诉我哪些记录需要求和才能得到值 274,这样我可以更清楚。
  • 可以看到 min_id = 1 出现了两次,最近一次是在 6.11 所以这意味着该日期之前的记录被丢弃并开始重新发送。因此,如果您只添加从该日期开始的行,您将收到 274。感谢您的调查!
【解决方案2】:

通过一个小的调整,您可以获取如下结果:

SELECT parameter, sum(rows) as sum, min(min_id) as min_id, max(max_id) as max_id,
  max(create_date) as max_date
FROM
   (SELECT 
      parameter
      , rows
      , min_id
      , max_id
      , create_date
      , status
      , MAX(case when min_id = 1 then create_date end) over (partition by parameter) as sent_start
   FROM my_table) as s
WHERE create_date >= sent_start and status = 'sent'
GROUP BY parameter

值得考虑数据的变化。可以使用大于 1 的 min_id 重新发送记录吗?记录可以在同一天内发送和重新发送吗?

如果其中任何一个是可能的,您可能希望使用 EXISTS 条件进行测试:

选项 2

;WITH SentRows as
(
SELECT *
FROM my_table
WHERE status='sent'
)

SELECT parameter, sum(rows) as sum, min(min_id) as min_id, max(max_id) as max_id,
  max(create_date) as max_date 
FROM SentRows as s
WHERE NOT EXISTS
  (SELECT 1 FROM SentRows t WHERE t.parameter = s.parameter AND t.create_date > s.create_date 
    AND t.min_id <= s.min_id AND t.max_id >= s.max_id)
GROUP BY parameter

对于部分重叠的记录,您可能希望涉及窗口函数,但这里不是必需的。

【讨论】:

    猜你喜欢
    • 2021-04-24
    • 1970-01-01
    • 2011-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-19
    • 1970-01-01
    相关资源
    最近更新 更多