【问题标题】:sql - Teradata select records per group based on conditionsql - Teradata 根据条件选择每组记录
【发布时间】:2019-11-27 14:22:08
【问题描述】:

输入:

| cust_no | month_nr | resource| segment |
|---------|----------|---------|---------|
|       1 | jan-18   | r3      | s1      |
|       1 | feb-18   | r4      | s1      |
|       1 | mar-18   | r2      | s1      |
|       1 | apr-18   | r3      | s1      |
|       1 | jun-18   | r7      | s1      |
|       2 | may-18   | r4      | s2      |
|       2 | jun-18   | r2      | s2      |
|       2 | aug-18   | r3      | s3      |
|       2 | sep-18   | r2      | s4      |
|       2 | oct-18   | r4      | s4      |
|       2 | nov-18   | r1      | s4      |
|       3 | sep-18   | r7      | s2      |
|       3 | oct-18   | r9      | s1      |
|       3 | nov-18   | r2      | s3      |

期望输出:

| cust_no | month_nr | resource| segment |
|---------|----------|---------|---------|
|       1 | jan-18   | r3      | s1      |
|       2 | may-18   | r4      | s2      |
|       2 | jun-18   | r2      | s2      |
|       2 | aug-18   | r3      | s3      |
|       2 | sep-18   | r2      | s4      |
|       3 | sep-18   | r7      | s2      |
|       3 | oct-18   | r9      | s1      |
|       3 | nov-18   | r2      | s3      |

我想过滤掉出现特定列值(段)的客户记录持续保持不变超过 2 次,并在输出中保留第一次出现的行。
根据以上样本数据:

  • 客户 1 有 5 个连续 s1 段:保留客户 1 的第一行输出;
  • 客户 2 有 3 个继续 s4 段:保留第 1 个 s4 段行;并保持s2段(连续2次)和s3段(1次)输出不变
  • 客户 3 记录在输出中保持不变,因为没有段值保持不变超过 2 次。

有什么建议吗?

【问题讨论】:

  • 您的 month_nr 列真的是一个日期,已在您显示的输出中转换为字符串吗?如果将其存储为字符串,则查找最早日期会变得更加棘手。您必须将其转换回可以运行 min 或 max 函数的东西。您需要在 where 子句中使用子查询。从 删除 where month_nr != ( select min(x.month_nr) from
    as X where X.segment =
    .segment group by x.segment)。但是 min() 不适用于月份字符串。当然
    是你的表名。
  • 星号是您试图在 SO 中使代码加粗的吗? (只是好奇)
  • 这张表的主键列是什么?
  • 是的@CaiusJard。只是想强调理解
  • 为什么 cust_no 2 segement s2 返回了两行?

标签: sql duplicates teradata


【解决方案1】:

我有理由确定 teradata 支持窗口函数。此查询应生成一个仅包含您要删除的行的行集,即对于每个客户,仅前两行与当前行具有相同段的行。您可以将其更改为“删除主键列不在的位置”的删除查询:

SELECT cust_no, month_nr, resource, segment
FROM 
  (
    SELECT 
      *, 
      LAG(segment, 1) OVER(PARTITION BY cust_no ORDER BY cast(month_nr as DATE FORMAT 'mmm-yy') as prevsegment,
      LAG(segment, 2) OVER(PARTITION BY cust_no ORDER BY cast(month_nr as DATE FORMAT 'mmm-yy') as prevprevsegment,
      LEAD(segment, 1) OVER(PARTITION BY cust_no ORDER BY cast(month_nr as DATE FORMAT 'mmm-yy') as nextsegment
    FROM table
  ) a
WHERE
  (segment = prevsegment AND segment = prevprevsegment) OR
  (segment = prevsegment AND segment = nextsegment)

查询查看当前段并将其与上一个和上一个上一个段进行比较(我称之为“前两个”规则)。它还将当前与前一个和下一个进行比较(我称之为“任何一方”规则)

对于一系列段,例如:1,2,2,3,3,3,4,4,4,4

逻辑如下:

1 - don't touch
2 - don't touch
2 - don't touch
3 - don't touch
3 - remove because of Either Side rule
3 - remove because of Previous Two rule
4 - don't touch
4 - either side
4 - either side
4 - previous two

等等

因此,上面的这个查询返回了你需要删除的行,作为一个练习,你将如何 donthatbillnleave 因为我不知道你的主键是什么

我唯一不确定的是,如果您尝试将无日日期字符串转换为日期,teradata 会做什么。您可能必须将“01-”连接到您的 month_nr 并调整日期格式。不要将日期存储为字符串!即使您只需要月份,也应该将其存储为每天 01 的 DATE

【讨论】:

  • 感谢@Caiusjard。为什么需要对月份进行排序?如果重复段值发生 >2 次,则保留第一行 ..
  • 您的查询是否过滤掉每个客户的所有重复段记录?我只想过滤掉重复的片段连续发生> 2次
  • @Jassen 好吧,您需要定义什么是“第一行”,这就是 OVER() 中的 ORDER BY 的用途; LAG 和 LEAD 函数必须对行进行排序,所以你必须选择一些东西来对行进行排序,这样数据库才能确定什么是“第一”
  • 好的,自从阅读了您的问题更改/反馈并更好地了解您的目标后,我进行了编辑
猜你喜欢
  • 2018-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-20
  • 2021-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多