Home > Mobile >  When I'm doing this query I'm getting NULL values. Why?
When I'm doing this query I'm getting NULL values. Why?

Time:12-31

I have a table called fact_trip which has a column as fare_final and I want to find the difference between values.

SQL> desc fact_trip
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 TRIP_UUID                                 NOT NULL VARCHAR2(20)
 DATESTR                                            DATE
 PRODUCT_TYPE_NAME                                  VARCHAR2(20)
 CITY_ID                                            NUMBER
 DRIVER_UUID                                        VARCHAR2(50)
 IS_COMPLETED                                       VARCHAR2(10)
 ETA                                                NUMBER
 ATA                                                NUMBER
 UFP_FARE                                           NUMBER(4,2)
 FARE_FINAL                                         NUMBER(4,2)

So when I do this I'm getting NULL as output:

SQL>  select sum(fare_final) from fact_trip where to_char(datestr, 'W')=1 - (select sum(fare_final) from fact_trip where to_char(datestr, 'W')=2);

SUM(FARE_FINAL)
---------------

I even tried doing those select queries individually like this:

SQL> select sum(fare_final) from fact_trip where to_char(datestr, 'W')=1;

SUM(FARE_FINAL)
---------------
         1821.6

SQL> select sum(fare_final) from fact_trip where to_char(datestr, 'W')=2;

SUM(FARE_FINAL)
---------------
             67

Which is of course fetching result. But then when I run those queries for what I want a difference of them, it's showing NULL. Like I want difference of them (1821.6 - 67). Can anybody tell what's wrong in it? Thank You!

CodePudding user response:

Should be

SELECT SUM (
          CASE
             WHEN TO_CHAR (datestr, 'W') = 1 THEN  fare_final
             WHEN TO_CHAR (datestr, 'W') = 2 THEN -fare_final
          END)
  FROM fact_trip;

I don't have your table so I'll illustrate it on Scott's EMP, computing the total for analysts and clerks:

SQL>   SELECT job, sal FROM emp ORDER BY job;

JOB              SAL
--------- ----------
ANALYST         3000  --> total for analysts is 6000
ANALYST         3000
CLERK           1300  --> total for clerks   is 4150
CLERK            950
CLERK            800  --> difference: 6000 - 4150 = 1850
CLERK           1100
MANAGER         2850
MANAGER         2975
MANAGER         2450
PRESIDENT       5000
SALESMAN        1500
SALESMAN        1250
SALESMAN        1250
SALESMAN        1600

14 rows selected.

SQL> SELECT SUM (
  2            CASE WHEN job = 'ANALYST' THEN  sal
  3                 WHEN job = 'CLERK'   THEN -sal
  4            END) total
  5    FROM emp;

     TOTAL
----------
      1850

SQL>

CodePudding user response:

SQL is not a worksheet, where you may evaluate any expression. You cannot use an expression as a SQL command: you have to eitherselect an expression from something, or calculate it in PL/SQL block.

You want to calculate the difference, so you assumed your code is: subquery - subquery. But because of described above this is not syntactically correct command, and parser tries to find a parse tree which is syntactically correct. And it actually finds one:

select sum(fare_final)
from fact_trip
where to_char(datestr, 'W') = (
  1 - (
    select sum(fare_final)
    from fact_trip
    where to_char(datestr, 'W') = 2
  )
)

Of course, such week doesn't exist and you get null as a result.

To turn your code into a correct command, the simplest way is to select the expression from a dual table with appropriate brackets to specify calculation precedence:

select
  (select sum(fare_final) from fact_trip where to_char(datestr, 'W')='1')
  - (select sum(fare_final) from fact_trip where to_char(datestr, 'W')='2') as res
from dual

But more performant and set-based approach would be:

select
  sum(
    case to_char(datestr, 'W')
      when '1' then 1
      when '2' then -1
    end * fare_final
  ) as res
from fact_trip
where to_char(datestr, 'W') in ('1', '2')

Below is the sample code with results of all that was described above:

select * from t
ID | VAL
-: | --:
 1 |   3
 2 |   6
 3 |   9
select sum(val)
from t
where id = 1 - (
  select sum(val)
  from t
  where id = 2
)
| SUM(VAL) |
| -------: |
|     null |
select
  (
(select sum(val)
from t
where id = 1) - (
  select sum(val)
  from t
  where id = 2
)
  ) as q
from dual
|  Q |
| -: |
| -3 |
select
  sum(
    case id
     when 1 then 1
     when 2 then -1
    end * val
  ) as res
from t
where id in (1, 2)
| RES |
| --: |
|  -3 |

db<>fiddle here

  • Related