How calculate things from many tables by using a few queries?
-
27-04-2021 - |
题
note: this question is related to PostGIS and Postgresql and is implemented with PHP
Now I have Table A :
gid | kstart | kend | ctrl_sec_no | the_geom |
626 | 238 | 239 | 120802 | 123456 |
638 | 249 | 250 | 120802 | 234567 |
4037| 239 | 249 | 120802 | 345678 |
note: the_geom is a geometry value (TYPE: LINE), in this case i random them for readability
And Table B :
gid | ctrl_sec_no | x | the_geom
543 | 120802 | 239 | null
544 | 120802 | 247 | null
[PostGIS description] These two tables are related by ctrl_sec_no, which means 3 continuous LINEs on ctrl_sec_no 120802 from Table A, are connected into one LINE and contains two POINTs from Table B. We only know the distance {MAX(kend) - MIN(kstart)} of the LINE and the kilometer (x) where it is on the LINE.
The question is what is PostgreSQL's query to..
(a.) select the highest value from A.kend, minus with the lowest value from A.kstart -> 250 - 238 = 12
(b.) select the highest value from A.kend, minus with 'x' value in B -> 250 - 239 = 11
(c.) calculate ratio from these two value ((b.)/(a.)) -> 11/12
(d.) using PostGIS : ST_Interpolate -> ST_Interpolate(A.the_geom, 11/12) note: this function is used to find the POINT along with the LINE, in other hand to define a position where the POINT is
(e.) we will get a value from (d.) and use it to UPDATE Table B on 'the_geom' column, which is initially NULL.
(f.) loop this set of queries for every rows in Table B.
[PostGIS Description] The purpose of this set of queries is to determine the_geom in Table B by calculate some math and put the output into a ST_Interpolate function to get the_geom of where the POINT in Table B is.
Thanks in Advanced, I know this is quiet complicated question. I don't mind if you will use too many queries. Just to get the correct value.
These are the actual query (final) with the help from danihp.
with CTE( max_kend) as (
SELECT MAX(A.kend)
FROM centerline A
),
r_b as (
select B.ctrl_sec_no,B.gid, MAX(CTE.max_kend) - B.km as b
FROM land_inventory B cross join CTE group by B.gid,B.ctrl_sec_no,B.km
),
r_a as (
SELECT MAX(A.kend) - MIN(A.kstart) as a
FROM centerline A
),
r_ratio as (
select r_b.gid, r_b.b / r_a.a as my_ratio
from r_a cross join r_b
),
r_new_int as (
select B.gid,r_ratio.my_ratio,B.ctrl_sec_no,B.km,ST_AsText(ST_Envelope(ST_Collect(ST_line_interpolate_point(A.the_geom, r_ratio.my_ratio )))) as new_int from centerline A, land_inventory B inner join r_ratio on B.gid = r_ratio.gid where A.ctrl_sec_no = B.ctrl_sec_no group by B.ctrl_sec_no,B.gid,r_ratio.my_ratio,B.km order by B.ctrl_sec_no
)
UPDATE land_inventory
set land_inventory.the_geom = n.new_int
from r_new_int n
where
n.gid = land_inventory.gid and
land_inventory.the_geom is NULL;
解决方案
Ok, lets go.
(a)
SELECT MAX(A.kend) - MIN( A.kstart) as a
FROM Table A
(b)
EDITED Assuming that gid is PK for Table B ...
with CTE( max_kend, min_x) as (
SELECT MAX(A.kend), NULL
FROM TableA A
)
select B.gid, MAX(CTE.max_kend) - B.min_x as b
FROM TableB B
cross join CTE
(c)
with CTE( max_kend, min_x) as (
SELECT MAX(A.kend), NULL
FROM TableA A
),
r_b as (
select B.gid, MAX(CTE.max_kend) - B.min_x as b
FROM TableB B
cross join CTE
),
r_a as (
SELECT MAX(A.kend) - MIN( A.kstart) as a
FROM Table A
)
select r_b.gid, r_a.a / r_b.b as my_ratio
from r_a cross join r_b
(d)
with CTE( max_kend, min_x) as (
SELECT MAX(A.kend), NULL
FROM TableA A
),
r_b as (
select B.gid, MAX(CTE.max_kend) - B.min_x as b
FROM TableB B
cross join CTE
),
r_a as (
SELECT MAX(A.kend) - MIN( A.kstart) as a
FROM Table A
),
r_ratio as (
select r_b.gid, r_a.a / r_b.b as my_ratio
from r_a cross join r_b
)
select ST_Interpolate(A.the_geom, r_ratio.my_ratio )
from TableB B
inner join r_ratio on B.gid = r_ratio.gid
(e, f)
with CTE( max_kend, min_x) as (
SELECT MAX(A.kend), NULL
FROM TableA A
),
r_b as (
select B.gid, MAX(CTE.max_kend) - B.min_x as b
FROM TableB B
cross join CTE
),
r_a as (
SELECT MAX(A.kend) - MIN( A.kstart) as a
FROM Table A
),
r_ratio as (
select r_b.gid, r_a.a / r_b.b as my_ratio
from r_a cross join r_b
),
r_new_int as (
select ST_Interpolate(A.the_geom, r_ratio.my_ratio ) as new_int
from TableB B
inner join r_ratio on B.gid = r_ratio.gid
)
UPDATE tableB
set tableB.the_geom = n.new_int
from r_new_int n
where
n.gid = tableB.gid and
tableB.the_geom is NULL
disclaimer, not testet.
EDITED
with CTE( max_kend) as (
SELECT MAX(A.kend)
FROM centerline A
),
r_b as (
select B.ctrl_sec_no,B.gid, MAX(CTE.max_kend) - B.km as b
FROM land_inventory B cross join CTE group by B.gid,B.ctrl_sec_no,B.km
),
r_a as (
SELECT MAX(A.kend) - MIN(A.kstart) as a
FROM centerline A
),
r_ratio as (
select r_b.gid, r_b.b / r_a.a as my_ratio
from r_a cross join r_b
),
r_new_int as (
select
B.gid,
r_ratio.my_ratio,
B.ctrl_sec_no,B.km,
ST_AsText(ST_Envelope(ST_Collect(
ST_line_interpolate_point(A.the_geom, r_ratio.my_ratio
)))) as new_int
from
centerline A inner join
land_inventory B
on A.ctrl_sec_no = B.ctrl_sec_no
inner join
r_ratio on B.gid = r_ratio.gid
group by B.ctrl_sec_no,B.gid,r_ratio.my_ratio,B.km order by B.ctrl_sec_no
)
UPDATE land_inventory
set the_geom = n.new_int
from r_new_int n
where
n.gid = land_inventory.gid and
land_inventory.the_geom is NULL;