Каков самый простой способ получить наименьшее значение и второе наименьшее значение из нескольких столбцов (функция MIN не работает)?

Ниже таблица из базы данных Teradata

SELECT
  sku.Item_id,
  sku.Item_length,
  sku.Item_width,
  sku.Item_heigth,
FROM  Category_item sku

Item_id | Item_length | Item_width |Item_heigth
-------------------------------------------
104174        8            6           1
9482763       8            8           8
8434610       8            9           1
2109145       54           34          2
567106        41           41          2
2028731       3            4           3

Конечный результат, который я хочу,

 Item_id | Item_length | Item_width |Item_heigth | MinValue | SecondMinVale
    ---------------------------------------------------------------------------
    104174        8            6           1          1            6
    9482763       8            8           8          8            8
    8434610       8            9           1          1            8
    2109145       54           34          2          2            34
    567106        41           41          2          2            41
    2028731       3            4           3          3            3

Поэтому я провел небольшое исследование в Интернете, в большинстве из них использовалась функция MIN с подзапросом или необработанная обработка по разделам. Функция min у меня не работает, потому что у меня три отдельных столбца. Я хочу получить минимум или минимум два значения из трех вышеуказанных столбцов.

Я пытался выполнить подзапрос или CTE, используя функцию Least, но застрял с получением второго наименьшего значения. Я не уверен, как использовать для этого необработанный раздел.

Любая помощь в этом будет высоко оценена.

Большое спасибо!!


person WeldaSudha    schedule 13.02.2020    source источник
comment
Ваше требование на самом деле довольно сложно изменить, но было бы намного проще справиться, если бы у вас были различные измерения в отдельных строках, а не в столбцах. В этом случае вы можете просто использовать ROW_NUMBER, чтобы ответить на свой вопрос.   -  person Tim Biegeleisen    schedule 13.02.2020
comment
@TimBiegeleisen Спасибо за объяснение, но я собираюсь использовать два приведенных выше значения в расчетах для автоматического отчета. Так что у меня нет большой гибкости здесь.   -  person WeldaSudha    schedule 13.02.2020
comment
Вы уверены, что все три значения всегда будут разными?   -  person Tim Biegeleisen    schedule 13.02.2020
comment
@TimBiegeleisen Нет. Это могут быть все одинаковые или два одинаковых. Так что не всегда будет по-разному точно.   -  person WeldaSudha    schedule 13.02.2020


Ответы (3)


Без аналитических функций, основанных на множествах, ваше требование сложно. Я мог бы предложить развернуть ваши данные:

WITH cte AS (
    SELECT Item_id, Item_length AS item FROM Category_item UNION ALL
    SELECT Item_id, Item_width FROM Category_item UNION ALL
    SELECT Item_id, Item_height FROM Category_item
),
cte2 AS (
    SELECT Item_id, item,
        ROW_NUMBER() OVER (PARTITION BY Item_id ORDER BY item) rn
    FROM cte
)

SELECT
    t1.Item_id,
    t1.Item_length,
    t1.Item_width,
    t1.Item_height,
    MAX(CASE WHEN rn = 1 THEN t2.item END) AS MinValue,
    MAX(CASE WHEN rn = 2 THEN t2.item END) AS SecondMinValue
FROM Category_item t1
INNER JOIN cte2 t2
    ON t1.Item_id = t2.Item_id
WHERE
    t2.rn <= 2
GROUP BY
    t1.Item_id,
    t1.Item_length,
    t1.Item_width,
    t1.Item_height;

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

person Tim Biegeleisen    schedule 13.02.2020
comment
Большое спасибо за быстрый ответ. Я думаю, что это выглядит многообещающе, и я собираюсь попробовать это и сообщить вам. К сожалению, я не разрабатываю эти таблицы, но я поговорю с ними. И последнее, это должно работать, когда все числа совпадают. Еще раз большое спасибо - person WeldaSudha; 13.02.2020
comment
@WeldaSucha Да, этот ответ устойчив как к двусторонней, так и к трехсторонней связи (и на самом деле возможные связи являются причиной, по которой я использую этот подход). - person Tim Biegeleisen; 13.02.2020
comment
небольшая проблема. Некоторые записывают, что он показывает одно и то же наименьшее число как для minvalue, так и для secondMinvlaue, даже если у них есть второе минимальное число. некоторые записи показывают мне совершенно другие цифры. Их нет даже в конкретных трех столбцах. Вы знаете, почему это так? - person WeldaSudha; 13.02.2020
comment
например, Item_id Item_length Item_width Item_heigth MinValue SecondMinValue ' result according to above colunm orders '5650678 4 16 16 4 4 в этом случае показывает одно и то же значение, должно быть 4 и 16. 4348907 8 29 56 8 8 это тоже самое. 9033813 13 10 17 3 3 У этого совсем другой результат. Вы знаете, что это такое? - person WeldaSudha; 13.02.2020
comment
В Teradata вы можете пропустить правильную фильтрацию результатов оконной функции, используя предложение QUALIFY. Как 2_ - person JNevill; 13.02.2020

Вы можете сделать это следующим образом:

это ниже:

SELECT MIN(Item_caract)
      FROM (VALUES (Item_length),(Item_width),(Item_heigth)) a(Item_caract)

дать вам минимум всех столбцов

и это:

(SELECT MIN(Item_caract)
      FROM (VALUES (Item_length),(Item_width),(Item_heigth)) a(Item_caract) where Item_caract >=
      (SELECT MIN(Item_caract)
      FROM (VALUES (Item_length),(Item_width),(Item_heigth)) a(Item_caract))

дает вам минимум, который больше, чем минимум выше

Ниже приведен полный запрос:

select * ,

(SELECT MIN(Item_caract)
      FROM (VALUES (Item_length),(Item_width),(Item_heigth)) a(Item_caract))
   AS MinValue ,

(SELECT MIN(Item_caract)
      FROM (VALUES (Item_length),(Item_width),(Item_heigth)) a(Item_caract) where Item_caract >=
      (SELECT MIN(Item_caract)
      FROM (VALUES (Item_length),(Item_width),(Item_heigth)) a(Item_caract))
      )
   AS SecondMinVale 
from cte

Выход:

104174  8   6   1   1   1
567106  41  41  2   2   2
2028731 3   4   3   3   3
2109145 54  34  2   2   2
8434610 8   9   1   1   1
9482763 8   8   8   8   8
person zip    schedule 13.02.2020
comment
Спасибо вам за быстрый ответ. Я уверен, как работает функция значений, так как я получаю все столбцы из таблицы. SELECT MIN(Item_caract) FROM Category_item (VALUES (Item_length),(Item_width),(Item_heigth)) a(Item_caract) г - person WeldaSudha; 13.02.2020
comment
Помимо проблемы, заключающейся в том, что Teradata не поддерживает ЗНАЧЕНИЯ, ваш результат просто возвращает наименьшее значение в обоих столбцах :-) - person dnoeth; 14.02.2020
comment
Спасибо dnoeth, удалю пост - person zip; 14.02.2020

Если у вас действительно есть три столбца, вы можете просто применить эту логику грубой силы:

SELECT sku.*,
   Least(Item_length,Item_width,Item_height) AS MinValue,
   CASE
     WHEN Item_length BETWEEN Least(Item_width, Item_height) AND 
                           Greatest(Item_width, Item_height) 
     THEN Item_length
     WHEN Item_width BETWEEN Least(Item_length, Item_height) AND 
                           Greatest(Item_length, Item_height) 
     THEN Item_width
     WHEN Item_height BETWEEN Least(Item_width, Item_length) AND 
                           Greatest(Item_width, Item_length)
     THEN Item_height
   END AS SecondMinValue
FROM  Category_item sku

Для более чем трех столбцов вам нужен подход Тима, это небольшая вариация (если ваш выпуск TD поддерживает UNPIVOT), позволяющая избежать обратного присоединения:

WITH cte AS 
 (
   SELECT up.*
     ,Row_Number() Over (PARTITION BY item_id ORDER BY val) AS rn
   FROM Category_item
   UNPIVOT
    ( val 
      FOR measure
      IN (Item_length AS 'l'
         ,Item_width  AS 'w'
         ,Item_height AS 'h') 
    ) AS up
 )  
SELECT
    Item_id,
    Max(CASE WHEN measure = 'l' THEN val END) AS item_length,
    Max(CASE WHEN measure = 'w' THEN val END) AS item_width,
    Max(CASE WHEN measure = 'h' THEN val END) AS item_height,
    Max(CASE WHEN rn = 1 THEN val END) AS MINVALUE,
    Max(CASE WHEN rn = 2 THEN val END) AS SecondMinValue
FROM cte
GROUP BY
    Item_id
person dnoeth    schedule 16.02.2020