根据计算转换 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) / 1
与 x / 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
中只有0
s:
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 中,您可以根据计算插入多条记录吗?