如何构造SQL查询以不为计算返回null

时间:2018-02-20 00:49:24

标签: mysql sql mariadb

我正在尝试构建一个执行以下操作的查询;

1)查询具有给定'acctuniqueid'的行,该行具有'acctoutputoctets'的第二大值,或者如果找不到匹配的行,则返回0

2)执行以下计算250 + 350-('acctinputoctets'的返回值+'acctoutputoctets'的返回值'||“0”)

使用“a25d16693309cdb4807effe00a9f076c”作为“acctuniqueid”字段。

表名:radacct

示例#1

+-----------+----------------------------------+-----------------+------------------+
| radacctid |           acctuniqueid           | acctinputoctets | acctoutputoctets |
+-----------+----------------------------------+-----------------+------------------+
|         5 | a25d16693309cdb4807effe00a9f076c |             150 |              250 |
|         8 | a25d16693309cdb4807effe00a9f076c |             250 |              350 |
+-----------+----------------------------------+-----------------+------------------+

示例#2

+-----------+----------------------------------+-----------------+------------------+
| radacctid |           acctuniqueid           | acctinputoctets | acctoutputoctets |
+-----------+----------------------------------+-----------------+------------------+
|         4 | a25d16693309cdb4807effe00a9f076c |             250 |              350 |
+-----------+----------------------------------+-----------------+------------------+

在示例#1中:250 + 350-(150 + 250)= 200 所以预期的结果是200

在示例#2中:250 + 350-(0)= 600 所以预期的结果是600

查询我到目前为止一直在修补:

SELECT  (SUM(250)+SUM(350)-((SUM(IFNULL(acctinputoctets,0)))+
                            (SUM(IFNULL(acctoutputoctets,0))))
        )
    FROM  
        ( SELECT  *,IFNULL(acctinputoctets,0),
                    IFNULL(acctoutputoctets,0)
            FROM  radacct
            WHERE  acctuniqueid = 'a25d16693309cdb4807effe00a9f076c'
            ORDER BY  acctoutputoctets DESC
            LIMIT  1 , 1
        ) as meh

返回示例#1的内容,但是对于示例#2,我得到NULL作为结果。

应该注意的是,在上面的查询“250”中,手动添加了“350”和“a25d16693309cdb4807effe00a9f076c”以用于测试和可读性目的,但稍后将替换为运行时变量输出。

我尝试过IFNULL和COALESCE的各种迭代,组合和放置,并尝试在线搜索类似的问题/解决方案帖子 - 但是我找不到任何与我正在做的事情相近的事情有“啊哈!”那一刻。

考虑到我(缺乏)SQL经验,我猜测(a)这是非常简单的事情,有人会立即发现,和/或(b)我已经完全错误地查询了我的查询是一种不同的,更正确的结构化查询方式,这超出了我目前的知识水平。

今天早上凌晨4点,经过几个小时的咒骂,恳求和讨价还价 - 我终于承认了失败,所以提供的任何援助都会受到高度赞赏。

提前致谢。

2 个答案:

答案 0 :(得分:0)

这似乎对我有用:

示例#1

CREATE TABLE radacct (
    radacctid           int,
    acctuniqueid        nvarchar(50),
    acctinputoctets     int,
    acctoutputoctets    int
    );

INSERT INTO radacct values
    (5, 'a25d16693309cdb4807effe00a9f076c', 150, 250),
    (8, 'a25d16693309cdb4807effe00a9f076c', 250, 350)


SELECT      250 + 350
            - COALESCE((SELECT acctinputoctets FROM radacct ORDER BY acctoutputoctets DESC LIMIT 1, 1), 0)
            - COALESCE((SELECT acctoutputoctets FROM radacct ORDER BY acctoutputoctets DESC LIMIT 1, 1), 0)

示例#2

CREATE TABLE radacct (
    radacctid           int,
    acctuniqueid        nvarchar(50),
    acctinputoctets     int,
    acctoutputoctets    int
    );

INSERT INTO radacct values
    (4, 'a25d16693309cdb4807effe00a9f076c', 250, 350);


SELECT      250 + 350
            - COALESCE((SELECT acctinputoctets FROM radacct ORDER BY acctoutputoctets LIMIT 1, 1), 0)
            - COALESCE((SELECT acctoutputoctets FROM radacct ORDER BY acctoutputoctets LIMIT 1, 1), 0)

但是,如果在acctoutputoctects中有多个行绑定第二个值,那么结果将是非常随机的。例如,如果在示例#1中,两行都有350作为acctoutputoctects列中的值,则结果将取决于值的插入方式,因为两行都符合条件,但在acctinputoctects列中具有不同的值(这会影响答案)。如果您提供一些关于如何打破关系的更多信息,我很乐意修改代码以适应它。

答案 1 :(得分:0)

这里的一个主要问题是决定在抽签的情况下进行选择。这个讨厌的代码试图在离开加入之前根据radacctid选择最近的最高和第二高值以获得最终结果

drop table if exists t;
create table t( radacctid int,           acctuniqueid  varchar(40), acctinputoctets int, acctoutputoctets int);
insert into t values
(         5 , 'a25d16693309cdb4807effe00a9f076c' ,             150 ,              250), 
(         8 , 'a25d16693309cdb4807effe00a9f076c' ,             250 ,              350), 
(         9 , 'a25d16693309cdb4807effe00a9f076c' ,             200 ,              250), 
(         4 , 'b25d16693309cdb4807effe00a9f076c' ,             10 ,                10),
(         6 , 'b25d16693309cdb4807effe00a9f076c' ,             250 ,              350),
(            7 , 'c25d16693309cdb4807effe00a9f076c' ,             20 ,                30); 

select mm.acctuniqueid,mm.maxid,mm.maxin,mm.maxout ,
         sm.acctuniqueid,sm.secondmaxid,sm.secondmaxin,sm.secondmaxout,
         (ifnull(mm.maxin,0) + ifnull(mm.maxout,0)) - 
         (ifnull(sm.secondmaxin,0) + ifnull(sm.secondmaxout,0)) as Total
from
(
select t.acctuniqueid,t.radacctid maxid,t.acctinputoctets maxin,t.acctoutputoctets maxout  
from t
join
(
select t.acctuniqueid,s.maxout, max(radacctid) maxid   #adjust maxid as required
from
(
select acctuniqueid, max(acctoutputoctets) maxout
from t 
where acctoutputoctets = (select max(acctoutputoctets) from t t1 where t1.acctuniqueid = t.acctuniqueid)
group by acctuniqueid
) s
join t on t.acctuniqueid = s.acctuniqueid and t.acctoutputoctets = s.maxout
group by t.acctuniqueid,s.maxout
) s
on s.acctuniqueid = t.acctuniqueid and s.maxid = t.radacctid
) mm
left join
(
select t.acctuniqueid,t.radacctid secondmaxid,t.acctinputoctets secondmaxin,t.acctoutputoctets secondmaxout  
from t
join
(
select t.acctuniqueid,s.secondmaxout, max(radacctid) secondmaxid   #adjust secondmaxid as required
from
(
select acctuniqueid, max(acctoutputoctets) secondmaxout
from t 
where acctoutputoctets < (select max(acctoutputoctets) from t t1 where t1.acctuniqueid = t.acctuniqueid)
group by acctuniqueid
) s
join t on t.acctuniqueid = s.acctuniqueid and t.acctoutputoctets = secondmaxout
group by t.acctuniqueid,s.secondmaxout
) s
on s.acctuniqueid = t.acctuniqueid and s.secondmaxid = t.radacctid
) sm
on mm.acctuniqueid = sm.acctuniqueid

+----------------------------------+-------+-------+--------+----------------------------------+-------------+-------------+--------------+-------+
| acctuniqueid                     | maxid | maxin | maxout | acctuniqueid                     | secondmaxid | secondmaxin | secondmaxout | Total |
+----------------------------------+-------+-------+--------+----------------------------------+-------------+-------------+--------------+-------+
| a25d16693309cdb4807effe00a9f076c |     8 |   250 |    350 | a25d16693309cdb4807effe00a9f076c |           9 |         200 |          250 |   150 |
| b25d16693309cdb4807effe00a9f076c |     6 |   250 |    350 | b25d16693309cdb4807effe00a9f076c |           4 |          10 |           10 |   580 |
| c25d16693309cdb4807effe00a9f076c |     7 |    20 |     30 | NULL                             |        NULL |        NULL |         NULL |    50 |
+----------------------------------+-------+-------+--------+----------------------------------+-------------+-------------+--------------+-------+
3 rows in set (0.01 sec)

如果您只是需要最大值(或最小值)以便在抽奖时使用最大值,那么可能会简化。