Oracle: outer join(+) with or clause replacement - sql

I have an enormous select that schematically looks like this:
SELECT c_1, c_2, ..., c_j FROM t_1, t_2, ..., t_k
WHERE e_11 = e_12(+)
AND e_21 = e_22(+)
AND ...
AND e_l1 = e_l2(+)
ORDER BY o
where j, k and l are in hundreds and e_mn is a column from some table. I need to add new columns A_1 and A_2 to the select from a new table T. The new columns are connected to the former select via a column call it B from a table R. I want those rows where A_1 = B or A_2 = B or those rows where there is no correspondeing A_i to the value B.
Suppose I only had to deal with tables T and R then I want this:
SELECT * FROM R
LEFT OUTER JOIN T
ON (A_1 = B OR A_2 = B)
To mimic this behaviour I'd want something like this in the big select:
SELECT c_1, c_2, ..., c_j, A_1, A_2 FROM t_1, t_2, ..., t_k, T
WHERE e_11 = e_12(+)
AND e_21 = e_22(+)
AND ...
AND e_l1 = e_l2(+)
AND (B = A_1(+) OR B = A_2(+))
ORDER BY o
this is, however, syntactically incorrect since the (+) operator cannot be used with the OR caluse. And if I leave out the (+)'s I lose those rows where there is no corresponding A_i to B.
What are my options here? Can I somehow find a way to do this without changing the whole body of the select? I doubt there is a reasonable way to do this, nevertheless I'd appreciate any help.
Thanks.

Related

How to extract a json value inside an array inside a json in SQL

I have a JSON being returned in my query called MetaDataJSON, inside which is an array of JSONs called Results. Inside each JSON in Results are two values, Chronic and Probability. There are a couple other tables that have been joined too. Is there a way to get Chronic in a column by itself? Right now I have gotten this far (table and variable names have been made generic):
SELECT DISTINCT
JSON_QUERY(mdj.value, '$.Results[0]') [Results]
FROM table1 t1
JOIN table2 t2 ON t2.parameter1 = t1.parameter1
AND t2.parameter2 = 'ASDF'
JOIN table3 t3 ON oad.parameter3 = oa.parameter3
AND t3.parameter4 = 11
CROSS APPLY OPENJSON(t3.MetaDataJSON) as mdj
This gets me a column called Results where each entry looks like:
{"Chronic": 0, "Probability": 0.0016}
Is there an efficient way to get Chronic in a column by itself? Thanks!
You can do it like this,
WITH jsons (x)
AS
(
-- replace this part with your query
Select a.x from (select '{"Chronic": 0, "Probability": 0.0016}' x ) as a, (SELECT 1 as y union select 2 as y ) as b
)
select
(SELECT value FROM OPENJSON(x,'$') where [key]='Chronic') as "Chronic",
(SELECT value FROM OPENJSON(x,'$') where [key]='Probability') as "Probability"
from jsons;
I think you can change the #json equation to use your query. But I cannot try since I don't have your tables...
BTW, I assume you are using MSSQL...

PostGIS Intersection of multiple tables

In my postGIS DB, I need to create a new layer from the intersection of multiple polygons layers, while maintaining all fields (or Columns) from all layers (or tables) ==> in the output table, I need all columns for the 3 input tables
I believe it has to include ST_Intersects, but I am unable to find the correct syntax. Can you help me designing the SQL command line, knowing the following generic table names:
- TableA (with the columns: GeomA (geometry), ColumnA1, ColumnA2)
- TableB (with the columns: GeomB (geometry), ColumnB1)
- TableC (with the columns: GeomC (geometry), ColumnC1)
All geometry fields from TableA,TableB and TableC are in the same projection.
Thanks
For clarity, since "interaction with multiple polygons layers" is a bit vague, it could mean:
you want to find all polygons from A that intersect with a polygon from B and a polygon from C
or A with B, B with C
or A with B, A with C and B with C
For simplicity let us assume the first scenario, and I presume the others will be pretty easy to deduce:
select A.*, B.*, C.*
from A, B, C
where st_intersects(A.geomA, B.geomB) = true
and st_intersects(A.geomA, C.geomC) = true
[EDIT] Not just finding the rows, but if the intersection itself is important we can do the following (in the simple case of two geometries intersecting)
select A.*, B.*, st_intersection(A.geomA, B.geomB) as geomAB
from A, B
where st_intersects(A.geomA, B.geomB) = true
I simplified the case because if A intersects with B, and A intersects with C, it is not even sure those two intersections intersect again and have a result.
If we suppost A intersects with B, B with C and C with A then we should have a intersection imho. So that would look like:
select A.*, B.*, C.*, st_intersection(A.geomA, st_intersection(B.geomB, C.geomC)) as geomABC
from A, B, C
where st_intersects(A.geomA, B.geomB) = true
and st_intersects(A.geomA, C.geomC) = true
and st_intersects(B.geomB, C.geomC) = true

Combining two tuples into one in oracle db

Say I have a bunch of letters grouped together and I want to find out which pair bonds with another the most, as an example I have
a b d b
b c e a
and it should return ab or ba because a-b are the most occurred here.
so far I have made a query that just pulls every two letters that are together, but when I run the query I get something like the above example but all are in separate tuples, like this
a
b
b
c
d
e
b
a
I need to compare the occurence of all the PAIRS, my logic so far is that I can use nvl() to concat them(but nvl() of a-b and b-a returns two separate instances), then run a count, but I'm not sure how to run a count on these as I called the letters
select a.value, b.value
from Letter a, Letter b, Word aw, Word bw, Sentence senA, sentence senb
where a.id = aw.aid and aw.pid = sena.id and b.id = bw.aid and
bw.pid = senb.id and aw.pid = bw.pid and a.value != b.value
;
TL;DR: I want to do a count(a.ltr-b.ltr pair) but not sure how to code that.
Thanks!
EDIT: table structure:
letter(id, value)
\
word(aid, pid)
\
sentence(id, name,sid)
basically, if two letters end up in the same sentence.id, they are a pair(bond).

SQL - WHERE (X, Y) IN (A, B)

I have some kind of blockage currently.
My theoretic query looks something like this:
SELECT * FROM Table WHERE X in (a, b, c) AND Y IN (d, e, f)
So basically, I want all rows having multiple columns match, meaning:
X, Y
1, 2
3, 4
5, 6
7, 8,
9, 10
If I want to get all rows where (X=1, Y=2) or (X=5, Y=6), so X and Y are correlated, how would I do that?
(MS SQL2005+)
Why not something simple like the following?
WHERE (X = 1 AND Y = 2) OR (X = 5 AND Y = 6) ...
Or, if you're looking for rows (based on your example) where Y should be X + 1, then:
WHERE Y = X + 1
If you have thousands of OR clauses like the above, then I would suggest you populate a criterion table ahead of time, and rewrite your query as a join. Suppose you have such a table Criteria(X, Y) then your query becomes much simpler:
SELECT Table.*
FROM Table
INNER JOIN Criteria ON Table.X = Criteria.X AND Table.Y = Criteria.Y
Don't forget to add an index / foreign keys as necessary to the new table.
If for some reason you prefer to not create a table ahead of time, you can use a temporary table or table variable and populate it within your procedure.
If X and Y are in a table then a JOIN would be cleanest:
SELECT * FROM Table t
INNER JOIN XandY xy
WHERE tX = xy.X AND t.Y = xy.Y
If there not in a table I would strongly suggest putting them in one. IN only works with single-value sets and there's no way to line up results using multiple IN clauses.

How to use a variable AS a where clause?

I have one where clause which I have to use multiple times. I am quite new to Oracle SQL, so please forgive me for my newbe mistakes :). I have read this website, but could not find the answer :(. Here's the SQL statement:
var condition varchar2(100)
exec :condition := 'column 1 = 1 AND column2 = 2, etc.'
Select a.content, b.content
from
(Select (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3)) as content
from table_name
where category = X AND :condition
group by (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3))
) A
,
(Select (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,100)) as content
from table_name
where category = Y AND :condition
group by (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,100))) B
GROUP BY
a.content, b.content
The content field is a CLOB field and unfortunately all values needed are in the same column. My query does not work ofcourse.
You can't use a bind variable for that much of a where clause, only for specific values. You could use a substitution variable if you're running this in SQL*Plus or SQL Developer (and maybe some other clients):
define condition = 'column 1 = 1 AND column2 = 2, etc.'
Select a.content, b.content
from
(Select (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3)) as content
from table_name
where category = X AND &condition
...
From other places, including JDBC and OCI, you'd need to have the condition as a variable and build the query string using that, so it's repeated in the code that the parser sees. From PL/SQL you could use dynamic SQL to achieve the same thing. I'm not sure why just repeating the conditions is a problem though, binding arguments if values are going to change. Certainly with two clauses like this it seems a bit pointless.
But maybe you could approach this from a different angle and remove the need to repeat the where clause. Querying the table twice might not be efficient anyway. You could apply your condition once as a subquery, but without knowing your indexes or the selectivity of the conditions this could be worse:
with sub_table as (
select category, content
from my_table
where category in (X, Y)
and column 1 = 1 AND column2 = 2, etc.
)
Select a.content, b.content
from
(Select (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3)) as content
from sub_table
where category = X
group by (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3))
) A
,
(Select (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,100)) as content
from sub_table
where category = Y
group by (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,100))) B
GROUP BY
a.content, b.content
I'm not sure what the grouping is for - to eliminate duplicates? This only really makes sense if you have a single X and Y record matching the other conditions, doesn't it? Maybe I'm not following it properly.
You could also use a case statement:
select max(content_x), max(content_y)
from (
select
case when category = X
then DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3) end as content_x,
case when category = Y
then DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,100) end as content_y,
from my_table
where category in (X, Y)
and column 1 = 1 AND column2 = 2, etc.
)