Table A
| Subject | Marks |
|---|---|
| A | 100 |
| B | 200 |
| C | 400 |
| D | 500 |
Table B
| Subject | Formula |
|---|---|
| A | A/B |
| B | B/D |
| C | D/A-B |
| D | A+B/C-D |
Output
| Subject | Result |
|---|---|
| A | 0.5 |
| B | 0.4 |
| C | 5 |
| D | 3 |
On
Let's build a parser in SQL....
WITH shunting_yard (subject, formula, stack, output) AS (
SELECT subject,
formula,
CAST(NULL AS VARCHAR2(4000)),
CAST(NULL AS VARCHAR2(4000))
FROM B
UNION ALL
SELECT subject,
CASE
WHEN SUBSTR(formula, 1, 1) NOT IN ('+', '-', '/', '*')
THEN SUBSTR(formula, 2)
WHEN stack IS NULL
OR DECODE(SUBSTR(stack, -1), '+', 1, '-', 1, '/', '2', '*', '2')
< DECODE(SUBSTR(formula, 1, 1), '+', 1, '-', 1, '/', '2', '*', '2')
THEN SUBSTR(formula, 2)
ELSE formula
END,
CASE
WHEN SUBSTR(formula, 1, 1) NOT IN ('+', '-', '/', '*')
THEN stack
WHEN stack IS NULL
OR DECODE(SUBSTR(stack, -1), '+', 1, '-', 1, '/', '2', '*', '2')
< DECODE(SUBSTR(formula, 1, 1), '+', 1, '-', 1, '/', '2', '*', '2')
THEN SUBSTR(formula, 1, 1) || stack
ELSE SUBSTR(stack, 2)
END,
CASE
WHEN SUBSTR(formula, 1, 1) NOT IN ('+', '-', '/', '*')
THEN output || SUBSTR(formula, 1, 1)
WHEN stack IS NULL
OR DECODE(SUBSTR(stack, -1), '+', 1, '-', 1, '/', '2', '*', '2')
< DECODE(SUBSTR(formula, 1, 1), '+', 1, '-', 1, '/', '2', '*', '2')
THEN output
ELSE output || SUBSTR(stack, 1, 1)
END
FROM shunting_yard
)
SEARCH DEPTH FIRST BY subject, formula SET order_id
CYCLE subject, formula, stack, output SET done TO 1 DEFAULT 0,
reverse_polish (subject, formula, stack, value) AS (
SELECT subject,
output,
CAST(NULL AS VARCHAR2(4000)),
CAST(NULL AS NUMBER)
FROM shunting_yard
WHERE done = 1
UNION ALL
SELECT r.subject,
SUBSTR(r.formula, 2),
CASE
WHEN SUBSTR(r.formula, 1, 1) IN ('+', '-', '*', '/')
THEN '_' || SUBSTR(r.stack, 3)
ELSE SUBSTR(r.formula, 1, 1) || r.stack
END,
CASE SUBSTR(r.formula, 1, 1)
WHEN '+'
THEN COALESCE(a2.marks, r.value) + COALESCE(a1.marks, r.value)
WHEN '-'
THEN COALESCE(a2.marks, r.value) - COALESCE(a1.marks, r.value)
WHEN '/'
THEN COALESCE(a2.marks, r.value) / COALESCE(a1.marks, r.value)
WHEN '*'
THEN COALESCE(a2.marks, r.value) * COALESCE(a1.marks, r.value)
ELSE r.value
END
FROM reverse_polish r
LEFT OUTER JOIN a a1
ON SUBSTR(r.stack, 1, 1) = a1.subject
LEFT OUTER JOIN a a2
ON SUBSTR(r.stack, 2, 1) = a2.subject
)
SEARCH DEPTH FIRST BY subject, formula SET order_id
CYCLE subject, formula, stack SET done TO 1 DEFAULT 0
SELECT subject, value
FROM reverse_polish
WHERE done = 1
Which, for the sample data:
CREATE TABLE A (Subject, Marks) AS
SELECT 'A', 100 FROM DUAL UNION ALL
SELECT 'B', 200 FROM DUAL UNION ALL
SELECT 'C', 400 FROM DUAL UNION ALL
SELECT 'D', 500 FROM DUAL;
CREATE TABLE B (Subject, Formula) AS
SELECT 'A', 'A/B' FROM DUAL UNION ALL
SELECT 'B', 'B/D' FROM DUAL UNION ALL
SELECT 'C', 'D/A-B' FROM DUAL UNION ALL
SELECT 'D', 'A+B/C-D' FROM DUAL;
Outputs:
| SUBJECT | VALUE |
|---|---|
| A | .5 |
| B | .4 |
| C | -195 |
| D | -399.5 |
Some results you posted (C and D) are invalid; first you have to multiply/divide, then add/subtract. For your kind of results, you'll need to use brackets.
Anyway: dynamic SQL should be used. Here's one option:
table_atable_bOutput: