Home » SQL & PL/SQL » SQL & PL/SQL » Need Help in SQL Query (Oracle 11g)
Need Help in SQL Query [message #644373] Wed, 04 November 2015 03:49 Go to next message
arifs3738
Messages: 39
Registered: November 2015
Location: India
Member
Q) List employee name, salary and his income group as 'LOW' or 'HIGH' depending on the salary amount. (If the salary is less than 4000 then he is in 'LOW' income group or else in 'HIGH' income group)?
ENAME SALARY LOW HIGH
SCOTT 3000 LOW
KING 5000 HIGH

I have achieved this with CASE STATEMENT as below:
SELECT E.*,
(CASE WHEN SAL < 4000 THEN 'LOW'
ELSE 'HIGH'
END) AS INCOME_GRP
FROM EMP E
ORDER BY INCOME_GRP;


Note: i was asked without case statement how can we write this in SQL. Please help me in writing this small SQL.

Thanks
Re: Need Help in SQL Query [message #644374 is a reply to message #644373] Wed, 04 November 2015 03:52 Go to previous messageGo to next message
John Watson
Messages: 8929
Registered: January 2010
Location: Global Village
Senior Member
Try the DECODE function. Though it is an odd piece of homework - CASE is much newer and generally a better way.

[Updated on: Wed, 04 November 2015 03:52]

Report message to a moderator

Re: Need Help in SQL Query [message #644375 is a reply to message #644373] Wed, 04 November 2015 03:53 Go to previous messageGo to next message
John Watson
Messages: 8929
Registered: January 2010
Location: Global Village
Senior Member
Sorry, I forgot to do the Moderator bit:

Welcome to the forum. Please read our OraFAQ Forum Guide and How to use [code] tags and make your code easier to read
Re: Need Help in SQL Query [message #644377 is a reply to message #644375] Wed, 04 November 2015 04:22 Go to previous messageGo to next message
arifs3738
Messages: 39
Registered: November 2015
Location: India
Member
Apart from Decode in general can we write this using SQL.
Re: Need Help in SQL Query [message #644378 is a reply to message #644377] Wed, 04 November 2015 04:27 Go to previous messageGo to next message
John Watson
Messages: 8929
Registered: January 2010
Location: Global Village
Senior Member
What's wrong with decode? Alternatively, you could inlcude a scalar subquery in your column projection list. Not very efficient, though.
Re: Need Help in SQL Query [message #644379 is a reply to message #644377] Wed, 04 November 2015 04:33 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Unless there's some other table that holds income groups there is no easy way to do this without using case and decode. You have to use some functions to check the income and output the resulting text.
Re: Need Help in SQL Query [message #644380 is a reply to message #644378] Wed, 04 November 2015 04:35 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
John Watson wrote on Wed, 04 November 2015 10:27
Alternatively, you could inlcude a scalar subquery in your column projection list.


How does that avoid decode?
Re: Need Help in SQL Query [message #644381 is a reply to message #644379] Wed, 04 November 2015 04:35 Go to previous messageGo to next message
Michel Cadot
Messages: 68641
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator

You can use a UNION ALL.

Re: Need Help in SQL Query [message #644383 is a reply to message #644380] Wed, 04 November 2015 04:36 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
You could avoid decode and case by using a combination of nvl2, nullif and sign but that would just be silly
Re: Need Help in SQL Query [message #644384 is a reply to message #644381] Wed, 04 November 2015 04:36 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Michel Cadot wrote on Wed, 04 November 2015 10:35

You can use a UNION ALL.



That I should have thought of.
Re: Need Help in SQL Query [message #644386 is a reply to message #644380] Wed, 04 November 2015 04:42 Go to previous messageGo to next message
John Watson
Messages: 8929
Registered: January 2010
Location: Global Village
Senior Member
cookiemonster wrote on Wed, 04 November 2015 10:35
John Watson wrote on Wed, 04 November 2015 10:27
Alternatively, you could inlcude a scalar subquery in your column projection list.


How does that avoid decode?

I was thinking of something like
select 'low' from emp where sal < 4000 and ....
which will return either 'low' or null, and using coalesce to combine the result of that with another scalar subquery that would return 'high' or null.

Arif, you have been given a lot of hints. What have you tried?
Re: Need Help in SQL Query [message #644388 is a reply to message #644386] Wed, 04 November 2015 04:59 Go to previous messageGo to next message
arifs3738
Messages: 39
Registered: November 2015
Location: India
Member
Hi All,

Thanks for the superb and prompt reply...
i tried below code with Union All

SELECT E.*, 'LOW' 
FROM EMP E
WHERE SAL < 4000
UNION ALL
SELECT E.*, 'HIGH' 
FROM EMP E
WHERE SAL > 4000;


but in the above query i dont want a single column as Low. i want two columns as Low & High. If sal is less than 4K then Low should be written in Low Columns else High in High Column.

Please give me query this time.
  • Attachment: OUTPUT.png
    (Size: 0.00KB, Downloaded 999 times)
Re: Need Help in SQL Query [message #644389 is a reply to message #644388] Wed, 04 November 2015 05:03 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Then you'll need to use null to make the third column
Re: Need Help in SQL Query [message #644390 is a reply to message #644386] Wed, 04 November 2015 05:07 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
John Watson wrote on Wed, 04 November 2015 10:42

I was thinking of something like
select 'low' from emp where sal < 4000 and ....
which will return either 'low' or null, and using coalesce to combine the result of that with another scalar subquery that would return 'high' or null.

Unless you're worried about sal being null I don't think you need a second subqery
Re: Need Help in SQL Query [message #644391 is a reply to message #644390] Wed, 04 November 2015 05:10 Go to previous messageGo to next message
arifs3738
Messages: 39
Registered: November 2015
Location: India
Member
Please lemme know the query of how i will make the second column null if the value is entered in first.
Re: Need Help in SQL Query [message #644394 is a reply to message #644391] Wed, 04 November 2015 05:24 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
by typing null:
SELECT E.*, 'LOW' as low, null as high
FROM EMP E
WHERE SAL < 4000
.....
Re: Need Help in SQL Query [message #644395 is a reply to message #644394] Wed, 04 November 2015 05:32 Go to previous messageGo to next message
arifs3738
Messages: 39
Registered: November 2015
Location: India
Member
thanks all of you, i am a newbie to SQL...
As per your suggestions, i m getting what i wanted as an output....
You all are Rockstar!!!
Query:

SELECT E.*, 'LOW' as LOW, NULL as HIGH
FROM EMP E
WHERE SAL < 4000
UNION ALL
SELECT E.*, NULL as HIGH, 'HIGH' as HIGH
FROM EMP E
WHERE SAL > 4000;


thanks....
Will be back with another one soon.
Re: Need Help in SQL Query [message #644404 is a reply to message #644395] Wed, 04 November 2015 07:09 Go to previous messageGo to next message
John Watson
Messages: 8929
Registered: January 2010
Location: Global Village
Senior Member
Well done! One point - what will you get if sal=4000 ? What if sal is NULL ?
This was my solution:
select
e.ename,e.sal,
coalesce(
(select 'low' from emp f where f.empno=e.empno and sal < 4000),
(select 'high' from emp f where f.empno=e.empno and sal >= 4000)
)
from emp e;

If you want top marks for this assignment, you might mention the efficiency of the query. This is thr execution plan I get for your solution,
Plan hash value: 1301082189

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    14 |   560 |     6   (0)| 00:00:01 |
|   1 |  UNION-ALL         |      |       |       |            |          |
|*  2 |   TABLE ACCESS FULL| EMP  |     8 |   320 |     3   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| EMP  |     6 |   240 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("SAL"<4000)
   3 - filter("SAL">4000)

orclz>

and this is mine,
Execution Plan
----------------------------------------------------------
Plan hash value: 732000419

---------------------------------------------------------------------------------------
| Id  | Operation                    | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |        |    15 |   225 |    18   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS BY INDEX ROWID | EMP    |     1 |     9 |     1   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN          | PK_EMP |     1 |       |     0   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS BY INDEX ROWID| EMP    |     1 |     9 |     1   (0)| 00:00:01 |
|*  4 |    INDEX UNIQUE SCAN         | PK_EMP |     1 |       |     0   (0)| 00:00:01 |
|   5 |  TABLE ACCESS FULL           | EMP    |    15 |   225 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("SAL"<4000)
   2 - access("F"."EMPNO"=:B1)
   3 - filter("SAL">=4000)
   4 - access("F"."EMPNO"=:B1)

orclz>

Which is better? That would depend on the hardware, the size of the tables, whether you can use parallel query, direct or indirect reads, any number of foactors.


Re: Need Help in SQL Query [message #644405 is a reply to message #644404] Wed, 04 November 2015 10:16 Go to previous messageGo to next message
Solomon Yakobson
Messages: 3273
Registered: January 2010
Location: Connecticut, USA
Senior Member
Another approach:

SQL> explain plan for
  2  with t as (
  3             select  4000 sal,
  4                     'HIGH' grade
  5               from  dual
  6            )
  7  select  e.*,
  8          nvl(grade,'LOW') grade
  9    from  emp e,
 10          t
 11    where t.sal(+) <= e.sal
 12  /

Explained.

SQL> select  *
  2    from  table(dbms_xplan.display)
  3  /

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------
Plan hash value: 4010907715

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |    14 |   560 |     6  (17)| 00:00:01 |
|   1 |  MERGE JOIN OUTER   |      |    14 |   560 |     6  (17)| 00:00:01 |
|   2 |   SORT JOIN         |      |    14 |   532 |     4  (25)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| EMP  |    14 |   532 |     3   (0)| 00:00:01 |
|*  4 |   SORT JOIN         |      |     1 |     2 |     2   (0)| 00:00:01 |
|   5 |    TABLE ACCESS FULL| DUAL |     1 |     2 |     2   (0)| 00:00:01 |

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access(INTERNAL_FUNCTION("E"."SAL")>=CASE  WHEN (ROWID(+) IS NOT
              NULL) THEN 4000 ELSE NULL END )
       filter(INTERNAL_FUNCTION("E"."SAL")>=CASE  WHEN (ROWID(+) IS NOT
              NULL) THEN 4000 ELSE NULL END )

20 rows selected.

SQL> 


This uses just a single pass through EMP table.

SY.
Re: Need Help in SQL Query [message #644545 is a reply to message #644405] Mon, 09 November 2015 07:52 Go to previous messageGo to next message
mnitu
Messages: 159
Registered: February 2008
Location: Reims
Senior Member
Basically it's the same idea but seems to be cheaper
Select e.*, 
       Nvl(t.grade,'High') grade
  From emp e
       Left Join 
       (Select -1 grp, 'Low' grade from dual) t
    On t.grp = sign(sal - 4000)
Re: Need Help in SQL Query [message #644546 is a reply to message #644545] Mon, 09 November 2015 08:18 Go to previous messageGo to next message
Solomon Yakobson
Messages: 3273
Registered: January 2010
Location: Connecticut, USA
Senior Member
mnitu wrote on Mon, 09 November 2015 08:52
Basically it's the same idea but seems to be cheaper


Are you sure it's cheaper?

SQL> declare
  2      v_sum number := 0;
  3      cursor v_cur
  4        is
  5  with t as (
  6             select  4000 sal,
  7                     'HIGH' grade
  8               from  dual
  9            )
 10  select  e.*,
 11          nvl(grade,'LOW') grade
 12    from  emp e,
 13          t
 14    where t.sal(+) <= e.sal;
 15  begin
 16      for v_i in 1..100000 loop
 17        for v_rec in v_cur loop
 18          v_sum := v_sum + v_rec.sal;
 19        end loop;
 20      end loop;
 21  end;
 22  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:08.18
SQL> declare
  2      v_sum number := 0;
  3      cursor v_cur
  4        is
  5  Select e.*, 
  6         Nvl(t.grade,'High') grade
  7    From emp e
  8         Left Join 
  9         (Select -1 grp, 'Low' grade from dual) t
 10      On t.grp = sign(sal - 4000);
 11  begin
 12      for v_i in 1..100000 loop
 13        for v_rec in v_cur loop
 14          v_sum := v_sum + v_rec.sal;
 15        end loop;
 16      end loop;
 17  end;
 18  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:12.48
SQL> 


SY.
Re: Need Help in SQL Query [message #644548 is a reply to message #644546] Mon, 09 November 2015 10:22 Go to previous messageGo to next message
mnitu
Messages: 159
Registered: February 2008
Location: Reims
Senior Member
I said "seems" because I just compared estimated cpu_cost for your query <cpu_cost>7654027</cpu_cost> with mine <cpu_cost>3863464</cpu_cost> others things being equal.
I can beat your example with a scalar sub-query but that's cheating.
Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 

SQL> set timi on
SQL> 
SQL> declare
  2     v_sum number := 0;
  3     cursor v_cur
  4     is
  5     with t as (
  6          select  4000 sal,
  7                  'HIGH' grade
  8            from  dual
  9     )
 10    select  e.*,
 11            nvl(grade,'LOW') grade
 12      from  emp e,
 13            t
 14      where t.sal(+) <= e.sal;
 15  begin
 16    for v_i in 1..100000 loop
 17       for v_rec in v_cur loop
 18           v_sum := v_sum + v_rec.sal;
 19        end loop;
 20    end loop;
 21  end;
 22  /
PL/SQL procedure successfully completed
Executed in 16,443 seconds
SQL> declare
  2     v_sum number := 0;
  3     cursor v_cur
  4     is
  5     Select e.*,
  6            Nvl((Select 'Low' grade from dual where Sign(sal-4000) = -1),'High') grade
  7       From emp e;
  8  begin
  9    for v_i in 1..100000 loop
 10       for v_rec in v_cur loop
 11           v_sum := v_sum + v_rec.sal;
 12        end loop;
 13    end loop;
 14  end;
 15  /
PL/SQL procedure successfully completed
Executed in 13,54 seconds

SQL> 


Re: Need Help in SQL Query [message #644550 is a reply to message #644548] Mon, 09 November 2015 10:40 Go to previous message
Michel Cadot
Messages: 68641
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator

Quote:
I can beat your example with a scalar sub-query but that's cheating.


I think so as it falls in the case/decode category.

Previous Topic: sql query help
Next Topic: PLSQL Collection index by varchar
Goto Forum:
  


Current Time: Sat Apr 20 10:51:37 CDT 2024