Выбор max () из нескольких столбцов - PullRequest
12 голосов
/ 14 декабря 2011

Хорошо, вот моя таблица:

product_id  version_id  update_id  patch_id
  1           1           0          0
  1           1           1          0
  1           1           1          1
  1           1           2          0
  1           1           2          1
  2           1           0          0
  2           2           0          0
  2           3           0          0
  2           3           0          1
  3           1           0          0
  3           1           0          1

Теперь я хочу выбрать самую последнюю версию продукта, поэтому версия с наибольшим значением update_id & patch_id.

Например,последняя версия

  • продукт 1 должен возвращать 1, 2, 1
  • продукт 2 должен возвращать 3, 0, 1
  • продукт 3 должен возвращать 1, 0,1

Я пробовал все виды вещей с GROUP BY и HAVING, пробовал подзапросы, но я все еще не могу найти способ сделать это.

Может ли кто-нибудь помочь мне найти правильный запрос, или я должен подумать о написании php-функции для этого?

Редактировать

Некоторые дополнительныеинформация: - Столбцы вместе являются первичным ключом (есть больше столбцов, но для этой проблемы они не имеют значения) - Ни один из столбцов не является автоинкрементным

Это таблица:

CREATE  TABLE IF NOT EXISTS `db`.`patch` (
`product_id` INT NOT NULL ,
`version_id` INT NOT NULL ,
`update_id` INT NOT NULL ,
`patch_id` INT NOT NULL
PRIMARY KEY (`product_id`, `version_id`, `update_id`, `patch_id`) ,
INDEX `fk_patch_update1` (`product_id` ASC, `version_id` ASC, `update_id` ASC) )

Редактировать 2

Помечено как дубликат, это не так: Другой вопрос ищет записи выше, чем значение для любого из трех различных столбцов.

В этом вопросе мы ищем наибольший номер версии, сгруппированный по product_id.

Edit 3

Ответ rgz снова говорит мне, что этодублировать.Прежде всего: этот вопрос старше.Во-вторых, я не думаю, что ответ тот же.

rgz предлагает использовать следующий запрос:

SELECT product_id, GREATEST(version_id, update_id, patch_id) AS latest_version FROM patch.

GREATEST (1,2,3) возвращает 3, верно?Ват, если у нас есть эти значения:

  product_id  version_id  update_id  patch_id
  1           1           0          0
  1           1           2          8
  1           3           0          0

Как я понимаю, этот запрос вернет:

  product_id  latest_version
  1                 1
  1                 8
  1                 3

Но он должен вернуть:

  product_id  version_id update_id  patch_id
  1           3          0          0

НадеюсьЯ думаю, что величайший может помочь.Если вы думаете, что это произойдет, пожалуйста, докажите, что я не прав.

Ответы [ 7 ]

9 голосов
/ 14 декабря 2011

Это один из примеров полезного использования уникальных идентификаторов.

Представьте, что у вас есть поле идентификатора автоинкремента, затем вы можете найти нужный идентификатор для каждого продукта, используя коррелированный подзапрос ...

SELECT
  *
FROM
  yourTable
WHERE
  id = (
        SELECT   id
        FROM     yourTable AS lookup
        WHERE    lookup.product_id = yourTable.product_id
        ORDER BY version_id DESC, update_id DESC, patch_id DESC
        LIMIT    1
       )

Эквивалентный без уникальный идентификатор требует нескольких коррелированных подзапросов ...

SELECT
  *
FROM
  yourTable
WHERE
     version_id = (
                   SELECT   MAX(version_id)
                   FROM     yourTable AS lookup
                   WHERE    lookup.product_id = yourTable.product_id
                  )
  AND update_id = (
                   SELECT   MAX(update_id)
                   FROM     yourTable AS lookup
                   WHERE    lookup.product_id = yourTable.product_id
                     AND    lookup.version_id = yourTable.version_id
                  )
  AND patch_id  = (
                   SELECT   MAX(patch_id)
                   FROM     yourTable AS lookup
                   WHERE    lookup.product_id = yourTable.product_id
                     AND    lookup.version_id = yourTable.version_id
                     AND    lookup.update_id  = yourTable.update_id
                  )

Это будет значительно медленнее, чем в таблице со столбцом уникального идентификатора.

Другой альтернативой (без уникального идентификатора) является самостоятельное объединение на разных уровнях агрегации.

SELECT
  yourTable.*
FROM
  (SELECT product_id, MAX(version_id) AS max_version_id FROM yourTable GROUP BY product_id) AS version
INNER JOIN
  (SELECT product_id, version_id, MAX(update_id) AS max_update_id FROM yourTable GROUP BY product_id, version_id) AS update
    ON  update.product_id = version.product_id
    AND update.version_id = version.max_version_id
INNER JOIN
  (SELECT product_id, version_id, updatE_id, MAX(patch_id) AS max_patch_id FROM yourTable GROUP BY product_id, version_id) AS patch
    ON  patch.product_id = update.product_id
    AND patch.version_id = update.version_id
    AND patch.update_id  = update.max_update_id
INNER JOIN
  yourTable
    ON  yourTable.product_id = patch.product_id
    AND yourTable.version_id = patch.version_id
    AND yourTable.update_id  = patch.update_id
    AND yourTable.patch_id   = patch.max_patch_id
3 голосов
/ 14 декабря 2011

Попробуйте:

Select product_id, version_id, update_id, patch_id
from (select * from MyTable 
      order by product_id, version_id desc, update_id desc, patch_id desc) as v
group by product_id

Извините, это @RolandoMySQLDBA.Простите за вторжение, но я отправляю ваш запрос и его вывод по образцу данных:

mysql> Select product_id, version_id, update_id, patch_id
    -> from (select * from prod
    ->       order by product_id, version_id desc, update_id desc, patch_id desc) as v
    -> group by product_id  ;
+------------+------------+-----------+----------+
| product_id | version_id | update_id | patch_id |
+------------+------------+-----------+----------+
|          1 |          1 |         2 |        1 |
|          2 |          3 |         0 |        1 |
|          3 |          1 |         0 |        1 |
+------------+------------+-----------+----------+
3 rows in set (0.00 sec)

Ваш запрос работает, как показано.Это также проще, чем мой ответ.Хорошее шоу !!!

1 голос
/ 14 декабря 2011

Я не проверял это, но я уверен, что вы можете сделать что-то вроде этого

SELECT val.product_id, MAX(val.myVersion)
FROM (SELECT product_id, ((version_id * 10 + update_id) * 10 + patch_id) as myVersion
      FROM myTable) as val
GROUP by product_id;

Извините, это @RolandoMySQLDBA. Простите за вторжение, но я отправляю ваш запрос и его вывод в пример данных:

mysql> SELECT val.product_id, MAX(val.myVersion)
    -> FROM (SELECT product_id, ((version_id * 10 + update_id) * 10 + patch_id) as myVersion
    ->       FROM prod) as val
    -> GROUP by product_id;
+------------+--------------------+
| product_id | MAX(val.myVersion) |
+------------+--------------------+
|          1 |                121 |
|          2 |                301 |
|          3 |                101 |
+------------+--------------------+
3 rows in set (0.01 sec)

Хотя отображение отличается, ваш запрос логически работает для исходного вопроса. +1 от меня !!!

0 голосов
/ 15 ноября 2016

MySQL имеет функцию GREATEST, поэтому вы должны использовать ее следующим образом:

SELECT product_id, GREATEST(version_id, update_id, patch_id) AS latest_version FROM patch.

Я пометил этот вопрос как дубликат, поскольку оба вопроса в основном задают одну и ту же вещь, выбирая максимальное значение из несколькихколонны.Здесь вы используете его в предложении SELECT, в другом вопросе вы используете его в предложении WHERE.В любом случае GREATEST делает свое дело.

0 голосов
/ 14 декабря 2011

Используя ваши входные данные из вопроса и таблицу без ключей, вот довольно больной подход, который работает:

Прежде всего, вам нужен следующий запрос:

select A.* from prod A LEFT JOIN
(select product_id,max(tagnum) maxtag from
(select *,(version_id*10000+update_id*100+patch_id) tagnum from prod) AA
group by product_id) B
USING (product_id)
WHERE (version_id*10000+update_id*100+patch_id) = B.maxtag;

Вот пример кода с использованием всех целых чисел, без индексов и данных примера:

DROP TABLE IF EXISTS prod;
CREATE TABLE prod
(
product_id INT,
version_id INT,
update_id INT,
patch_id INT
) ENGINE=MyISAM;
INSERT INTO prod VALUES
( 1,  1,  0, 0 ),
( 1,  1,  1, 0 ),
( 1,  1,  1, 1 ),
( 1,  1,  2, 0 ),
( 1,  1,  2, 1 ),
( 2,  1,  0, 0 ),
( 2,  2,  0, 0 ),
( 2,  3,  0, 0 ),
( 2,  3,  0, 1 ),
( 3,  1,  0, 0 ),
( 3,  1,  0, 1 );
select * from prod;
select *,(version_id*10000+update_id*100+patch_id) tagnum from prod;
select A.* from prod A LEFT JOIN
(select product_id,max(tagnum) maxtag from
(select *,(version_id*10000+update_id*100+patch_id) tagnum from prod) AA
group by product_id) B
USING (product_id)
WHERE (version_id*10000+update_id*100+patch_id) = B.maxtag;

Вот результат:

mysql> DROP TABLE IF EXISTS prod;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE prod
    -> (
    -> product_id INT,
    -> version_id INT,
    -> update_id INT,
    -> patch_id INT
    -> ) ENGINE=MyISAM;
Query OK, 0 rows affected (0.04 sec)

mysql> INSERT INTO prod VALUES
    -> ( 1,  1,  0, 0 ),
    -> ( 1,  1,  1, 0 ),
    -> ( 1,  1,  1, 1 ),
    -> ( 1,  1,  2, 0 ),
    -> ( 1,  1,  2, 1 ),
    -> ( 2,  1,  0, 0 ),
    -> ( 2,  2,  0, 0 ),
    -> ( 2,  3,  0, 0 ),
    -> ( 2,  3,  0, 1 ),
    -> ( 3,  1,  0, 0 ),
    -> ( 3,  1,  0, 1 );
Query OK, 11 rows affected (0.00 sec)
Records: 11  Duplicates: 0  Warnings: 0

mysql> select * from prod;
+------------+------------+-----------+----------+
| product_id | version_id | update_id | patch_id |
+------------+------------+-----------+----------+
|          1 |          1 |         0 |        0 |
|          1 |          1 |         1 |        0 |
|          1 |          1 |         1 |        1 |
|          1 |          1 |         2 |        0 |
|          1 |          1 |         2 |        1 |
|          2 |          1 |         0 |        0 |
|          2 |          2 |         0 |        0 |
|          2 |          3 |         0 |        0 |
|          2 |          3 |         0 |        1 |
|          3 |          1 |         0 |        0 |
|          3 |          1 |         0 |        1 |
+------------+------------+-----------+----------+
11 rows in set (0.00 sec)

mysql> select *,(version_id*10000+update_id*100+patch_id) tagnum from prod;
+------------+------------+-----------+----------+--------+
| product_id | version_id | update_id | patch_id | tagnum |
+------------+------------+-----------+----------+--------+
|          1 |          1 |         0 |        0 |  10000 |
|          1 |          1 |         1 |        0 |  10100 |
|          1 |          1 |         1 |        1 |  10101 |
|          1 |          1 |         2 |        0 |  10200 |
|          1 |          1 |         2 |        1 |  10201 |
|          2 |          1 |         0 |        0 |  10000 |
|          2 |          2 |         0 |        0 |  20000 |
|          2 |          3 |         0 |        0 |  30000 |
|          2 |          3 |         0 |        1 |  30001 |
|          3 |          1 |         0 |        0 |  10000 |
|          3 |          1 |         0 |        1 |  10001 |
+------------+------------+-----------+----------+--------+
11 rows in set (0.01 sec)

mysql> select A.* from prod A LEFT JOIN
    -> (select product_id,max(tagnum) maxtag from
    -> (select *,(version_id*10000+update_id*100+patch_id) tagnum from prod) AA
    -> group by product_id) B
    -> USING (product_id)
    -> WHERE (version_id*10000+update_id*100+patch_id) = B.maxtag;
+------------+------------+-----------+----------+
| product_id | version_id | update_id | patch_id |
+------------+------------+-----------+----------+
|          1 |          1 |         2 |        1 |
|          2 |          3 |         0 |        1 |
|          3 |          1 |         0 |        1 |
+------------+------------+-----------+----------+
3 rows in set (0.00 sec)

mysql>

Попробуйте!

CAVEAT

Мой ответ будет поддерживаться для каждого продукта

  • до 99 версий
  • до 99 обновлений
  • до99 патчей
0 голосов
/ 14 декабря 2011

Попробуй это.

SELECT
  version_id,
  max_update.update_id,
  max_patch.patch_id
FROM
  TABLE
    OUTER APPLY
    (
      SELECT TOP 1
        update_id
      FROM
        TABLE t1
      WHERE
        TABLE.version_id = t1.version_id
        AND TABLE.product_id = t1.product_id
      ORDER BY update_id DESC
    ) max_update
    OUTER APPLY
    (
      SELECT TOP 1
        patch_id 
      FROM
        TABLE t1
      WHERE
        TABLE.version_id = t1.version_id
        AND TABLE.product_id = t1.product_id
        AND max_update.update_id = t1.update_id
      ORDER BY patch_id DESC
    ) max_patch
0 голосов
/ 14 декабря 2011

Вы можете группировать по max(update_id * maxpatchidvalue + patch_id), чтобы получить то, что вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...