Home » SQL & PL/SQL » SQL & PL/SQL » emp nums which makes a total of $70000
emp nums which makes a total of $70000 [message #43640] Wed, 13 August 2003 03:40 Go to next message
Narayan
Messages: 12
Registered: August 2002
Junior Member
Dear all,
I have a table emp as emp(emp_num , salary) and the values are
1001, $10000
1002, $20000
1005, $40000
1006, $10000
1007, $5000
1003, $50000
I want see the records which makes a total of $70000
Can anybody throw some light on it using a SQL Query or PL/SQL.
In this case there are 4 combinations
1001, $10000 1002, $20000 1003, $50000 1003, $50000
1002, $20000 1005, $40000 1001, $10000 1002, $20000
1005, $40000 1006, $10000 1006, $10000
Is it possible to see all these combinations using a sql query or pl/sql. Any help much appreciated.
Re: emp nums which makes a total of $70000 [message #43643 is a reply to message #43640] Wed, 13 August 2003 09:06 Go to previous messageGo to next message
Art Metzer
Messages: 2480
Registered: December 2002
Senior Member
quote from Narayan:
----------------------------------------------------------------------
Dear all,
I have a table emp as emp(emp_num , salary) and the values are 
1001, $10000
1002, $20000
1005, $40000
1006, $10000
1007, $5000
1003, $50000
I want see the records which makes a total of $70000
Can anybody throw some light on it using a SQL Query or PL/SQL.
In this case there are 4 combinations 
1001, $10000 1002, $20000 1003, $50000 1003, $50000
1002, $20000 1005, $40000 1001, $10000 1002, $20000
1005, $40000 1006, $10000 1006, $10000 
Is it possible to see all these combinations using a sql query or pl/sql. Any help much appreciated.

----------------------------------------------------------------------
Narayan,

This solution requires at least version 9i, namely because I'm calling an analytic function (i.e.,ROW_NUMBER()) from within PL/SQL.

First, here are some helper functions (that I picked up from here) that you will need; they convert decimal numbers to VARCHAR2s of their binary representations:
SQL> CREATE OR REPLACE FUNCTION to_base (
  2      p_dec   IN  NUMBER
  3  ,   p_base  IN  NUMBER)
  4  RETURN VARCHAR2
  5  IS
  6      l_str VARCHAR2(255) DEFAULT NULL;
  7      l_num NUMBER DEFAULT p_dec;
  8      l_hex VARCHAR2(16) DEFAULT '0123456789ABCDEF';
  9  BEGIN
 10      IF ((p_dec IS NULL) OR (p_base IS NULL))
 11      THEN
 12          RETURN (NULL);
 13      END IF;
 14      IF ((TRUNC(p_dec) != p_dec) OR (p_dec < 0)) THEN
 15          RAISE PROGRAM_ERROR;
 16      END IF;
 17      LOOP
 18          l_str := SUBSTR(l_hex, MOD(l_num, p_base) + 1, 1) || l_str;
 19          l_num := TRUNC(l_num / p_base);
 20          EXIT WHEN (l_num = 0);
 21      END LOOP;
 22      RETURN (l_str);
 23  END to_base;
 24  /
  
Function created.
  
SQL> CREATE OR REPLACE FUNCTION to_dec (
  2      p_str       IN  VARCHAR2
  3  ,   p_from_base IN  NUMBER DEFAULT 16)
  4  RETURN NUMBER
  5  IS
  6      l_num   NUMBER DEFAULT 0;
  7      l_hex   VARCHAR2(16) DEFAULT '0123456789ABCDEF';
  8  BEGIN
  9      IF ((p_str IS NULL) OR (p_from_base IS NULL))
 10      THEN
 11          RETURN TO_NUMBER(NULL);
 12      END IF;
 13      FOR i IN 1..LENGTH(p_str) LOOP
 14          l_num := l_num * p_from_base + INSTR(l_hex,UPPER(SUBSTR(p_str,i,1))) - 1;
 15      END LOOP;
 16      RETURN (l_num);
 17  END to_dec;
 18  /
  
Function created.
  
SQL> CREATE OR REPLACE FUNCTION to_hex(p_dec IN NUMBER) RETURN VARCHAR2
  2  IS
  3  BEGIN
  4      RETURN to_base(p_dec,16);
  5  END to_hex;
  6  /
  
Function created.
  
SQL> CREATE OR REPLACE FUNCTION to_bin(p_dec IN NUMBER) RETURN VARCHAR2
  2  IS
  3  BEGIN
  4      RETURN to_base(p_dec,2);
  5  END to_bin;
  6  /
  
Function created.
  
SQL> CREATE OR REPLACE FUNCTION to_oct(p_dec IN NUMBER) RETURN VARCHAR2
  2  IS
  3  BEGIN
  4      RETURN to_base(p_dec,8);
  5  END to_oct;
  6  /
  
Function created.
Secondly, here is how I set up my data:
SQL> CREATE TABLE t_emp (emp_num NUMBER, salary NUMBER);
  
Table created.
  
SQL> INSERT INTO t_emp VALUES (1001, 10000);
  
1 row created.
  
SQL> INSERT INTO t_emp VALUES (1002, 20000);
  
1 row created.
  
SQL> INSERT INTO t_emp VALUES (1003, 50000);
  
1 row created.
  
SQL> INSERT INTO t_emp VALUES (1004, TO_NUMBER(NULL));
  
1 row created.
  
SQL> INSERT INTO t_emp VALUES (1005, 40000);
  
1 row created.
  
SQL> INSERT INTO t_emp VALUES (1006, 10000);
  
1 row created.
  
SQL> INSERT INTO t_emp VALUES (1007, 5000);
  
1 row created.
  
SQL> COMMIT;
  
Commit complete.
And here is the procedure that crunches the numbers:
SQL> CREATE OR REPLACE PROCEDURE find_rows_summing_up_to (
  2      p_seeking_sum   IN  NUMBER
  3  )
  4  AS
  5      CURSOR c_hits (
  6          p_binary_string     IN  VARCHAR2)
  7      IS
  8          SELECT t_pop.emp_num
  9          ,      t_pop.salary
 10          FROM  (SELECT ROW_NUMBER() OVER (ORDER BY t.emp_num) rn
 11                 ,       t.emp_num
 12                 ,       t.salary
 13                 FROM    t_emp     t
 14                 WHERE   t.salary IS NOT NULL) t_pop
 15          WHERE  SUBSTR(p_binary_string,t_pop.rn,1) = '1'
 16      ;
 17      l_depth             PLS_INTEGER := 0;
 18      l_binary_string     VARCHAR2(255);
 19      l_candidate_sum     NUMBER;
 20  BEGIN
 21      SELECT COUNT(*)
 22      INTO   l_depth
 23      FROM   t_emp    t
 24      WHERE  t.salary IS NOT NULL;
 25      
 26      IF ((l_depth > 0)
 27      AND (p_seeking_sum IS NOT NULL)) THEN
 28          FOR i IN 1..POWER(2,l_depth) LOOP
 29              l_binary_string := LPAD(to_bin(i),l_depth,'0');
 30              SELECT SUM(TO_NUMBER(SUBSTR(l_binary_string,t_pop.rn,1)) * t_pop.salary)
 31              INTO   l_candidate_sum
 32              FROM  (SELECT (ROW_NUMBER() OVER (ORDER BY t.emp_num)) rn
 33                     ,       t.emp_num
 34                     ,       t.salary
 35                     FROM    t_emp    t
 36                     WHERE   t.salary IS NOT NULL) t_pop;
 37              IF (l_candidate_sum = p_seeking_sum) THEN
 38                  FOR emps IN c_hits(l_binary_string) LOOP
 39                      DBMS_OUTPUT.PUT_LINE('ID = '
 40                                           || emps.emp_num
 41                                           || ', salary = '
 42                                           || LPAD(emps.salary,7));
 43                  END LOOP;
 44                  DBMS_OUTPUT.PUT_LINE(RPAD('.',30,'.'));
 45              END IF;
 46          END LOOP;
 47      END IF;
 48  END find_rows_summing_up_to;
 49  /
  
Procedure created.
And finally, here's how you call it:
SQL> EXEC find_rows_summing_up_to(70000);
ID = 1002, salary =   20000
ID = 1005, salary =   40000
ID = 1006, salary =   10000
..............................
ID = 1002, salary =   20000
ID = 1003, salary =   50000
..............................
ID = 1001, salary =   10000
ID = 1003, salary =   50000
ID = 1006, salary =   10000
..............................
ID = 1001, salary =   10000
ID = 1002, salary =   20000
ID = 1005, salary =   40000
..............................
  
PL/SQL procedure successfully completed.
  
SQL> 
A word of caution, Narayan....The above is only practical for tables with very few rows. The addition of each row to t_emp will cause the runtime of this procedure--namely, the FOR loop that begins on line 28--to roughly double.

Good luck,

A.
Re: emp nums which makes a total of $70000 [message #43651 is a reply to message #43643] Thu, 14 August 2003 04:05 Go to previous messageGo to next message
Babu Samuel
Messages: 2
Registered: August 2003
Junior Member
The easiest way of doing this is by a simple SQL statement. Assuming that you need only three records (max) in each distinct combination - the number of records is directly proportional to the number of occurences of the table reference used in this query.

SELECT a.emp_num, a.salary, b.emp_num, b.salary, c.emp_num, c.salary
FROM emp a, emp b, emp c
WHERE a.emp_num <> b.emp_num
AND b.emp_num <> c.emp_num
AND a.emp_num <> c.emp_num
AND ( a.salary
+ b.salary
+ c.salary = 70000
)
UNION
SELECT a.emp_num, a.salary, b.emp_num, b.salary, NULL, NULL
FROM emp a, emp b
WHERE a.emp_num <> b.emp_num AND ( a.salary
+ b.salary = 70000
)
/

Please note this will work in 9i version, if you are using lesser version of DB, you may have to use to_number on null to avoid value error.

Hope this helps!

Cheers,
Sam
Re: emp nums which makes a total of $70000 [message #43653 is a reply to message #43651] Thu, 14 August 2003 05:26 Go to previous messageGo to next message
Narayan
Messages: 12
Registered: August 2002
Junior Member
Babu,
Sorry to tell you but your query doesn't seem to work because as you have not mentoned any joins(=) then how would you expect to return results. I have tired your query but it came up with no rows selected. Thanx for your effort.

Cheers
Narayan
Re: emp nums which makes a total of $70000 [message #43654 is a reply to message #43643] Thu, 14 August 2003 05:30 Go to previous messageGo to next message
Narayan
Messages: 12
Registered: August 2002
Junior Member
Art,
As we are still using oracle 7.3.4 and 8.0.6 can you help me with the functionalities which are supported by 7.3.4 and 8.0.6. Thanx for your effort.

Cheers
Nan
Re: emp nums which makes a total of $70000 [message #43656 is a reply to message #43643] Thu, 14 August 2003 06:10 Go to previous messageGo to next message
Narayan
Messages: 12
Registered: August 2002
Junior Member
Art,
Your Script is working perfectly even without ROW_NUM and OVER functions. Its just 200%perfect.
Thanks a million.

Cheers
Nan
Re: emp nums which makes a total of $70000 [message #43657 is a reply to message #43653] Thu, 14 August 2003 09:11 Go to previous messageGo to next message
Babu Samuel
Messages: 2
Registered: August 2003
Junior Member
I am not sure why it didn't work for you. It worked for me. I have just used "Amount" instead of "Salary"

The results after executing the query is:

EMPNO AMOUNT EMPNO AMOUNT EMPNO AMOUNT
---------- ---------- ---------- ---------- ---------- ----------
1 10000 2 20000 3 40000
1 10000 3 40000 2 20000
1 10000 4 10000 6 50000
1 10000 6 50000 4 10000
2 20000 1 10000 3 40000
2 20000 3 40000 1 10000
2 20000 3 40000 4 10000
2 20000 4 10000 3 40000
2 20000 6 50000 # #
3 40000 1 10000 2 20000
3 40000 2 20000 1 10000
3 40000 2 20000 4 10000
3 40000 4 10000 2 20000
4 10000 1 10000 6 50000
4 10000 2 20000 3 40000
4 10000 3 40000 2 20000
4 10000 6 50000 1 10000
6 50000 1 10000 4 10000
6 50000 2 20000 # #
6 50000 4 10000 1 10000

You might be missing something I guess! The problem with this query is it tries and throws all the possible combinations, the query can be re-written to select only distinct combinations.

Cheers,
Babu
Re: emp nums which makes a total of $70000 [message #43658 is a reply to message #43657] Thu, 14 August 2003 10:11 Go to previous message
Narayan
Messages: 12
Registered: August 2002
Junior Member
Babu,
I am sorry about my previous post. Its working fine. I missed a <> join condition. Thanx for your help
Much appreciated.

Cheers
Nan
Previous Topic: columns on which indexes is made
Next Topic: Oracle to SQL Server
Goto Forum:
  


Current Time: Sat Apr 27 00:20:36 CDT 2024