Hi Tom,
Just to prove that Oracle SQL is powerful enough for solving mathematical problems OR for curiosity, can you share us the query to generate the matrix multiplication result. I think that it can be achieved using ONLY MODEL clause?.
Is it possible to write using analytical functions Lag and Lead functions?
__ __ __ __
| 6 7 -4| | 5 -1 6 -3|
M1= | 0 4 1| M2= | 0 4 1 7|
| 2 -2 3| | 8 2 9 3|
|_ _| |_ _|
M1 x M2 =
__ __
| 6×5 + 7×0 + -4×8 6×-1 + 7×4 + -4×2 6×6 + 7×1 + -4×9 6×-3 + 7×7 + -4×3 |
| 0×5 + 4×0 + 1×8 0×-1 + 4×4 + 1×2 0×6 + 4×1 + 1×9 0×-3 + 4×7 + 1×3 |
| 2×5 + -2×0 + 3×8 2×-1 + -2×4 + 3×2 2×6 + -2×1 + 3×9 2×-3 + -2×7 + 3×3 |
|__ __|
Result =
__ __
|-2 14 7 19|
|8 18 13 31|
|34 -4 37 -11|
|__ __|
CREATE TABLE m1 (c1 number, c2 number, c3 number)
/
CREATE TABLE m2 (col1 number, col2 number, col3 number,col4 number)
/
INSERT INTO m1 VALUES (6,7,-4)
/
INSERT INTO m1 VALUES (0,4,1)
/
INSERT INTO m1 VALUES (2,-2,3)
/
COMMIT;
SELECT * FROM m1
/
INSERT INTO m2 VALUES (5,-1,6,-3)
/
INSERT INTO m2 VALUES (0,4,1,7)
/
INSERT INTO m2 VALUES (8,2,9,3)
/
COMMIT;
SELECT * FROM m2
/
Thanks,
Boralli
I had to change your tables a bit - as everyone knows, the order of insertion into a table does not predict the order of retrieval. So, we need to add a row number in there - some sort of monotonically increasing value - to retrieve the matrix in the right order.
ops$tkyte%ORA11GR2> CREATE TABLE m1 (rn number, c1 number, c2 number, c3 number)
2 /
Table created.
ops$tkyte%ORA11GR2> CREATE TABLE m2 (rn number, col1 number, col2 number, col3 number,col4 number)
2 /
Table created.
ops$tkyte%ORA11GR2> INSERT INTO m1 VALUES (1, 6,7,-4)
2 /
1 row created.
ops$tkyte%ORA11GR2> INSERT INTO m1 VALUES (2, 0,4,1)
2 /
1 row created.
ops$tkyte%ORA11GR2> INSERT INTO m1 VALUES (3, 2,-2,3)
2 /
1 row created.
ops$tkyte%ORA11GR2> COMMIT;
Commit complete.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> SELECT * FROM m1
2 /
RN C1 C2 C3
---------- ---------- ---------- ----------
1 6 7 -4
2 0 4 1
3 2 -2 3
ops$tkyte%ORA11GR2> INSERT INTO m2 VALUES (1, 5,-1,6,-3)
2 /
1 row created.
ops$tkyte%ORA11GR2> INSERT INTO m2 VALUES (2, 0,4,1,7)
2 /
1 row created.
ops$tkyte%ORA11GR2> INSERT INTO m2 VALUES (3, 8,2,9,3)
2 /
1 row created.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> COMMIT;
Commit complete.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> SELECT * FROM m2
2 /
RN COL1 COL2 COL3 COL4
---------- ---------- ---------- ---------- ----------
1 5 -1 6 -3
2 0 4 1 7
3 8 2 9 3
Now, what we need to do is transpose matrix M2 to make it set friendly. We want to join the first row in M1 with the first column in M2 and the 2nd column in M2 and so on. Same with row 2 in m1. So, it we turn M2 on it's side we can just cartesian join to get all of our points:
ops$tkyte%ORA11GR2> with d1
2 as
3 ( select rn, cname, val
4 from m2
5 unpivot ( val for cname in (COL1, COL2, COL3, COL4) )
6 )
7 select * from d1;
RN CNAM VAL
---------- ---- ----------
1 COL1 5
1 COL2 -1
1 COL3 6
1 COL4 -3
2 COL1 0
2 COL2 4
2 COL3 1
2 COL4 7
3 COL1 8
3 COL2 2
3 COL3 9
3 COL4 3
12 rows selected.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> with d1
2 as
3 ( select rn, cname, val
4 from m2
5 unpivot ( val for cname in (COL1, COL2, COL3, COL4) )
6 ),
7 d2 as
8 (
9 select cname, x1, x2, x3
10 from d1
11 pivot (max(val) for rn in ( 1 as x1, 2 as x2, 3 as x3 ))
12 )
13 select * from d2;
CNAM X1 X2 X3
---- ---------- ---------- ----------
COL1 5 0 8
COL2 -1 4 2
COL3 6 1 9
COL4 -3 7 3
a combination pivot/unpivot transposed our result set - so we have two sets each with three columns (easy to multiply now)....
ops$tkyte%ORA11GR2> with d1
2 as
3 ( select rn, cname, val
4 from m2
5 unpivot ( val for cname in (COL1, COL2, COL3, COL4) )
6 ),
7 d2 as
8 (
9 select cname, x1, x2, x3
10 from d1
11 pivot (max(val) for rn in ( 1 as x1, 2 as x2, 3 as x3 ))
12 ),
13 d3 as
14 (
15 select c1*x1+c2*x2+c3*x3 val, rn, cname
16 from m1, d2
17 )
18 select * from d3;
VAL RN CNAM
---------- ---------- ----
-2 1 COL1
8 2 COL1
34 3 COL1
14 1 COL2
18 2 COL2
-4 3 COL2
7 1 COL3
13 2 COL3
37 3 COL3
19 1 COL4
31 2 COL4
-11 3 COL4
12 rows selected.
and all we have to do is turn the CNAME column into columns - pivoting again:
ops$tkyte%ORA11GR2> with d1
2 as
3 ( select rn, cname, val
4 from m2
5 unpivot ( val for cname in (COL1, COL2, COL3, COL4) )
6 ),
7 d2 as
8 (
9 select cname, x1, x2, x3
10 from d1
11 pivot (max(val) for rn in ( 1 as x1, 2 as x2, 3 as x3 ))
12 ),
13 d3 as
14 (
15 select c1*x1+c2*x2+c3*x3 val, rn, cname
16 from m1, d2
17 )
18 select column1, column2, column3, column4
19 from d3
20 pivot (max(val) for cname in ( 'COL1' as column1, 'COL2' as column2, 'COL3' as column3, 'COL4' as column4 ))
21 order by rn
22 /
COLUMN1 COLUMN2 COLUMN3 COLUMN4
---------- ---------- ---------- ----------
-2 14 7 19
8 18 13 31
34 -4 37 -11
qed :)
I am looking forward to seeing all of the other techniques others come up with :)