在匹配选择条件的行之前选择 n 行

Posted

技术标签:

【中文标题】在匹配选择条件的行之前选择 n 行【英文标题】:select n rows prior to row that match select condition 【发布时间】:2019-12-09 19:13:14 【问题描述】:

我有一个来自生产线的过程数据的大表,其中包含产品在 Hadoop 数据湖中创建过程中所经历的许多步骤。在某些时候,我很想知道在某个过程发生前 N 步发生了什么。

我可以编写一个选择查询,它返回与我可以识别的进程相对应的行,但是我如何(并且应该)在满足我的实际选择查询的行之前返回 N 行?

我想知道是否可以在 SQL/pyspark 中做这样的事情,我是否应该这样做,或者在选择包含我想要的信息的更大数据集后,是否应该在 python 中做这样的事情并使用 python 过滤掉我需要的位。

示例表结构:

|Col 1 | Col 2 | Col 3| Col 4  |
|A     | 1     | One  | Date 1 |
|C     | 1     | Two  | Date 2 |
|B     | 1     | One  | Date 1 |
|C     | 2     | Two  | Date 2 |
|C     | 1     | Three| Date 3 |
|D     | 2     | Four | Date 1 |
|E     | 1     | Five | Date 5 |

SELECT * FROM Table1
WHERE COL 1 = "C" and COL 3 = "Three"
ORDER BY COL 4, Col 2

会返回什么

|Col 1 | Col 2 | Col 3| Col 4  |
|C     | 1     | Three| Date 3 |

我想退货

|Col 1 | Col 2 | Col 3| Col 4  |
|C     | 1     | One  | Date 2 |
|C     | 2     | Two  | Date 2 |
|C     | 1     | Three| Date 3 |

高于 N=2,但 N 应该是可变的。如果可以在 SQL 中实现,我真的很感兴趣,这是否应该在 SQL 中完成,或者是否最好在代码中完成。我可以看到双方的争论,但需要一些外部意见。

编辑:两种建议的方法似乎都依赖于我之前提供的结构,其中 Col 2 是一个递增的值。这是误导,因为我使用 Col 2 和数字作为虚拟值。我现在已经用两列更新了表格,它们实际上显示了表格是如何正确排序的。首先是包含日期时间戳的列,其次是包含整数的列。

该表是 Hadoop 数据湖中的一个表,因此建议的解决方案应提供可以在该环境中执行的 SQL。

编辑 2:很明显,行本身可能不一定是连续的,所以我不想要最后 N 行,而是希望最后 N 行也满足某个谓词。在上面的示例中,谓词是 where Col2 = "C"。

【问题讨论】:

您的意思是 COL 3 = "Three" 我相信,因为您的 Col2 是数字。 你是 100% 正确的 嗨,关于 pyspark 解决方案 - 是的,它的性能肯定会更好,但它也需要更多的工作。你有什么准备吗?像火花上下文定义,或者至少连接到 SQL 数据库?如果是让您从头开始使用 pyspark,则不值得使用 SQL,除非作为学习练习。 pyspark 和连接一切都设置好了。这是一项富有成效的任务,再加上学习练习。 Apache spark 或 pyspark 上的 SQL 与 spark 上下文很好,处理提取的数据也很好,它更多地是关于如何以最佳方式提取数据以及我的努力最好花在这方面的教育上。 【参考方案1】:

您可以使用row_number() 函数如下:

Declare @n int = 3

SELECT *
FROM (
   select Col1,Col2,Col3,
          Row_Number() over (ORDER BY Col2 ASC) as RowOrder
   from table1
) x
where x.RowOrder <= @n

【讨论】:

如果我的数据通常必须按两列排序,而这里没有像 Col 2 这样的简化顺序,这仍然有效吗?像这样的事情应该在 SQL 中完成,还是用 python 之类的东西更好? 我会在 SQL 中进行,它会提供更好的性能并且更容易通过 SQL Profiler 进行调试。这种方法: Row_number() over (ORDER BY COL2,COL3 asc)) 也可能有效,或者您可能需要有两个不同的 roworder 列,然后也根据您的 roworder 列对主查询进行排序(使用 order by)。需要看到更确定的数据。 我必须在内部选择中添加一个 where 子句,因为表太大而无法选择所有它,当我这样做时,我只会返回完全符合条件的行我指定的初始选择,而不是前面的 N 行。这是因为我放了 where 子句吗? @Aesir 我认为你不应该在 where 子句中使用和 COL 3 = "Three"。 “我会在 SQL 中执行,它会提供更好的性能”这是非常大胆的声明。我敢说——如果你把你的 pyspark 代码写对了,这基本上是不真实的。【参考方案2】:

您可以使用运行计数:

SELECT *
FROM (SELECT t1.*,
             SUM(CASE WHEN COL1 = 'D' AND COL2 = 'Three THEN 1 ELSE 0 END)  OVER (ORDER BY col2 ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING) as cnt_special
      FROM Table1 t1
WHERE cnt_special > 0;

或者,您可以使用窗口函数来识别col2 值。如果您希望偏移量是逻辑的(即基于col2 中的)而不是物理的(即行数),则此方法有效:

SELECT *
FROM (SELECT t1.*,
             MAX(CASE WHEN COL1 = 'D' AND COL2 = 'Three THEN col2 END)  OVER (ORDER BY col2) as special_col2
      FROM Table1 t1
WHERE col2 <= special_col2 and col2 >= special_col2 - 2

【讨论】:

我试过这个,但不能让它工作。我的顺序涉及两列,我更新了我的问题以显示。对不起,如果这令人困惑。从语法上讲,rows_between 也出现错误:不匹配的输入 'rows_between' 期望 ')'、','、'RANGE'、'ROWS'(第 2 行,第 129 行)。这是因为我在 Hadoop 数据湖中的表上运行 SQL 查询吗? @Aesir 。 . . rows between 中没有下划线。那是一个错字。

以上是关于在匹配选择条件的行之前选择 n 行的主要内容,如果未能解决你的问题,请参考以下文章

hive - 如何为每个匹配选择前 N 个元素

总计匹配列表框选择

Notaped++标记选择符合条件的行书签

sed简单使用选择性显示

与字段的一个或多个条件匹配的查询行

如何在 Oracle SQL 中查找最具体的匹配行