Как отфильтровать результат INNER JOIN с помощью функции MAX - PullRequest
1 голос
/ 26 октября 2011

Мне нужно добавить фильтр с функцией 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

Ответы [ 4 ]

1 голос
/ 26 октября 2011

Прежде всего, у вас есть синтаксическая ошибка в вашем запросе : псевдоним подзапроса равен 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) , если производительность имеет значение.

0 голосов
/ 06 января 2012
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
    )   
    ;   
0 голосов
/ 27 октября 2011

Вы не указали, какую версию PostgreSQL вы используете.Если это 8,4+, вы можете попробовать другой подход и использовать функцию ранжирования для достижения своей цели:

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
0 голосов
/ 26 октября 2011
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 */
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...