Как структурировать SQL-запрос, чтобы он не возвращал ноль для расчета

0

Я пытаюсь создать запрос, который будет выполнять следующее:

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

Query, с которым я уже занимался:

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, я предполагаю, что либо (а) это что-то действительно простое, что кто-то сразу обнаружит, и/или (б) я поступил с моим запросом совершенно неправильно, и есть другое и более правильный способ структурирования этого запроса, который находится за пределами моего текущего уровня знаний.

В 4 утра этим утром, и после нескольких часов ругательства, мольбы и торг - я, наконец, признал поражение, и поэтому любая помощь была бы высоко оценена.

Заранее спасибо.

  • 0
    Разве ожидаемое значение примера № 2 не будет равно 0, поскольку есть только одна строка, и поэтому вы не можете получить строку со вторым по величине значением для acctoutputoctets? Кроме того, когда вы используете LIMIT 1, 1, для возврата нет второй строки, поэтому все значения будут нулевыми для примера № 2.
  • 1
    Чем a25d16693309cdb4807effe00a9f076c полезно включить в пример?
Показать ещё 3 комментария
Теги:
mariadb

2 ответа

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
    Я учел то, что вы говорили о двух строках, которым надоело иметь второе по величине значение, поэтому теперь я изменил структуру, включив в нее индекс, и теперь выполняю ORDER BY вместо столбца acctoutputoctets.
0

Важнейшей проблемой здесь является решение в случае ничьих, которые acctinputoctets выбрать. Этот неприятный код пытается выбрать самые последние самые высокие и самые высокие значения на основе 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)

Возможно, это может быть упрощено, если вам просто понадобилось максимальное (или мин) значение, чтобы перейти с максимальным значением в случае ничьей.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню