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 |
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 |
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 |
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 |
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 #43657 is a reply to message #43653] |
Thu, 14 August 2003 09:11 |
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
|
|
|
|
Goto Forum:
Current Time: Sat Apr 27 00:20:36 CDT 2024
|