【问题标题】:Query to select rows with minimum distinct value of a column查询以选择具有最小不同列值的行
【发布时间】:2020-06-18 23:41:37
【问题描述】:

我需要为 A 列的每一行选择具有 B 列最小值的行,但它应该与迄今为止为 A 列选择的其他值不同。所以 A 的顺序很重要。此外,如果 B 已用完且没有剩余,则 A 的后面值应为 NULL 或不出现在结果中。

A 和 B 都是数字(或时间戳)。 示例:

A   | B | 
----+---+
1   | 3 | 
1   | 5 | 
1   | 6 | 
2   | 3 | 
2   | 5 | 
9   | 3 |
9   | 5 | 

所以想要的结果是:

A   | B | 
----+---+
1   | 3 | 
2   | 5 | 

select A, min(B) group by A 显然不起作用,因为我不希望 B 被重复。 Distinct 也不起作用,因为行已经不同。我在任何地方都找不到类似的问题。 我正在使用的实际数据是 redshift 上的时间序列数据库,因此 A 和 B 是时间戳。特别欢迎 CTE。

【问题讨论】:

  • 那么1, 6也是不同的。
  • @zealous 是,但 6 不是分配给 1 的最小值。
  • @zealous 我的错。我刚刚更正了我的问题。
  • a == 2 的最小值应该是三个吗?
  • 用您正在使用的数据库标记您的问题。

标签: sql amazon-redshift


【解决方案1】:

首先我认为这可以通过ROW_NUMBER () OVER (ORDER PARTITION BY B DESC) 解决,但是有一个问题,B 中的数字不应该重复。

目前唯一想到的就是制作临时表,我知道这不是最好的方法,但您可能可以改进它

DECLARE @Tabla1 TABLE(A INT) 
DECLARE @Tabla2 TABLE(B INT)
DECLARE @Tabla3 TABLE(A INT, B INT)
INSERT INTO @Tabla1 SELECT DISTINCT A FROM PRUEBA

WHILE (SELECT COUNT(*) FROM @Tabla1) > 0
BEGIN
  DECLARE @A INT, @B INT;
  SET @A = (SELECT TOP 1  * FROM @Tabla1);
  SET @B = (SELECT MIN(B) FROM PRUEBA WHERE A = @A AND B NOT IN(SELECT * FROM @Tabla2));
  INSERT INTO @Tabla2 VALUES (@B)
  DELETE FROM @Tabla1 WHERE A = @A
  INSERT INTO @Tabla3 SELECT A, B FROM PRUEBA WHERE A = @A AND B = @B
END

SELECT * FROM @Tabla3

也许你可以使用游标,但你需要计算花费更多的计算开销,游标或临时表

【讨论】:

    【解决方案2】:

    这基本上是一个“寻找对角线”的问题。您需要知道 A 在 A 中的 B 等级以及 A 在 all 中的等级。我相信这适用于给定的数据:

    select A, B from (
      select row_number() over (partition by A order by B) as RN,
        dense_rank() over (order by A) as DR.
        A, B
        from <table> )
    where RN = DR; 
    

    对于更复杂的情况,这个解决方案会变得更复杂。

    附录: 因为我知道它会被问到而且这是一个有趣的问题,所以我想出了这样一个更复杂的解决方案会是什么样子:

    select min(A) as A, B from (
      select decode(A <> nvl(min(A) over (order by DRB, DRA rows between unbounded preceding and 1 preceding),-1), true, 'good', 'no good') as Y,
        A, B from (
        select dense_rank() over (partition by B order by A) as DRA,
          dense_rank() over ( order by B) as DRB,
          A, B from <table>
      )
      where DRA <= DRB
    )
    where Y = 'good'
    group by B
    order by A, B;
    

    【讨论】:

    • 谢谢@Bill Weiner。它看起来很有希望,但我不确定我是否理解它。任何澄清都会有所帮助。
    • 我从 B 的排名和每个 B 的 As 排名开始。现在我们知道,对于排名最低的 B,我们希望 B 值的排名最低的 A - 这导致了A 的等级(在 B 值内)必须等于或小于 B 等级的条款。在同一个选择中,我按这些排名对行进行排序,并在 A 值上设置窗口,以查找当前 A 是否与前行的最小 A 匹配 - 此 A、B 组合之前已使用过。这将为每个 A 设置一个最低未使用 B 的标志。最后,我抓取“好”标记的行并按 B 分组以找到匹配的最小 A。
    猜你喜欢
    • 2013-02-23
    • 2016-01-21
    • 2023-03-30
    • 1970-01-01
    • 2015-07-30
    • 2021-11-10
    • 2012-07-14
    • 2013-08-15
    • 1970-01-01
    相关资源
    最近更新 更多