SQL Server Recursion query - recursive-query

Hi I have the following Node and Link tables. I need to build the line coordinates array using the Node table. However if the type of node is a vertex, I need to add the coordinates to the array and get the next coordinates (using FromID->ToID) until a non vertex is found, which is the end point of the line.
I have tried to follow a solution using recursive queries from previous posts, but this didn't work. Is Recursive queries or querying an XML (by joining the 2 tables) output the best way to achieve this? I am using SQL Server 2008
Node Table:
NODEID TYPE COORDS
BEND1 VALVE (439754,350240)
BEND3 VALVE (439720,350268)
COP1 HYDRANT (439879,350292)
EFJ1 FITTING (439740,350248)
NFH1 VALVE (439798,350262)
NFH2 VALVE (439802,350313)
NWO3 VALVE (439752,350244)
NSV1 VALVE (439877,350292)
NSV2 VALVE (439753,350245)
NSV3 VALVE (439752,350244)
TP1 HYDRANT (439752,350244)
TP2 HYDRANT (439864,350360)
VERTEX3 VERTEX (439805,350314)
VERTEX1 VERTEX (439730,350286)
VERTEX2 VERTEX (439769,350301)
PR4 VALVE (439824,350332)
VERTEX6 VERTEX (439853,350357)
LINK TABLE
FROMID TOID STATUS
BEND1 NWO3 OPER
BEND3 VERTEX1 OPER
COP1 NSV1 OPER
EFJ1 BEND3 OPER
NFH1 NSV1 OPER
NFH2 VERTEX3 OPER
TP1 NSV3 OPER
VERTEX1 VERTEX2 OPER
VERTEX2 NFH2 OPER
VERTEX3 PR4 OPER
EXPECTED OUTPUT
RECNUM FROMID TOID LINE_COORDS
1 BEND1 NWO3 (439754,350240),(439752,350244)
2 BEND3 NFH2 (439720,350268),(439730,350286),(439769,350301),(439802,350313)
3 COP1 NSV1 (439879,350292),(439877,350292)
4 EFJ1 BEND3 (439740,350248),(439720,350268)
5 NFH1 NSV1 (439798,350262),(439877,350292)
6 NFH2 PR4 (439802,350313),(439805,350314),(439824,350332)
7 TP1 NSV3 (439752,350244),(439752,350244)

You can try this but I have no SQL Server on the hand to test the query.
WITH PathCTE as
(
select
X1.FromID as FromID,
X1.ToID as ToID,
[Path] = cast(N1.Coords + ',' + N2.Coords as nvarchar(max)),
Stop = (case when N2.TYPE = 'VERTEX' THEN 0 ELSE 1 END)
from
tblLink X1 inner join tblNode N1 on X1.FromID = N1.NodeID
inner join tblNode N2 on X1.ToID = N2.NodeID
where
not exists (select 1 from tblLink X2 where X2.ToID = X1.FromID AND N1.TYPE = 'VERTEX')
union all
select
PathCTE.FromID,
X.ToID,
[Path] = PathCTE.[Path] + ',' + tblNode.Coords,
STOP = (case when tblNode.TYPE = 'VERTEX' THEN 0 ELSE 1 END)
from
PathCTE
inner join tblLink X on PathCTE.ToID = X.FromID
inner join tblNode on X.ToID = tblNode.NodeID
where PathCTE.Stop = 0
)
select RecNUM = row_number() over (order by FromID), FromID, ToID, Path as Line_Coords
from
PathCTE
where
PathCTE.Stop = 1
order by
FromID;

Related

q - apply function on table rowwise

Given a table and a function
t:([] c1:1 2 3; c2:`a`b`c; c3:13:00 13:01 13:02)
f:{[int;sym;date]
symf:{$[x=`a;1;x=`b;2;3]};
datef:{$[x=13:00;1;x=13:01;2;3]};
r:int + symf[sym] + datef[date];
r
};
I noticed that when applying the function f onto columns of t, then the entire columns are passed into f and if they can be operated on atomically then the output will be of the same length as the inputs and a new column is produced. However in our example this wont work:
update newcol:f[c1;c2;c3] from t / 'type error
because the inner functions symf and datef cannot be applied to the entire column c2, c3, respectively.
If I dont want to change the function f at all, how can I apply it row by row and collect the values into a new column in t.
What's the most q style way to do this?
EDIT
If not changing f is really inconvenient one could workaround like so
f:{[arglist]
int:arglist 0;
sym:arglist 1;
date:arglist 2;
symf:{$[x=`a;1;x=`b;2;3]};
datef:{$[x=13:00;1;x=13:01;2;3]};
r:int + symf[sym] + datef[date];
r
};
f each (t`c1),'(t`c2),'(t`c3)
Still I would be interested how to get the same result when working with the original version of f
Thanks!
You can use each-both for this e.g.
q)update newcol:f'[c1;c2;c3] from t
c1 c2 c3 newcol
------------------
1 a 13:00 3
2 b 13:01 6
3 c 13:02 9
However you will likely get better performance by modifying f to be "vectorised" e.g.
q)f2
{[int;sym;date]
symf:3^(`a`b!1 2)sym;
datef:3^(13:00 13:01!1 2)date;
r:int + symf + datef;
r
}
q)update newcol:f2[c1;c2;c3] from t
c1 c2 c3 newcol
------------------
1 a 13:00 3
2 b 13:01 6
3 c 13:02 9
q)\ts:1000 update newcol:f2[c1;c2;c3] from t
4 1664
q)\ts:1000 update newcol:f'[c1;c2;c3] from t
8 1680
In general in KDB, if you can avoid using any form of each and stick to vector operations, you'll get much more efficiency

remove duplicates in a table (rexx language)

I have a question about removing duplicates in a table (rexx language), I am on netphantom applications that are using the rexx language.
I need a sample on how to remove the duplicates in a table.
I do have a thoughts on how to do it though, like using two loops for these two tables which are A and B, but I am not familiar with this.
My situation is:
rc = PanlistInsertData('A',0,SAMPLE)
TABLE A (this table having duplicate data)
123
1
1234
12
123
1234
I need to filter out those duplicates data into TABLE B like this:
123
1234
1
12
You can use lookup stem variables to test if you have already found a value.
This should work (note I have not tested so there could be syntax errors)
no=0;
yes=1
lookup. = no /* initialize the stem to no, not strictly needed */
j=0
do i = 1 to in.0
v = in.i
if lookup.v <> yes then do
j = j + 1
out.j = v
lookup.v = yes
end
end
out.0 = j
You can eliminate the duplicates by :
If InStem first element, Move the element to OutStem Else check all the OutStem elements for the current InStem element
If element is found, Iterate to the next InStem element Else add InStem element to OutStem
Code Snippet :
/*Input Stem - InStem.
Output Stem - OutStem.
Array Counters - I, J, K */
J = 1
DO I = 1 TO InStem.0
IF I = 1 THEN
OutStem.I = InStem.I
ELSE
DO K = 1 TO J
IF (InStem.I ?= OutStem.K) & (K = J) THEN
DO
J = J + 1
OutStem.J = InStem.I
END
ELSE
DO
IF (InStem.I == OutStem.K) THEN
ITERATE I
END
END
END
OutStem.0 = J
Hope this helps.

PostGIS: intersections of set of collinear line segments, with counts

I have a set of collinear line segments (may be mutually disjoint, contained, or overlapping).
I want to make a new set of line segments where the segments are disjoint or touching (not overlapping), and each line segment has a count of the original line segments that cover it.
For example, suppose the original set is (drawn non-collinearly for illustration):
A----------------------B
C---------------------------D
E-----F
G-------------H
I-------J
the desired new set would be:
A-------C---E-----F-----B-----------D G-------------H-------J
1 2 3 2 1 1 1
(only the point coordinates matter, the new set does not share point objects with the old set)
How can I achieve this with PostGIS?
Related question: suppose I start with a table of line segments, not all collinear, how do I write the entire query that groups the collinear segments together and then applies the solution to my first question?
Thanks for any help!
Setup (for later queries):
create table lines (
id serial primary key,
label text not null,
line_data geometry(linestring) not null
);
insert into lines(label, line_data)
values ('A-B', ST_MakeLine(ST_MakePoint(-3, -6), ST_MakePoint( 1, 2))),
('D-C', ST_MakeLine(ST_MakePoint( 2, 4), ST_MakePoint(-2, -4))),
('E-F', ST_MakeLine(ST_MakePoint(-1, -2), ST_MakePoint( 0, 0))),
('G-H', ST_MakeLine(ST_MakePoint( 3, 6), ST_MakePoint( 4, 8))),
('I-J', ST_MakeLine(ST_MakePoint( 4, 8), ST_MakePoint( 5, 10))),
('P-L', ST_MakeLine(ST_MakePoint( 1, 0), ST_MakePoint( 2, 2))),
('X-Y', ST_MakeLine(ST_MakePoint( 2, 2), ST_MakePoint( 0, 4)));
Notes:
I purposely switched your D and C points to demonstrate a need for vector negation
The P-L line is parallel with your example lines (but not collinear)
The X-Y line has nothing to do with the others
the solutions below obviously won't work, when you have linestrings that have more than 2 points and those are not on the same line (so when a single linestring is not straight).
The ST_Union aggregate function can split your collinear linestrings. You'll just need to calculate how many lines are containing those.
However, grouping by collinearity is not that simple. I did not find any out-of-the-box solution for this, but you can calculate it (this will not calculate counts yet):
select string_agg(label, ','), ST_AsText(ST_Multi(ST_Union(line_data)))
from lines
group by (
select case
when ST_SRID(s) <> ST_SRID(e) then row(ST_SRID(s), s, null)
when ST_X(s) = ST_X(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(ST_X(s), 1.0), ST_SRID(s)), null)
when ST_Y(s) = ST_Y(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(1.0, ST_Y(e)), ST_SRID(s)), null)
else (
select row(
ST_SRID(s),
(select case
when ST_Y(rv) < 0
then ST_SetSRID(ST_MakePoint(-ST_X(rv), -ST_Y(rv)), ST_SRID(s))
else rv
end), -- normalized vector (negated when necessary, but same for all parallel lines)
(ST_X(e) * ST_Y(s) - ST_X(s) * ST_Y(e)) / (ST_X(e) - ST_X(s)) -- solution of the linear equaltion, where x=0
)
from coalesce(1.0 / nullif(ST_Distance(s, e), 0), 0) dmi, -- distance's multiplicative inverse
ST_TransScale(e, -ST_X(s), -ST_Y(s), dmi, dmi) rv -- raw vector (translated and scaled)
)
end
from ST_StartPoint(line_data) s,
ST_EndPoint(line_data) e
)
will produce:
X-Y | MULTILINESTRING((2 2,0 4))
P-L | MULTILINESTRING((1 0,2 2))
E-F,A-B,I-J,G-H,D-C | MULTILINESTRING((-3 -6,-2 -4),(-2 -4,-1 -2),(-1 -2,0 0),(0 0,1 2),(2 4,1 2),(3 6,4 8),(4 8,5 10))
To calculate counts, JOIN your original data again, where the splitted lines are contained by (ST_Contains) your original lines:
select ST_AsText(splitted_line), count(line_data)
from (select ST_Multi(ST_Union(line_data)) ml
from lines
group by (
select case
when ST_SRID(s) <> ST_SRID(e) then row(ST_SRID(s), s, null)
when ST_X(s) = ST_X(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(ST_X(s), 1.0), ST_SRID(s)), null)
when ST_Y(s) = ST_Y(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(1.0, ST_Y(e)), ST_SRID(s)), null)
else (
select row(
ST_SRID(s),
(select case
when ST_Y(rv) < 0
then ST_SetSRID(ST_MakePoint(-ST_X(rv), -ST_Y(rv)), ST_SRID(s))
else rv
end), -- normalized vector (negated when necessary, but same for all parallel lines)
(ST_X(e) * ST_Y(s) - ST_X(s) * ST_Y(e)) / (ST_X(e) - ST_X(s)) -- solution of the linear equaltion, where x=0
)
from coalesce(1.0 / nullif(ST_Distance(s, e), 0), 0) dmi, -- distance's multiplicative inverse
ST_TransScale(e, -ST_X(s), -ST_Y(s), dmi, dmi) rv -- raw vector (translated and scaled)
)
end
from ST_StartPoint(line_data) s,
ST_EndPoint(line_data) e)) al,
generate_series(1, ST_NumGeometries(ml)) i,
ST_GeometryN(ml, i) splitted_line
left join lines on ST_Contains(line_data, splitted_line)
group by splitted_line
will return:
LINESTRING(-3 -6,-2 -4) | 1
LINESTRING(-2 -4,-1 -2) | 2
LINESTRING(-1 -2,0 0) | 3
LINESTRING(0 0,1 2) | 2
LINESTRING(2 2,0 4) | 1
LINESTRING(1 0,2 2) | 1
LINESTRING(2 4,1 2) | 1
LINESTRING(3 6,4 8) | 1
LINESTRING(4 8,5 10) | 1

Orientdb get last vertex from each path when Traversing by edge property

I need to traverse all vertices that are connected by edges where the property 'dependence' is 'true'
This is what I have so far:
SELECT
FROM (TRAVERSE *
FROM (SELECT outE() FROM 9:5)
WHILE (#class = 'E' AND dependence = 'yes') OR #class = 'V')
WHERE #class = 'V'
Although im not sure if is the best way to do it, this seems to work fine following only the paths where edges have 'dependence' = 'yes'.
Now, There could be more than one path generated, and I need to get the last vertex from each path/branch.
traverserdVertex(-1) should return the last one, but im guessing that is from the whole traversal so is no good. (and it looks like there's a bug because it retrieves more than one)
The outer SELECT returns the whole bag of vertices so I'm thinking that maybe finding the ones that doesn't have an outgoing edge with dependence='yes' might solve it, although I'm not sure how to do it nicely.
SOLUTION:
SELECT
FROM (TRAVERSE *
FROM (SELECT outE() FROM 9:5)
WHILE (#class = 'E' AND dependence = 'yes') OR #class = 'V')
WHERE #class = 'V' AND NOT (outE() contains (dependence='yes'))
This effectively returns the last vertex from each branch. I'm open to any other option, I'm wondering if it could be improved.
I tried with an example by building the following graph
The javascript function "myFunction" has three parameters which are ridVertex, property and value
var g=orient.getGraph();
var previous=[];
var currently=[];
var node=[];
var b=g.command("sql","select from v where #rid =" + ridVertex);
if(b.length>0){
previous.push(b[0]);
node.push(b[0]);
do{
for(i=0;i<previous.length;i++){
var edges=g.command("sql","select expand(outE()) from V where #rid = "+ previous[i].getId());
var myVertex=[];
for(j=0;j<edges.length;j++){
var edge=edges[j];
var dependence=edge.getProperty(property);
if(dependence==value){
var vIn=edge.getProperty("in");
myVertex.push(vIn);
}
}
if(myVertex.length>0){
setPaths();
}
}
change();
}while(previous.length>0);
}
return node;
function setPaths(){
for (m = 0; m < node.length; m++) {
var lastId=node[m].getId().toString();
var idOut=previous[i].getId().toString();
if (lastId==idOut) {
for(r=0;r<myVertex.length;r++){
var vertex=myVertex[r];
node.push(vertex);
currently.push(vertex);
}
node.splice(m,1);
break;
}
}
}
function change(){
previous=[];
for (indice=0;indice<currently.length;indice++)
previous.push(currently[indice]);
currently=[];
}
Using the following command
select expand(result) from (select myFunction("#9:0","dependence","yes") as result)
the paths are A -> D and A -> B -> C -> G and then will be returned the verteces D and G
The following is a slight simplification of #sebastian's solution, using Allesandro's graph (with dependentOn.value being 0 or 1):
select from
(TRAVERSE * FROM (select from Circle where name="A")
while (#CLASS="dependentOn" and value=1) OR #CLASS="Circle")
where #CLASS='Circle' AND NOT (outE().value contains 1)
----+-----+------+----+--------------
# |#RID |#CLASS|name|in_dependentOn
----+-----+------+----+--------------
0 |#11:6|Circle|G |[#12:4]
1 |#11:3|Circle|D |[#12:1]

How to print the value of a variable after every round in matlab?

I have 100 nodes using following for loop:
xm1=100; %diameters of sensor network
ym1=100;
sink1.x=50; %distance of base station from the network
sink1.y=120;
nl = 100; %no of nodes
pl=0.1; %probibilty of a node to become cluster head
El1= 0;
Eint=0.5; %energy supplied to each node
Etl =0 ;
for i=1:1:nl
Sl(i).xd=rand(1,1)*xm1; %it will distribute the nodes in 1 dimension in x axis randomly.
XR(i)=Sl(i).xd; %we store its value in xr
Sl(i).yd=rand(1,1)*ym1; %it will distribute the nodes in 1 dimension in y axis randomly
YR(i)=Sl(i).yd;
Sl(i).id = i;
Sl(i).G=0; % as the no of node that have been cluster head is zero 0
Sl(i).E=Eint; %%*(1+rand*a);
%fprintf(' Sensor node energy: %15f \n',Eint); %?
%initially there are no cluster heads only nodes
Sl(i).type='N';
end
cluster formation took place like tis
for r=1:1:rmax
for i=1:1:nl
if(Sl(i).E>0)
temp_randl=rand;
if ( (Sl(i).G)<=0)
if(temp_randl<= (pl/(1-pl*mod(r,round(1/pl)))))
countCHsl=countCHsl+1;
packets_TO_BSl=packets_TO_BSl+1;
PACKETS_TO_BSl(r+1)=packets_TO_BSl;
Sl(i).type='C';
Sl(i).G=round(1/pl)-1;
Cl(clusterl).xd=Sl(i).xd;
Cl(clusterl).yd=Sl(i).yd;
distancel=sqrt( (Sl(i).xd-(Sl(n+1).xd) )^2 + (Sl(i).yd-(Sl(n+1).yd) )^2 );
Cl(clusterl).distance=distancel;
Cl(clusterl).id=i;
X(clusterl)=Sl(i).xd;
Y(clusterl)=Sl(i).yd;
clusterl=clusterl+1;
distancel;
if (distancel>do)
Sl(i).E=Sl(i).E- ( (ETX+EDA)*(4000) + Emp*4000*(distancel*distancel*distancel*distancel ));
end
if (distancel<=do)
Sl(i).E=Sl(i).E- ( (ETX+EDA)*(4000) + Efs*4000*(distancel * distancel ));
end
end
end
% S(i).G=S(i).G-1;
end
end
STATISTICS.COUNTCHS(r+1)=countCHsl;
for i=1:1:nl
if ( Sl(i).type=='N' && Sl(i).E>0 )
if(clusterl-1>=1)
min_disl=Inf;
min_dis_clusterl=0;
for cl=1:1:clusterl-1
templ=min(min_disl,sqrt( (Sl(i).xd-Cl(cl).xd)^2 + (Sl(i).yd-Cl(cl).yd)^2 ) );
if ( templ<min_disl )
min_disl=templ;
min_dis_clusterl=cl;
end
end
min_disl;
if (min_disl>do)
Sl(i).E=Sl(i).E- ( ETX*(4000) + Emp*4000*( min_disl *min_disl * min_disl * min_disl));
end
if (min_disl<=do)
Sl(i).E=Sl(i).E- ( ETX*(4000) + Efs*4000*( min_disl * min_disl));
end
Sl(Cl(min_dis_clusterl).id).E =Sl(Cl(min_dis_clusterl).id).E- ( (ERX + EDA)*4000 );
packets_TO_CHl=packets_TO_CHl+1;
Sl(i).min_disl=min_disl;
Sl(i).min_dis_clusterl=min_dis_clusterl;
else
min_disl=sqrt( (Sl(i).xd-Sl(n+1).xd)^2 + (Sl(i).yd-Sl(n+1).yd)^2 );
if (min_disl>do)
Sl(i).E=Sl(i).E- ( ETX*(4000) + Emp*4000*( min_dis1 *min_dis1 * min_dis1 * min_dis1));
end
if (min_disl<=do)
Sl(i).E=Sl(i).E- ( ETX*(4000) + Efs*4000*( min_disl * min_disl));
end
packets_TO_BSl=packets_TO_BSl+1;
end
end
end
end
Now I have to print value of S1(i).E for all i after every round?
Means I have to print remaining energy of all nodes at every round.
Thanks in advance.
And the exact answer of this question is
fprintf('%0.2f \n',Sl(:).E);
I assume r stands for round, so you could add any of the following lines right before your last end to print the remaining energy:
sprintf('%0.2f \n',Sl(:).E);
disp([Sl(:).E]');
Sl(:).E
a simple
S1(i).E,
should work.