将按类别过滤的最高绝对值插入另一个 table

Insert highest absolut value filtered by category into another table

我想 select 每个类别的 table 中的最高绝对值。

这是我的 table:

CREATE TABLE mytable
(
     CategoryID INTEGER NOT NULL PRIMARY KEY,  
     ExpValue   INTEGER NOT NULL
);

INSERT INTO mytable (CategoryID, ExpValue) VALUES (11, 0);
INSERT INTO mytable (CategoryID, ExpValue) VALUES (11, 11);
INSERT INTO mytable (CategoryID, ExpValue) VALUES (11, -59);
INSERT INTO mytable (CategoryID, ExpValue) VALUES (130, 0);
INSERT INTO mytable (CategoryID, ExpValue) VALUES (130, 59);
INSERT INTO mytable (CategoryID, ExpValue) VALUES (130, -2);

这就变成了这个

+------------+----------+
| CategoryID | ExpValue |
+------------+----------+
|         11 |        0 |
|         11 |      -13 |
|         11 |      -59 |
|        130 |        0 |
|        130 |       59 |
|        130 |        2 |
+------------+----------+

对于每个类别,我 select 最高值是这样的:

INSERT INTO #Result
    SELECT TOP 1 *
    FROM #SmallTable
    WHERE CategoryID = 11
    ORDER BY ExpValue DESC;

这个效果很好。但我知道发现了一个边缘案例。如您所见,对于 CategoryID = 11,它将 return 为 0 的行。

但我希望它改为选择值 -59。因此,任何数字中最高的 abs()

而对于 CategoryID = 130,它应该连续选择 59。

table只能有3种情况。

  1. 对于存在多个正值和一个 0 值的特定 CategoryID -> return 最高值

  2. 对于存在多个 0 值的特定 CategoryID -> 选择一个 0 值

  3. 对于存在多个负值和一个 0 值的特定 CategoryID -> 选择最小值。

如您所见,总是存在 0 的回退,但除了唯一的正值、负值或根本没有其他值。

table 实际上有更多的列 (30),但我只显示了查询所需的 2 列。但实际上我需要整行。

我的示例 table 的结果应该是:

+------------+----------+
| CategoryID | ExpValue |
+------------+----------+
|         11 |      -59 |
|        130 |       59 |
+------------+----------+

编辑:谢谢大家。我最终是这样做的:

INSERT INTO #Result
    SELECT TOP 1 *
    FROM #SmallTable
    WHERE CategoryID = 11
    ORDER BY ABS(ExpValue) DESC;

您可以对 amx abs(

使用子查询
select  m.CategoryID, m.ExpValue
from #SmallTable m
INNER JOIN  (
    Select CategoryID , max(abs(ExpValue )) max_abs
    FROM #SmallTable
    GROUP BY CategoryID

    ) t on t.max_abs = abs(ExpValue )
        and t.CategoryID = m.CategoryID

.

INSERT INTO #Result
select  m.CategoryID, m.ExpValue
from #SmallTable m
INNER JOIN  (
    Select CategoryID , max(abs(ExpValue )) max_abs
    FROM #SmallTable
    GROUP BY CategoryID

    ) t on t.max_abs = abs(ExpValue )
        and t.CategoryID = m.CategoryID

您可以使用单个聚合和一些条件逻辑:

select categoryid,
       (case when abs(min(expval)) > abs(max(expval)) then min(expval)
             else max(expval)
        end)
from #smalltable
group by categoryid;

如果您只想要一个类别,您可以在 group by.

之前进行过滤

另一种选择。在 ORDER BY 子句中使用 ROW_NUMBER 窗口函数,以及 TOP (1) WITH TIES:

SELECT TOP (1) WITH TIES
  CategoryID,
  ExpValue
FROM
  mytable
ORDER BY ROW_NUMBER() OVER (PARTITION BY CategoryID ORDER BY ABS(ExpValue) DESC);

结果:

+------------+----------+
| CategoryID | ExpValue |
+------------+----------+
|         11 |      -59 |
|        130 |       59 |
+------------+----------+

通过将行号放入 select 列表中可以更容易地了解它是如何工作的:

  CategoryID,
  ExpValue,
  ROW_NUMBER() OVER (PARTITION BY CategoryID ORDER BY ABS(ExpValue) DESC) as RowNum
FROM
  mytable;

结果:

+------------+----------+--------+
| CategoryID | ExpValue | RowNum |
+------------+----------+--------+
|         11 |      -59 |      1 |
|         11 |       11 |      2 |
|         11 |        0 |      3 |
|        130 |       59 |      1 |
|        130 |       -2 |      2 |
|        130 |        0 |      3 |
+------------+----------+--------+

TOP (1) WITH TIES 只取每个分组中的第 1 行。

这里是 Rextester Demo