使用 SQL Select 语句计算空值

Posted

技术标签:

【中文标题】使用 SQL Select 语句计算空值【英文标题】:Null Calculation With SQL Select Statement 【发布时间】:2011-01-22 12:51:03 【问题描述】:

我有以下表格

Input           Output
---------------------------------
12.22           
                2.22

如果我通过以下 Sql 语句:

Select Input,Output,Balance=sum(Input - Output) from Stock group by input,output

所以输出是:

Input            Output       Balance
--------------------------------------
12.22            NULL         NULL
NULL             2.22         NULL

如果我想要下面的输出:

Input            Output       Balance
--------------------------------------
12.22                         12.22
                 2.22         10.00

比什么是 SQL Transact 语句?

我的表结构如下:

companyID   int
transID     int    -- Primary Key (Auto Increment)
Date        datetime
particulars varchar
input       decimal
output      decimal

注意:- 我在 input 和 Output 列上应用了 Group By 函数,这没有区别,因为 transID 列是自动递增的,因此应该是显示表格的所有行。

【问题讨论】:

看起来您想要运行总计计算?如果是这样,您按什么顺序订购? (NULL 位很简单 - 只需使用 COALESCE 【参考方案1】:
Select Input,
       Output,
       @runbal:=@runbal+SUM(COALESCE(Input, 0) - COALESCE(Output, 0)) AS Balance
from (select @runbal:=0) rt,Stock 
group by Input,Output

【讨论】:

Input,Output 上的分组不太可能是正确的,他可能希望保留交易日期排序。如果您省略 sum 和 group by,我会对此表示赞成。 @Martin,这里需要 @runbal 变量,但是如果我们创建 bal1 额外的列来存储其余的计算,而不是在除以输入和输出之后。有可能吗? @Andomar - 我同意这个查询似乎没有实际应用,但 OP 需要澄清这个@mahesh 你能扩展你的问题来告诉我们你的实际表架构并添加更多的示例数据吗和期望的结果?这会给你想要的结果,但它们似乎没有多大意义,现在你似乎无论如何都在改变它们! @Martin,我已经测试了你的代码,但它只是要求“@runbal”变量,即使你声明了它。 @mahesh - 您能否根据标签确认您实际上在mysql 上?不是 Microsoft SQL Server,因为我看到您提到 Transact SQL?【参考方案2】:

我认为这可能对你有用。首先,这是我定义测试表和测试数据的方式:

declare @stock table (
  transId int not null identity(1,1), 
  [date] date not null, -- use datetime if not using SQL Server 2008
  input decimal(7,2) null, 
  [output] decimal(7,2) null
);

insert into @stock values
('1/23/2011', 12.22, null),
('1/23/2011', null, 2.22),
('1/24/2011', 16, null),
('1/24/2011', 3.76, null),
('1/24/2011', null, 5.50);

这是我用来产生您在问题中指定的结果的选择。该查询为给定日期的事务 ID 顺序中的所有事务生成总计。如果要计算多天的总数,请注释掉 AND b.[date] = a.[date] 行。

select 
  [date],
  input = isnull(input,0), 
  [output] = isnull([output],0),
  balance = (isnull(input,0)-isnull([output],0)) +
        isnull((
          select 
            sum((isnull(input,0)-isnull([output],0)))
          from @stock b
          where b.transId < a.transId
          and b.[date] = a.[date] -- comment this for totals over multiple dates
        ),0)
from @stock a
order by transId;

这个查询给出:

date        input   output  balance
2011-01-23  12.22   0.00    12.22
2011-01-23   0.00   2.22    10.00
2011-01-24  16.00   0.00    16.00
2011-01-24   3.76   0.00    19.76
2011-01-24   0.00   5.50    14.26

作为脚注,由于每笔交易的运行总值始终相同,我建议在您的表中添加一个余额列,并在插入交易行时计算余额列的值。这样,您只需查看最后一笔交易的余额即可确定插入交易的余额应该是多少。

【讨论】:

【参考方案3】:

任何涉及 null 的“正常”操作都会产生 null。

阅读COALESCE;使用COALESCE(foo, 0)如果不为null则返回foo,如果foo为null则返回0这一事实。

【讨论】:

【参考方案4】:

这是我想与 arcain 的解决方案附近的社区分享的 Sql-2000 服务器解决方案:

这里我使用 Coalesce 函数而不是 ISNULL

select
transID,
input,
output,
runningtotal =  coalesce(input,0)- coalesce(output,0) +
coalesce(
(select
sum(coalesce(input,0)-coalesce(output,0))
from stock b
where b.transID < a.transID
),0)
from stock a
order by transID

谢谢.......

【讨论】:

【参考方案5】:

使用 arcain 示例表,您可以使用以下查询,利用窗口功能来完成工作。

--arcain sample table 

declare @stock table (
      transId int not null identity(1,1), 
      [date] date not null, -- use datetime if not using SQL Server 2008
      input decimal(7,2) null, 
      [output] decimal(7,2) null
    );

insert into @stock values
('1/23/2011', 12.22, null),
('1/23/2011', null, 2.22),
('1/24/2011', 16, null),
('1/24/2011', 3.76, null),
('1/24/2011', null, 5.50);

查询

SELECT *,
        SUM( COALESCE(input,0) - COALESCE(output,0) ) 
            OVER (PARTITION BY date ORDER BY date,transId ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
FROM @stock

【讨论】:

以上是关于使用 SQL Select 语句计算空值的主要内容,如果未能解决你的问题,请参考以下文章

SQL语句条件为空值

如何写sql语句去掉oracle返回结果中的空值(NULL)

关于Oracle的SQL语句中group by的空值问题请教?

检查 MS Access SQL 语句中的空值

sql如何判断字段的值是否空值

sql查询不为空的字段