根据计算转换 SQL Server 表

Posted

技术标签:

【中文标题】根据计算转换 SQL Server 表【英文标题】:Transform SQL Server table based on calculation 【发布时间】:2021-12-31 05:26:53 【问题描述】:

我有一张像下面这样的表格

Column1 Column2
A 200
A 200
A 0
B 300
B 200
C 100

我想把这张表变成下表

带计算:对于column1的每个元素,SUM(column2)/count of (non-zero column2)

Column1 Column2
A ((200+ 200 + 0) / 2) = 200
B ((300 + 200) / 2) = 250
C 100 / 1 = 100

我唯一能想到的就是循环遍历Column1 的不同元素并运行:

SELECT SUM(Column2) 
FROM Table 
WHERE Column1 = i / (SELECT COUNT(Column2) 
                     FROM Table 
                     WHERE Column1 = i AND Column2 <> 0)

并生成一个表格。

有更好的方法吗?

【问题讨论】:

【参考方案1】:

使用聚合:

SELECT Column1,
       SUM(Column2) / COUNT(CASE WHEN Column2 <> 0 THEN 1 END) AS Column2
FROM yourTable
GROUP BY Column1
HAVING COUNT(CASE WHEN Column2 <> 0 THEN 1 END) > 0;

【讨论】:

如果任何 column1 值的所有 olumn2 都是 0,那么它将失败并出现错误“遇到除以零错误。”。 我的回答是有效的,假设 OP 期望每个组总是至少有一个非零值。如果没有,OP 将不得不澄清预期的行为。 整洁。 COUNT(NULLIF(Column2, 0)) 更短一些,如果更模糊一些。 @KaziMohammadAliNur 是对的(在他自己的回答中),您也可以删除 WHERE 中的那些行,因为它不会影响最终结果。如:(x + 0) / 1x / 1 相同【参考方案2】:

您可以使用 where 子句删除 column2 中包含 0 的行,然后使用聚合来获得您想要的结果。但它会删除所有 column1 中所有 columnd2 中为 0 的那些 column1 值。

但是 Query2 将返回 column2 中值为零的行,而不是删除删除的行。

架构和插入语句:

 create table testTable (Column1    varchar(50), Column2 int);
 insert into testTable values('A',  200);
 insert into testTable values('A',  200);
 insert into testTable values('A',  0);
 insert into testTable values('B',  300);
 insert into testTable values('B',  200);
 insert into testTable values('C',  100);
 insert into testTable values('D',  0);

查询1:

 SELECT Column1,
        SUM(Column2) / COUNT(*) AS Column2
 FROM testTable where column2<>0
 GROUP BY Column1;

输出:

Column1 Column2
A 200
B 250
C 100

查询2:

 SELECT Column1,
        Coalesce(SUM(Column2) / nullif(COUNT(CASE WHEN Column2 <> 0 THEN 1 END),0),0) AS Column2
 FROM testTable
 GROUP BY Column1;

输出:

Column1 Column2
A 200
B 250
C 100
D 0

db小提琴here

【讨论】:

0 / 0 不是0,它被定义为Not A Number,您可以将其表示为NULL。所以我会删除最后的COALESCE 你是绝对正确的。我认为而不是 NULL OP 会更喜欢结果中的 0。【参考方案3】:

您可以使用派生表过滤掉 0 column2 行。然后,您可以应用 GROUP BY。

declare @table table (Column1 char(1),  Column2 int)
insert into @table values
('A',200),
('A',200),
('A',0  ),
('B',300),
('B',200),
('C',100);

SELECT Column1, (sum(column2) / count(column2) ) as column2
from
(
SELECT * FROM @TABLE where Column2 <> 0) as t
group by Column1
Column1 column2
A 200
B 250
C 100

【讨论】:

【参考方案4】:

在除以 column2 的总和时,检索 column1 的不同值并忽略 column2 的零值。并且还要考虑这里除以零错误。

-- SQL Server
SELECT t.column1
     , t.column2 / (CASE WHEN (t.total - t.total_zero) = 0 THEN 1 ELSE (t.total - t.total_zero) END)
FROM (SELECT column1
           , SUM(column2) column2
           , COUNT(CASE WHEN column2 = 0 THEN 1 END) total_zero
           , COUNT(1) total
      FROM test
      GROUP BY column1) t

请查看此网址https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=3853456941909ffffb8792415adc1f6f

【讨论】:

【参考方案5】:

使用AVG() 窗口函数,因为您想要Column2 的平均值。

如果您希望结果中包含Column1 的所有值,即使它们在Column2 中只有0s:

SELECT DISTINCT Column1,
       AVG(CASE WHEN Column2 <> 0 THEN Column2 END) OVER (PARTITION BY Column1) Column2
FROM tablename;

如果您想要 Column1 的值至少有 1 个 Column2 而不是 0 的结果:

SELECT DISTINCT Column1,
       AVG(Column2) OVER (PARTITION BY Column1) Column2
FROM tablename
WHERE Column2 <> 0;

请参阅demo。

请注意,SQL Server 会将整数的平均值截断为整数,因此如果您希望将结果作为浮点数,您应该将 Column2 乘以 1.0,例如:

AVG(CASE WHEN Column2 <> 0 THEN 1.0 * Column2 END) 

或:

AVG(1.0 * Column2)

【讨论】:

以上是关于根据计算转换 SQL Server 表的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL Server 中,您可以根据计算插入多条记录吗?

如何根据列值SQL Server扩展表[重复]

SQL Server:根据另一个表中条目的频率选择条目

SQL Server - 如何根据动态公式执行计算

SQL Server Update 根据自身表不同记录的值修改,链表修改

sql server2008根据经纬度计算两点之间的距离