Function/ Macro to get a value - function

Let say I have a table with 3 variable: var1, var2, var3 and another table of reference.
Now I want to create anothe variable: var4; var4 is computed from var1, var2 and var3 and the reference table.
I could create a macro to do that (for each line), but I dont know how to pass the value from the macro (a table) into a result. I wonder how can we do it by creating a function to get a value, not a macro?
I understand that if I can create a function like that (this function will include data step and proc summary), thing will be easy like:
var4 = myfunction(var1, var2, var3).
Update:
The table reference in my case is:
age range1 range2 range3
1 10 1 8
2 0 4 1
3 4 6 1
4 6 5 2
5 10 5 6
So I want my function to get like:
var4 = myfunction(var1, var2, var3), for example var1 = 2, var2 = 2, var3 = 5:
Take the sum of range2 (correspond to var1 = 2); from line 2 to line 5 (corrspond to var2= 2 and var3 = 5) and the result will be: 4 + 6 + 5 + 5.
Thanks in advance.

One solution could be to first modify the reference table to a long format with one row per age per range number, and with the accumulated range in a new variable. The sum from var2 to var3 then becomes the difference between two accumulated values, which is easier to compute in a double join:
* Define input data with parameters;
data have;
input var1 var2 var3;
datalines;
1 1 3
2 2 5
3 1 4
;
run;
* Define reference table;
data ref_table;
input age range1 range2 range3;
datalines;
1 10 1 8
2 0 4 1
3 4 6 1
4 6 5 2
5 10 5 6
;
run;
* Modify reference table to long format with accumulated ranges;
data mod_ref_table;
set ref_table;
* Calculated accumulated values of each range;
acc_range1 + range1;
acc_range2 + range2;
acc_range3 + range3;
* Output the accumulated values for each range;
range_no = 1;
acc_range = acc_range1;
output;
range_no = 2;
acc_range = acc_range2;
output;
range_no = 3;
acc_range = acc_range3;
output;
keep age range_no acc_range;
run;
* Calculate output;
proc sql;
create table want as
select a.*
,case
when a.var2 = 1 then c.acc_range
else c.acc_range - b.acc_range
end as val4
from have as a
left join mod_ref_table as b
on a.var1 = b.range_no and a.var2-1 = b.age
left join mod_ref_table as c
on a.var1 = c.range_no and a.var3 = c.age
;
quit;

Macro returning a value
OK the solution can be found here.
Anyway thanks for your support.

Related

How to create a table column from a vector of data in MySQL?

New to SQL here.
I have experience using R to create tables/data frames from vectors of data. Here is an example of some basic R code that accomplishes what I'm trying to do in MySQL.
df = data.frame(var1 = c(1,2,3), var2 = c('a','b','c'))
produces
var1 var2
1 1 a
2 2 b
3 3 c
I want to know how to do this in MySQL.
For example, I could write:
create table dummytable select 1 as var1, a as var2;
And I'd get a one-row table with 1 in column 1 and b in column 2.
But how would I replace 1 and a above with vectors of data, so that the table I'm creating has multiple rows?
Clearly this won't work, but what I'm looking for is something like:
create table dummytable select c(1,2,3) as var1, c('a','b','c') as var2;
What basic function am I missing to create and use vectors?
I don't have MySQL handy, but this is tested in SQL Server, PostgreSQL, and SQLite.
conn <- DBI::dbConnect(...)
DBI::dbExecute(conn, "create table dummytable (var1 int, var2 nchar(3))")
# [1] 0
DBI::dbExecute(conn, "insert into dummytable (var1, var2) values (1,'a'), (2,'b'), (3,'c')")
# [1] 3
DBI::dbGetQuery(conn, "select * from dummytable")
# var1 var2
# 1 1 a
# 2 2 b
# 3 3 c
mydat <- data.frame(var1 = 4:5, var2 = c("d", "e"), stringsAsFactors = FALSE)
DBI::dbWriteTable(conn, "dummytable", mydat, append = TRUE)
DBI::dbGetQuery(conn, "select * from dummytable")
# var1 var2
# 1 1 a
# 2 2 b
# 3 3 c
# 4 4 d
# 5 5 e
# equivalent to dbWriteTable:
DBI::dbAppendTable(conn, "dummytable", mydat)

round to the nearest even number with array of numbers

My function and rounding to nearest even number
function y = rndeven(x)
if x<=1
y=2;
else
y = 2*floor(x);
end
endfunction
When I run it I get:
cc=[0:3]'
both=[cc,rndeven(cc)]
0 0
1 2
2 4
3 6
What I'm trying to get as the Result:
0 2
1 2
2 2
3 4
You can use the modulo 2 to find whether a number is even. If it isn't this will return 1, so just add 1 to this number to find the nearest (larger) even number:
function y = rndeven(x)
x = floor(x);
x(x <= 1) = 2;
y = mod(x,2)+x;
end
This works for any array, order of elements does not matter.
You could also check if it is dividable by 2 if you don't want to use the mod function. The pseudo code would be something like this:
while(x % 2 != 0) x = x + 1
return x

How to get number of steps to get a sub of tree

How can I do to get number of steps to get a sub of tree .
for example I have a table like this:
id title parent_id
1 A 0
2 B 0
3 C 1
4 F 3
5 O 3
6 D 2
7 J 6
8 T 2
9 P 8
A // 1 step
C //2 step
F //3 step
O //3 step
B //1 step
D //2 step
J //3 step
T //2 step
P //3 step
for example if I give a number like 1 (id = 1 ), it should return 1 and id=6 it should return 2 as step.
my DBMS is MySQL.
It can be a recursive stored procedure, if your tree is not very deep. Something like this (with addition of proper condition handlers), or anything of the same kind, it can be written in various ways:
DELIMITER $
CREATE PROCEDURE depth(IN n INT, OUT depth INT)
BEGIN
DECLARE parent INT DEFAULT 0;
SET max_sp_recursion_depth=255;
SELECT parent_id INTO parent FROM t WHERE id=n;
IF parent = 0 THEN SET depth = 1;
ELSE CALL depth(parent,depth); SET depth = depth + 1;
END IF;
END $
DELIMITER ;
CALL(6,#depth);
SELECT #depth;
Also, MariaDB 10.2 supports recursive CTE. It's an early beta now, so it's not good for production, but if you're only evaluating your options, you can try it out. This should work:
WITH RECURSIVE tree(id,parent_id,depth) AS
(
SELECT id, parent_id, 1 from t WHERE parent_id=0
UNION ALL
SELECT t.id, t.parent_id, depth+1 FROM t JOIN tree ON tree.id = t.parent_id
) SELECT * FROM tree WHERE id = 6;

Why exactly does this function return a value to some power? (python 2.7)

def power(num, x = 1):
result = 1
for i in range(x):
result = result * num
return result
So I came across a tutorial on calling functions with 2 arguments and this one in the picture was used as an example to show how you could make a function called power(num, x=1) that takes an interval in the first argument and raises it to the power of the second argument. Can someone explain in laymen's terms why this happens and what exactly is going on in this function and 'for' loop?
First, range(x) is equivalent to range(0, x), and generates a sequence that ranges from 0 to x - 1. For example, with range(3) you get the sequence 0, 1, and 2, which has three elements. In general, range(x) generates a sequence that has x elements.
Second, for i in range(x) makes i iterates throught all the elements of range(x). Since range(x) has x elements, i will iterate through x different values, so the statements in the for loop will be executed x times.
With the above analysis, the body of the power function is equivalent to the following:
result = 1
result = result * num
result = result * num
// repeat x times
result = result * num
which is equivalent to:
result = 1 * num * num * ... * num // x nums here
which, apparently, is num raised to the power of x.
Update
Here's how this function works with specific input data. When num is 3 and x is 4, we have:
result = 1
result = result * num // = 1 * 3 = 3
result = result * num // = 3 * 3 = 9
reuslt = result * num // = 9 * 3 = 27
result = result * num // = 27 * 3 = 81 = 3^4
return result // 81 is returned
We can also show the execution process in more details:
result = 1
i = 0 // entering the loop
result = result * num // = 1 * 3 = 3
i = 1 // the second round of the loop begins
result = result * num // = 3 * 3 = 9
i = 2 // the third round of the loop begins
reuslt = result * num // = 9 * 3 = 27
i = 3 // the fourth and final round of the loop begins
result = result * num // = 27 * 3 = 81 = 3^4
// range(4) is exhausted, so the loop ends here
return result // 81 is returned

Trying to find index of minimum value in a matrix fails in Octave

So I have this matrix:
E1 = [54 5 2 4;4 5 19 29;31 4 2 9; 1 3 99 34]
lets say I want to find the location of the value closest to 18.9. let A = 18.9
I would do
[r,c] = find(E1==min(min(abs(E1-A))))
This doesn't work. It returns r = "[](0x1)" and c = "[](0x1)"
however,
if I first do:
F = abs(E1-A) and then do
[r,c] = find(F==min(min(F)))
this gives r = 2 and c = 3 which is correct. 19 is the closest value and 19 lives in row 2 column 3.
Why doesnt this work then? F is simply abs(E1-A) so why can I not put abs(E1-A) in place of F in the find formula?
min(min(abs(E1-A)))
ans = 0.10000
This gives you the min over the absolute difference. Then you compare it to E1 which has absolute values. This is complete different from your second formular
[r,c] = find(F==min(min(F)))
where you comapre the minimum difference with the matrix containing the absolute of differences between E1 and A. If you replace in your second formula F with abs(E1-A) you would get
[r,c] = find(abs(E1-A)==min(min(abs(E1-A))))
Which would also work. Nevertheless I would suggest another approach:
E1 = [54 5 2 4;4 5 19 29;31 4 2 9; 1 3 99 34];
A = 18.9;
# get the index ( Column-major order) of the minimum
idx = nthargout (2, #min, abs (E1-A)(:));
# this returns 10
# convert it ro row, column
[r, c] = ind2sub (size (E1), idx)
r = 2
c = 3