Oracle Spatial Index on a View of multiple tables - oracle

I have three big tables with same structure (BATHY_SHC_1, BATHY_SHC_2 and BATHY_SHC_3), each with a SDO_GEOMETRY column “POINT_PP”, the spatial index of each is VALID.
I have made a view on these tables that includes this geometry column (V_BATHY_SHC).
I can make spatial request on the view to find all point within a rectangle like this with correct results:
SELECT PT_ID, POINT_PP from V_BATHY_SHC
WHERE SDO_RELATE(POINT_PP, MDSYS.SDO_GEOMETRY(2003, 32618, null, MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,3),MDSYS.SDO_ORDINATE_ARRAY(635267,5037808, 635277,5037818)), 'mask=anyinteract') = 'TRUE';
I have upload a polygon MASK in a table MNE_MASK, added a line in metadata and created a spatial index (as usual). It has a valid spatial index. The geometry is in the same SRID (32618).
Then I want to get all points from the view that are within the polygon from the MNE_MASK table. If I made the query on one of the table, I get correct results:
SELECT A.PT_ID, A.POINT_PP
FROM BATHY_SHC_1 A, MNE_MASK B
WHERE B.MNE_ID = 1
AND SDO_RELATE(A.POINT_PP, B.MASK, 'mask=ANYINTERACT ') = 'TRUE';
But if I made it on the view like this:
SELECT A.PT_ID, A.POINT_PP
FROM V_BATHY_SHC A, MNE_MASK B
WHERE B.MNE_ID = 1
AND SDO_RELATE(A.POINT_PP, B.MASK, 'mask=ANYINTERACT ') = 'TRUE';
I got this error:
ORA-13226: interface not supported without a spatial index
ORA-06512: at "MDSYS.MD", line 1723
ORA-06512: at "MDSYS.MDERR", line 8
ORA-06512: at "MDSYS.SDO_3GL", line 94
In the past, I’ve always made queries on spatial index of views of multiple tables without problem.
I can make spatial query on both without issue but I can’t make a SDO_RELATE between them…
Why is this one any different?
Thanks a lot for your insight and help!
Edit:
I've found a quick workaround but it doesn't explain why.
If I swap the two first params in the SDO_RELATE function, the request works.
SELECT A.PT_ID, A.POINT_PP
FROM V_BATHY_SHC A, MNE_MASK B
WHERE B.MNE_ID = 1
AND SDO_RELATE(B.MASK, A.POINT_PP, 'mask=ANYINTERACT ') = 'TRUE';

In SDO_RELATE, the first parameter is a geometry column in a table, whereas the second is a single geometry. This said, I wonder why your original query works. There you have the view column as the first parameter, just like in the failing query.

Related

sdo_relate giving a wrong query result

I have two geometry in two feature class ,one named "HY90299 " and the other named "hyboxsdo " ,the two geometry do not intersect .
but when i run a spatial query in oralce ,
"select sdo_relate(t.shape,g.shape ,'mask=ANYINTERACT') from HY90299 t,hyboxsdo g " ,
it return "true", the result is not correct .am I doing something wrong?
my oracle version is 11g
you can get the two geometry by
1.i put the two geometry into two shape file . you can get them from here
https://pan.baidu.com/s/1YQnwe8nstzgHOAwHgx9JGQ
2.or create the two geometry by wkt
①MULTIPOLYGON (((-16.657423019000021 82.843477248999989, 16.710901260000014 66.242341995000004, 74.611375808999981 57.038061142000004, 111.18630027799998 67.126588820999984, -16.657423019000021 82.843477248999989)))
②MULTIPOLYGON (((60.839999999999975 26.569999999999993, 143.45000000000005 26.569999999999993, 143.45000000000005 55.75, 60.839999999999975 55.75, 60.839999999999975 26.569999999999993)))
Append
1.select * from user_sdo_geom_metadata where table_name='HY90299'
=============================
return "HY90299 SHAPE {{null,-180,180,0.001},{null,-90,90,0.001}} 4326"
2.select sdo_geom.validate_geometry_with_context(c.shape,0.000000005) from hy90299 c
select sdo_geom.validate_geometry_with_context(c.shape,0.001) from hy90299 c
=============================
all return "true"
3.select shape from hy90299
=============================
return "{2003,4326,null,{1,1003,1},{111.186300278,67.126588821,-16.657423019,82.843477249,16.71090126,66.242341995,74.611375809,57.038061142,111.186300278,67.126588821}}"
4.select sdo_geom.relate(t.shape,'determine',sdo_geometry(2003,4326,null, SDO_ELEM_INFO_ARRAY(1,1003,3),SDO_ORDINATE_ARRAY(60.840,26.570,143.450,55.750)),0.000000005) as spat_rel from HY90299 t
=============================
return "DISJOINT"
5.select sdo_geom.relate(t.shape,'determine',sdo_geometry(2003,4326,null, SDO_ELEM_INFO_ARRAY(1,1003,1),SDO_ORDINATE_ARRAY(60.840,26.570, 143.450,26.570, 143.450,55.750,60.840,55.750,60.840, 26.570)),0.000000005) as spat_rel from HY90299 t
=============================
return "OVERLAPBDYINTERSECT"
From the manual (https://docs.oracle.com/cd/B28359_01/appdev.111/b28400/sdo_operat.htm#SPATL1039), spatial operators "must always be used in a WHERE clause", not in the SELECT part of the query.
To use them (in the WHERE clause, as mentioned), they must be spatially indexed.
If you want to see the spatial relation, you can use one of the spatial functions - e.g:
select t.*,g.*, sdo_geom.relate(t.shape,'determine',g.shape,0.000000005) as spat_rel
from HY90299 t, hyboxsdo g
If you want you can add the function to the WHERE caluse as well, to filter the results - e.g. add in the above snippet:
where sdo_geom.relate(t.shape,'determine',g.shape,0.000000005) not in ('TOUCH','DISJOINT')
For a handful of geometries, you'll be fine. As the number of geometries grows, you must either use spatial indexes and add operator(s) in the WHERE clause, or device another way to filter the rows (e.g. by an attribute, id, etc) - spatial functions do not scale well.
You also have the responsibility to choose the TOLERANCE value that is appropriate for your data and query (I chose 0.000000005 as your shapes seem to have 8 significant decimals).
Last, BUT NOT LEAST, you'd want to make certain that your geometries are valid (again, at the appropriate tolerance).
HTH
APPEND:
1)
with HY90299 as (
select sdo_util.from_wktgeometry(
'MULTIPOLYGON (((-16.657423019000021 82.843477248999989, 16.710901260000014 66.242341995000004, 74.611375808999981 57.038061142000004, 111.18630027799998 67.126588820999984, -16.657423019000021 82.843477248999989)))'
) shape from dual ),
HYBOXSDO as (
select sdo_util.from_wktgeometry(
'MULTIPOLYGON (((60.839999999999975 26.569999999999993, 143.45000000000005 26.569999999999993, 143.45000000000005 55.75, 60.839999999999975 55.75, 60.839999999999975 26.569999999999993)))'
) shape from dual )
select sdo_geom.relate(t.shape,'determine',g.shape,0.000000005)
from HY90299 t,hyboxsdo g ;
The result is DISJOINT - also:
with HY90299 as (
select sdo_geometry(2003,4326,null, SDO_ELEM_INFO_ARRAY(1,1003,1),SDO_ORDINATE_ARRAY(-16.657423019000021, 82.843477248999989, 16.710901260000014, 66.242341995000004, 74.611375808999981, 57.038061142000004, 111.18630027799998, 67.126588820999984, -16.657423019000021, 82.843477248999989))
shape from dual )
select sdo_geom.relate(t.shape,'determine',
sdo_geometry(2003,4326,null, SDO_ELEM_INFO_ARRAY(1,1003,3),SDO_ORDINATE_ARRAY(60.840,26.570,143.450,55.750))
,0.000000005) as spat_rel from HY90299 t
The result is, again, DISJOINT.
Your 'overlapbdyintersect' shouldn't be there - check the contents of your tables (since the difference in your two queries is the 'window' geometry, double check the hyboxsdo table).
2) You are wrong. Tolerance is essential. If you use sdo_geom.relate(t.shape,'determine',g.shape,2) -that is a tolerance of 2 meters- in the above queries, you will get TOUCH instead of DISJOINT (and by this, you can also tell that your geometries are roughly 2m apart). However, with these two geometries, you would never get OVERLAP.
3) A geometry's validity is directly related to the tolerance you use. Your geometries are valid (in 8 decimals) - I'm just saying that it will save you LOTS of headaches if you don't take it for granted. Never assume - check!
4) It doesn't matter how you put the geometries in the table. The only think you might want to consider (especially in production environments) is the number of decimals stored in the database - if your data make good sense at a precision of, say, 3 decimals, you'd be better off rounding or truncating your coordinates to that. Simpler coordinates lead to smaller footprint (database storage) and faster performance.

How to filter clickhouse table by array column contents?

I have a clickhouse table that has one Array(UInt16) column. I want to be able to filter results from this table to only get rows where the values in the array column are above a threshold value. I've been trying to achieve this using some of the array functions (arrayFilter and arrayExists) but I'm not familiar enough with the SQL/Clickhouse query syntax to get this working.
I've created the table using:
CREATE TABLE IF NOT EXISTS ArrayTest (
date Date,
sessionSecond UInt16,
distance Array(UInt16)
) Engine = MergeTree(date, (date, sessionSecond), 8192);
Where the distance values will be distances from a certain point at a certain amount of seconds (sessionSecond) after the date. I've added some sample values so the table looks like the following:
Now I want to get all rows which contain distances greater than 7. I found the array operators documentation here and tried the arrayExists function but it's not working how I'd expect. From the documentation, it says that this function "Returns 1 if there is at least one element in 'arr' for which 'func' returns something other than 0. Otherwise, it returns 0". But when I run the query below I get three zeros returned where I should get a 0 and two ones:
SELECT arrayExists(
val -> val > 7,
arrayEnumerate(distance))
FROM ArrayTest;
Eventually I want to perform this select and then join it with the table contents to only return rows that have an exists = 1 but I need this first step to work before that. Am I using the arrayExists wrong? What I found more confusing is that when I change the comparison value to 2 I get all 1s back. Can this kind of filtering be achieved using the array functions?
Thanks
You can use arrayExists in the WHERE clause.
SELECT *
FROM ArrayTest
WHERE arrayExists(x -> x > 7, distance) = 1;
Another way is to use ARRAY JOIN, if you need to know which values is greater than 7:
SELECT d, distance, sessionSecond
FROM ArrayTest
ARRAY JOIN distance as d
WHERE d > 7
I think the reason why you get 3 zeros is that arrayEnumerate enumerates over the array indexes not array values, and since none of your rows have more than 7 elements arrayEnumerates results in 0 for all the rows.
To make this work,
SELECT arrayExists(
val -> distance[val] > 7,
arrayEnumerate(distance))
FROM ArrayTest;

Oracle 9i Sub query

Hi Can any one help me out of this query forming logic
SELECT C.CPPID, c.CPP_AMT_MANUAL
FROM CPP_PRCNT CC,CPP_VIEW c
WHERE
CC.CPPYR IN (
SELECT C.YEAR FROM CPP_VIEW_VIEW C WHERE UPPER(C.CPPNO) = UPPER('123')
AND C.CPP_CODE ='CPP000000000053'
and TO_CHAR(c.CPP_DATE,'YYYY/Mon')='2012/Nov'
)
AND UPPER(C.CPPNO) = UPPER('123')
AND C.CPP_CODE ='CPP000000000053'
and TO_CHAR(c.CPP_DATE,'YYYY/Mon') = '2012/Nov';
Please Correct me if i formed wrong query structure, in terms of query Performance and Standards. Thanks in Advance
If you have some indexes or partitioned tables I would not use functions on columns but on variables, to be able to use indexes/select partitions.
Also I use ANSI 92 SQL syntax. You don't specify(or not directly) a join contition between cpp_prcnt and cpp_view so it is actually a cartesian product(cross join)
SELECT C.CPPID, c.CPP_AMT_MANUAL
FROM CPP_PRCNT CC
CROSS JOIN CPP_VIEW c
WHERE
CC.CPPYR IN (
SELECT C.YEAR
FROM CPP_VIEW_VIEW C
WHERE C.CPPNO = '123'
AND C.CPP_CODE ='CPP000000000053'
AND trunc(c.CPP_DATE,'MM')=to_date('2012/Nov','YYYY/Mon')
)
AND C.CPPNO = '123'
AND C.CPP_CODE ='CPP000000000053'
AND trunc(c.CPP_DATE,'MM')=to_date('2012/Nov','YYYY/Mon')
If you show us the definition of cpp_view_view(seems to be a view over cpp_view), the definition(if simple) of CPP_VIEW and what you're trying to achieve, I bet there are more things to be improved/fixed.
There are a couple of things you could improve:
if possible, get rid of the UPPER() in the comparison - this will render any indices useless. If that's not possible, consider a function-based index on UPPER(CPPNO)
do not convert your DATE column to a string to compare it with a string - do it the other way round (i.e. convert your string to a date => only one conversion needed instead of one per table row, use of indices possible)
play around with EXISTS instead of IN, as suggested by Dileep - might be faster

Symfony2/Doctrine DQL QueryException

So I'm attempting to do a query on a table that holds two foreign keys. This table basically sets a specific userID to be an "admin" of a specific zoneID in our application my DQL is this:
'SELECT z, zone FROM MLBPBeerBundle:TableZoneAdmins z JOIN z.zoneAdminsZID WHERE z.zoneAdminsPID = '.$userID .'AND zone.zoneId = z.zoneAdminsZID'
I am getting this error:
An exception has been thrown during the rendering of a template ("[Syntax Error] line 0, col 80: Error: Expected end of string, got 'z'") in "MLBPBeerBundle:Profile:index.html.twig" at line 10.
From looking at the query the part in question "line 0, col 80 is the beginning of z.zoneAdminsPID which means at least in my interpretation of the error that it expects the string to end right after the WHERE which makes no sense
What makes this even more confusing is I have already successfully used a similar query to get a team name out of our games table which has a foreign key to the teams id:
'SELECT g, team1 FROM MLBPBeerBundle:TableGame g JOIN g.gameWinnertid WHERE g.gameZoneid = '.$zoneId .'AND team1.id = g.gameWinnertid'
Thank you for any help you can provide this has left me stumped as to me I don't really see a difference in how to two queries operate other than the fact they are grabbing different data
I was able to fix this by not including the JOIN, Symfony is more automagical than I thought in the fact that
SELECT z FROM MLBPBeerBundle:TableZoneAdmins z WHERE z.zoneAdminsPID = '.$userID
From here the zoneAdminsZID was a proper zone Entity, now I believe this is lazily loading this entity aka not firing the query till I "derefence" the ZID but for us this works just fine

PL/SQL: UPDATE inside CURSOR, but some data is NULL

I'm still learning some of the PL/SQL differences, so this may be an easy question, but... here goes.
I have a cursor which grabs a bunch of records with multiple fields. I then run two separate SELECT statements in a LOOP from the cursor results to grab some distances and calculate those distances. These work perfectly.
When I go to update the table with the new values, my problem is that there are four pieces of specific criteria.
update work
set kilometers = calc_kilo,
kilo_test = test_kilo
where lc = rm.lc
AND ld = rm.ld
AND le = rm.le
AND lf = rm.lf
AND code = rm.code
AND lcode = rm.lcode
and user_id = username;
My problem is that this rarely updating because rm.lf and rm.le have NULL values in the database. How can I combat this, and create the correct update.
If I'm understanding you correctly, you want to match lf with rm.lf, including when they're both null? If that's what you want, then this will do it:
...
AND (lf = rm.lf
OR (lf IS NULL AND rm.lf IS NULL)
)
...
It's comparing the values of lf and rm.lf, which will return false if either is null, so the OR condition returns true if they're both null.
I have a cursor which grabs a bunch of records with multiple fields. I then run two separate SELECT statements in a LOOP from the cursor results to grab some distances and calculate those distances. These work perfectly.
When I go to update the table with the new values, my problem is that there are four pieces of specific criteria.
The first thing I'd look at is not using a cursor to read data, then make calculations, then perform updates. In 99% of cases it's faster and easier to just run updates that do all of this in a single step
update work
set kilometers = calc_kilo,
kilo_test = test_kilo
where lc = rm.lc
AND ld = rm.ld
AND NVL(le,'x') = NVL(rm.le,'x')
AND NVL(lf,'x') = NVL(rm.lf,'x')
AND code = rm.code
AND lcode = rm.lcode
and user_id = username;

Resources