【问题标题】:How to filter the result of an INNER JOIN with a MAX function如何使用 MAX 函数过滤 INNER JOIN 的结果
【发布时间】:2011-10-25 20:01:46
【问题描述】:

我需要在这个查询的结果中添加一个带有 MAX 函数的过滤器;

SELECT a.INTEGER_0, a.INTEGER_1, a.DATE_0, a.DATE_1, a.INTEGER_2
FROM TABLE_A a           
INNER JOIN               
   (SELECT b.INTEGER_0, b.INTEGER_1, b.DATE_0, max(b.DATE_1) AS max_date
    FROM TABLE_A b     
    GROUP BY b.INTEGER_0, b.INTEGER_1, b.DATE_0
   ) AS result         
ON  a.INTEGER_0 = b.INTEGER_0
AND a.INTEGER_1 = b.INTEGER_1
AND a.DATE_0 = b.DATE_0  
AND a.DATE_1 = b.max_date

没关系!!但我需要过滤结果max(INTEGER_2)
我尝试了另一个 INNER JOIN,但结果很糟糕!

其他信息
行:

1,7,'2011-02-01','2011-01-01',8
1,7,'2011-02-01','2011-01-02',7
1,7,'2011-02-01','2011-01-04',6
1,7,'2011-02-01','2011-01-04',3
1,7,'2011-02-01','2011-01-04',3

正确结果:

1,7,'2011-02-01','2011-01-04',6

【问题讨论】:

  • 定义一个“坏”的结果?能否给出样本数据和预期输出?
  • 很多很多行:P 我需要使用 max(b.INTEGER_2) 从结果中过滤,因为如果我将 max(b.INTEGER_2) 添加为 max_int_2 并添加到 ON -> AND a.INTEGER_2 = b .max_int_2 我用 b.max_date 丢失了一些行,因为 INTEGER_2 列在某些情况下包含错误数据...谢谢回答!

标签: sql postgresql inner-join


【解决方案1】:

首先,您的查询中有一个语法错误:子查询的别名是AS result。您将其与 b 的内部别名混淆了。

1 行

如果您只想要 一个 行与 max(integer_2),那么 ORDER BY / LIMIT 将完成这项工作。您的查询可能如下所示:

SELECT a.integer_0, a.integer_1, a.date_0, a.date_1, a.integer_2
FROM   table_a a           
JOIN   (
    SELECT b.integer_0, b.integer_1, b.date_0, max(b.date_1) as max_date
    FROM   table_a b     
    GROUP  BY b.integer_0, b.integer_1, b.date_0
    ) AS b ON a.integer_0 = b.integer_0
        AND a.integer_1 = b.integer_1
        AND a.date_0 = b.date_0  
        AND a.date_1 = b.max_date
ORDER  BY a.integer_2 DESC
LIMIT  1;

所有行

如果您希望结果集中的 所有 行带有 max(integer_2)(正如您的查询所暗示的那样),那么您可以这样做:

SELECT a.integer_0, a.integer_1, a.date_0, a.date_1, a.integer_2
FROM   table_a a           
JOIN   (
    SELECT b.integer_0, b.integer_1, b.date_0, max(b.date_1) as max_date
    FROM   table_a b     
    GROUP  BY b.integer_0, b.integer_1, b.date_0
    ) AS b ON a.integer_0 = b.integer_0
        AND a.integer_1 = b.integer_1
        AND a.date_0 = b.date_0  
        AND a.date_1 = b.max_date
WHERE (a.date_1, a.integer_2) = (
        SELECT date_1, integer_2
        FROM   table_a
        ORDER  BY 1 DESC, 2 DESC
        LIMIT  1);

或者更好的是,大大简化为:

SELECT integer_0, integer_1, date_0, date_1, integer_2
FROM   table_a a           
WHERE     (integer_0, integer_1, date_0, date_1, integer_2) = ( 
    SELECT integer_0, integer_1, date_0, date_1, integer_2
    FROM   table_a b
    ORDER  BY 4 DESC, 5 DESC
    LIMIT  1);
-- ORDER  BY something?  -- add these lines ..
-- LIMIT  1;            -- .. if you want just one row 

或者再简化一些

SELECT *
FROM   table_a a           
WHERE  (a) = ( 
    SELECT b
    FROM   table_a b
    ORDER  BY date_1 DESC, integer_2 DESC
    LIMIT  1);
-- ORDER  BY something?  -- add these lines ..
-- LIMIT  1;            -- .. if you want just one row 

如果性能很重要,请确保在 table_a (date_1, integer_2) 上有一个索引

【讨论】:

  • 谢谢你的回答,我需要这个:列:A(INT),B(INT),C(DATE),D(DATE),E(INT),我需要:所有行等于 A,B,C 其中 MAX(D) 如果不止一行具有相同的 A,B,C,D 我需要使用 MAX(E) 进行过滤,但需要所有具有相同 A、B、C、D、E 的 reg .. . 最大的问题是 E 有时不是正确的 seq 因为我不包括在第一个过滤器中。
【解决方案2】:
SELECT a.INTEGER_0, a.INTEGER_1, a.DATE_0, a.DATE_1, MAX(a.INTEGER_2) AS MaxInt2
FROM TABLE_A a           
INNER JOIN               
   (SELECT b.INTEGER_0, b.INTEGER_1, b.DATE_0, max(b.DATE_1) AS max_date
    FROM TABLE_A b     
    GROUP BY b.INTEGER_0, b.INTEGER_1, b.DATE_0
   ) AS result         
ON  a.INTEGER_0 = b.INTEGER_0
AND a.INTEGER_1 = b.INTEGER_1
AND a.DATE_0 = b.DATE_0  
AND a.DATE_1 = b.max_date
GROUP BY a.INTEGER_0, a.INTEGER_1, a.DATE_0, a.DATE_1
HAVING MAX(a.INTEGER_2) = 42 /* Adjust this according to what your filter needs */

【讨论】:

  • 感谢您的回答,但我需要在相同 INTEGER_0、INTEGER_1、DATE_0、DATE_1 的行中使用最大 INTEGER_2 过滤结果
【解决方案3】:

您尚未指定您使用的 PostgreSQL 版本。如果是 8.4+,您可以尝试不同的方法并使用 ranking function 来实现您的目标:

WITH ranked AS (
  SELECT
    INTEGER_0,
    INTEGER_1,
    DATE_0,
    DATE_1,
    INTEGER_2,
    RANK() OVER (
      PARTITION BY
        INTEGER_0,
        INTEGER_1,
        DATE_0
      ORDER BY
        DATE_1 DESC
    ) AS rnk
  FROM TABLE_A
)
SELECT
  INTEGER_0,
  INTEGER_1,
  DATE_0,
  DATE_1,
  INTEGER_2
FROM TABLE_A
WHERE rnk = 1
ORDER BY INTEGER_2 DESC
LIMIT 1

【讨论】:

    【解决方案4】:
    SET search_path='tmp';
    -- generate some data
    DROP TABLE atable CASCADE;
    CREATE TABLE atable
        ( integer_0 INTEGER
        , integer_1 INTEGER
        , date_0 DATE
        , date_1 DATE
        , integer_2 INTEGER
        );  
    INSERT INTO atable( integer_0,integer_1,date_0,date_1,integer_2)
    VALUES
    (1,7,'2011-02-01','2011-01-01',8)
    ,(1,7,'2011-02-01','2011-01-02',7)
    ,(1,7,'2011-02-01','2011-01-04',6)
    ,(1,7,'2011-02-01','2011-01-04',3)
    ,(1,7,'2011-02-01','2011-01-04',3)
        ;
    
    -- Query the data
    SELECT integer_0,integer_1,date_0,date_1,integer_2
    FROM atable a0
    WHERE NOT EXISTS (SELECT *
        FROM atable a1
        WHERE a1.integer_0 = a0.integer_0
        AND a1.integer_1 = a0.integer_1
        AND a1.date_0 = a0.date_0
        AND a1.date_1 > a0.date_1
        )   
    AND NOT EXISTS (SELECT *
        FROM atable a2
        WHERE a2.integer_0 = a0.integer_0
        AND a2.integer_1 = a0.integer_1
        AND a2.date_0 = a0.date_0
        AND a2.date_1 = a0.date_1
        AND a2.integer_2 > a0.integer_2
        )   
        ;   
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-05
      • 2020-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-17
      相关资源
      最近更新 更多