user1583775
user1583775

Reputation: 45

decode is not working in oracle sql query

I have here simple query using group function.Here is the query

SELECT DECODE (DIRAPP, NULL, 'SML', DIRAPP) DD
  FROM (SELECT      'At Director Approval '
                 || NVL (COUNT (*), 0)
                 || ' Cheques of Rs. '
                 || NVL (TO_CHAR (SUM (BPV_AMT), '9,999,999,999'), 0)
                 || ' in '
                 || CONCATENATE_LIST
                                 (CURSOR (SELECT DISTINCT NVL
                                                             (BPV_DTE,
                                                              SYSDATE
                                                             ) BPV_DTE
                                                     FROM CHECK_DATA
                                                    WHERE STA_FLG IN (1, 3)
                                                 ORDER BY 1 DESC
                                         )
                                 ) DIRAPP
            FROM CHECK_DATA
           WHERE STA_FLG IN (1, 3)
        GROUP BY 1, 2) A

I have used the nvl function and also decode but when no data found against the flags 1 and 3 then nothing is shown even 0 from nvl and also working decode.I want to show the whole string with as At Director Approval 0 Cheques of Rs.0 Please any one help me to do this

Upvotes: 0

Views: 2054

Answers (1)

Alex Poole
Alex Poole

Reputation: 191275

decode isn't broken, it just has no data to work with. You are filtering on where sta_flg in (1,3), so if there are no records with either status, there are no rows at all. You can't decode what doesn't exist.

One way around this is to change the way you're counting and summing the values so that the filtering is effectively done within the select, not the where. Removing the formatting for a moment, rather than doing:

SELECT COUNT(*), SUM(BPV_AMT)
FROM check_data
WHERE sta_flag IN (1,3);

... which will return no rows if there are no records with matching flags, even if there is other data in the table, you can do:

SELECT SUM(CASE WHEN sta_flg IN (1,3) THEN 1 ELSE 0 END) AS rec_cnt,
    SUM(CASE WHEN sta_flg IN (1,3) THEN bpv_amt ELSE 0 END) AS bpv_amt_tot
FROM check_data;

As long as the table isn't empty, this will return a single row of data, with either normal values or both rec_cnt and bpv_amt_tot set to zero.

Plugging that in as an inner select your query might look like:

SELECT 'At Director Approval '
    || rec_cnt
    || ' Cheques of Rs. '
    || TO_CHAR(bpv_amt_tot, '9,999,999,999')
    || CASE WHEN rec_cnt = 0 THEN NULL
        ELSE ' in ' || CONCATENATE_LIST(CURSOR(
            SELECT DISTINCT NVL(bpv_dte, SYSDATE)
            FROM check_data
            WHERE sta_flg IN (1, 3)
            ORDER BY 1 DESC
        )) END AS dirapp
FROM (
    SELECT SUM(CASE WHEN sta_flg IN (1,3) THEN 1 ELSE 0 END) AS rec_cnt,
        SUM(CASE WHEN sta_flg IN (1,3) THEN bpv_amt ELSE 0 END) AS bpv_amt_tot
    FROM check_data
);

The case around the ' in ' || CONCATENATE_LIST(... part is just to avoid a trailing in appearing when there are no matching statuses.

Since you aren't selecting any non-aggregated columns, you don't need a group by clause. (And the one you had was incorrect anyway - you can't group by column positions, so group by 1,2 is grouping by two constant values, which doesn't add anything).

And finally, since you're using concatenate_list() I assume you're on a version earlier than 11gR2; if you are on the current version then the built-in listagg() would be simpler.

Upvotes: 3

Related Questions