简体   繁体   English

从多列中获取最小值和次最小值的最简单方法是什么(MIN 函数不起作用)?

[英]What is the simplest way to get the least value and second least value from multiple columns (MIN function does not work this)?

Below table is from Teradata database下表来自 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

The final result that I want is,我想要的最终结果是,

 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

So I did a little research online, most of them used MIN function with a subquery or raw over by partition.所以我在网上做了一些研究,他们中的大多数使用 MIN 函数和子查询或按分区原始。 Min function does not work for me, because I have three separate columns. Min 函数对我不起作用,因为我有三个单独的列。 I want to get minimum or least two values from the above three columns.我想从上述三列中获得最小或至少两个值。

I tried to do subquery or CTE using Least function, but I am stuck with getting the second least value.我尝试使用 Least 函数执行子查询或 CTE,但我坚持获得第二个最小值。 I am not sure how to use raw over partition for this.我不确定如何为此使用原始分区。

Any help regarding this will be highly appreciated.对此的任何帮助将不胜感激。

Thank you so much!!非常感谢!!

You can do it this way:你可以这样做:

this below:下面这个:

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

give you the minimum of all columns给你所有列中的最小值

and this:和这个:

(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))

gives you the minimum that is bigger than the minimum above给你比上面的最小值大的最小值

Below is the full query:以下是完整查询:

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

Output:输出:

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

Without set based analytic functions, your requirement is difficult.如果没有基于集合的分析函数,您的需求就很困难。 I might suggest unpivoting your data:我可能会建议取消数据透视:

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;

Note that the need to use such unpivoting operations might seriously imply that your table should be redesigned with the various measurements being stored per item across rows , rather than across columns.请注意,需要使用这种unpivoting操作可能会严重意味着你的表应与各种测量存储每个项目跨行,而不是跨列进行重新设计。

If you actually got three columns you can simply apply this brute-force logic:如果你真的有三列,你可以简单地应用这个蛮力逻辑:

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

For more than three columns you need Tim's approach, this is a slight variation (if your TD release supports UNPIVOT) avoiding the join-back:对于三个以上的列,您需要 Tim 的方法,这是一个轻微的变化(如果您的 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM