Compare two unrelated tables sql - sql

We're dealing with geographic data with our Oracle database.
There's a function called ST_Insertects(x,y) which returns true if record x intersects y.
What we're trying to do is, compare each record of table A with all records of table B, and check two conditions
condition 1 : A.TIMEZONE = 1 (Timezone field is not unique)
condition 2 : B.TIMEZONE = 1
condition 3 : ST_Intersects(A.SHAPE, B.SHAPE) (Shape field is where the geographical information is stored)
The result we're looking for is records ONLY from the table A that satisfy all 3 conditions above
We tried this in a single select statement but it doesn't seem to make much sense logically

pseudo-code that demonstrates a cross-join:
select A.*
from
tbl1 A, tbl2 B
where
A.TIMEZONE = 1 and
B.TIMEZONE = 1 and
ST_Intersects(A.SHAPE, B.SHAPE)
if you get multiples, you can put a distinct and only select A.XXX columns
With a cross-join rows are matched like this
a.row1 - b.row1
a.row1 - b.row2
a.row1 - b.row3
a.row2 - b.row1
a.row2 - b.row2
a.row2 - b.row3
So if row 1 evaluates to true on multiple rows, then just add a distinct on a.Column1, etc.

If you want to use the return value from your function in an Oracle SQL statement, you will need to change the function to return 0 or 1 (or 'T'/'F' - some data type supported by Oracle Database, which does NOT support the Boolean data type).
Then you probably want something like
select <columns from A>
from A
where A.timezone = 1
and exists ( select *
from B
where B.timezone = 1
and ST_intersects(A.shape, B.shape) = 1
)

Related

In operator takes only one Id(if Id is repeating) from the list in sql server

I have a query I am using IN operator and I want all the rows from in given list as shown in the picture that I want 3 rows for id 1 and one for id 2, but I only get one row for Id = 1 is there any other solution for this.
IN can't do what you want. JOIN instead:
select * from logs
JOIN (values (1),(2),(1),(1)) x (id)
ON logs.id = x.id

Filter by one column then count unique value in another column in SQL

I would like to filter data by column Base =1 and then count the number of unique values in another column 'Animal' in SQL, data:
Animal Base Value
1 A 1 X
2 B 1 X
3 A 2 Y
4 A 3 V
Expected output in this case is 2 from the first two rows.
Simpler than you may have thought:
SELECT count(DISTINCT Animal)
FROM tbl
WHERE Base = 1;
Should work in any halfway decent RDBMS including your undisclosed one. (You may have to enclose column names in double-quotes.)
This should do it, assuming the table is named animals:
select count(*) from (select distinct Animal from animals where Base=1) tb1;

SQL How to return a result set that will combine multiple rows into one row

I am trying to get one row returned for each store number and per date that includes all values from the RecordTypeA column for that date.
The table I am using is created with a column named "RecordTypeA", it is a bit data type with (1 and 0) entries. 1 equals Type A and 0 equals Type B.
What I am trying to do is show the value of the RecordTypeA column for the store if there are entries of 1 and / or 0 on the same date on the same row.
Scenario 1 (One row returns for the store for the date): RecordTypeA column value = '1'
There is one row in the table for the store and date and the RecordTypeA column = '1' :
Scenario 2 (Two Rows return for the store for the same date):
Row One - RecordTypeA = '1'
Row Two - RecordTypeA = '0' (The column is still named RecordTypeA, but value '0' means something different so I want to create a column name?)
Scenario 3 (One row returns for the store for the date):
RecordTypeA column value = '0'
There is one row in the table for the store and date and the RecordTypeA column = '0' :
My issue is that I am getting multiple rows returned when the store has a RecordtypeA = 0 and a RecordtypeA = 1 row. Which I need to return on the same row. (Create columns that hold both 1 and 0 or Null.
What I am getting is
StoreID Date RecordTypeA
1234 2020-01-04 0
1234 2020-01-05 0
1234 2020-01-05 1
Needed:
StoreID Date RecordTypeA RecordTypeB
1234 2020-01-04 0 NULL
1234 2020-01-05 0 1
I have tried adding in case statements but I have not been able to get the one row as needed. Also, searched and tried PIVOT statements (I don't truly understand PIVOTs) but I get an error on the RecordTypeA Bit type.
Case when s.RecordTypeA = '1' Then 'TypeA' Else 'Null' End as Type
Case when s.RecordTypeA = '0' Then 'TypeB' Else 'Null' End as Type
SELECT r.StoreID,
r.CreatedDate,
s.RecordTypeA
From Request r
Inner Join Stores s on r.id = s.id
Group by r.StoreID,
r.CreatedDate,
s.RecordTypeA
Welcome to stack overflow community!
Have you tried to construct 3 queries and use UNION ALL statement?
You can create a query for StoreID, Date, RecordTypeA, TypeB and Typec.
For example:
SELECT CONCAT(r.StoreID, r.CreatedDate, s.RecordTypeA) AS DATA, 'A' AS TYPE
FROM YOURDATABASE.YOURTABLE
WHERE (A CRITERIA FOR TYPE A)
UNION ALL
SELECT CONCAT(r.StoreID, r.CreatedDate, s.RecordTypeA) AS DATA, 'B' AS TYPE
FROM YOURDATABASE.YOURTABLE
WHERE (A CRITERIA FOR TYPE B)
UNION ALL
...
I use the same alias on the example because with union all, all the queries must have the same columns, so you can use a CONCAT to put all your data from the different queries in one column, the column "TYPE" is for the difference the queries at the result.
Even if you not use concat you can return the columns different but all the queries must have the same column count on the select.
With multiple queries, you can define de criteria you want for type A, B, C through Z but have all of them at one result.
Important: Union all statements are somehow heavy for performance, so have it in mind.

SQL Case with calculation on 2 columns

I have a value table and I need to write a case statement that touches 2 columns: Below is the example
Type State Min Max Value
A TX 2 15 100
A TX 16 30 200
A TX 31+ 500
Let say I have another table that has the following
Type State Weight Value
A TX 14 ?
So when I join the table , I need a case statement that looks at weight from table 2 , type and state - compare it to the table 1 , know that the weight falls between 2 and 15 from row 1 and update Value in table 2 with 100
Is this doable ?
Thanks
It returns 0 if there aren't rows in this range of values.
select Type, State, Weight,
(select coalesce(Value, 0)
from table_b
where table_b.Type = table_a.Type
and table_b.State = table_a.State
and table_a.Value between table_b.Min and table_b.Max) as Value
from table_a
For an Alteryx solution: (1) run both tables into a Join tool, joining on Type and State; (2) Send the output to a Filter tool where you force Weight to be between Min and Max; (3) Send that output to a Select tool, where you grab only the specific columns you want; (since the Join will give you all columns from all tables). Done.
Caveats: the data running from Join to Filter could be large, since you are joining every Type/State combination in the Lookup table to the other table. Depending on the size of your datasets, that might be cumbersome. Alteryx is very fast though, and at least we're limiting on State and Type, so if your datasets aren't too large, this simple solution will work fine.
With larger data, try to do it as part of your original select, utilizing one of the other solutions given here for your SQL query.
Considering that Min and Max columns in first table are of Integer type
You need to use INNER JOIN on ranges
SELECT *
FROM another_table a
JOIN first_table b
ON a.type = b.type
AND a.State = b.State
AND a.Weight BETWEEN b.min AND b.max

SQL: Most efficient way to select sequences of rows from a table

I have a tagged textual corpus stored in an SQL table like the following:
id tag1 tag2 token sentence_id
0 a e five 1
1 b f score 1
2 c g years 1
3 d h ago 1
My task is to search the table for sequences of tokens that meet certain criteria, sometimes with gaps between each token.
For example:
I want to be able to search for a sequence similar to the following:
the token has the value a in the tag1 column, and
the second token is one to two rows away from the first, and has the value g in tag2 or b in tag1, and
the third token should be at least three rows away, and has ago in the token column.
In SQL, this would be something like the following:
SELECT * FROM my_table t1
JOIN my_table t2 ON t1.sentence_id = t2.sentence_id
JOIN my_table t3 ON t3.sentence_id = t1.sentence_id
WHERE t1.tag1 = 'a' AND (t2.id = t1.id + 1 OR t2.id = t1.id + 2)
AND (t2.tag2 = 'g' OR t2.tag1 = 'b')
AND t3.id >= t1.id + 3 AND t3.token = 'ago'
So far I have only been able to achieve this by joining the table by itself each time I specify a new token in the sequence (e.g. JOIN my_table t4), but with millions of rows this gets quite slow. Is there a more efficient way to do this?
You could try this staged approach:
apply each condition (other than the various distance conditions) as a subquery
Calculate the distances between the tokens which meet the conditions
Apply all the distance conditions separately.
This might improve things, if you have indexes on the tag1, tag2 and token columns:
SELECT DISTINCT sentence_id FROM
(
-- 2. Here we calculate the distances
SELECT cond1.sentence_id,
(cond2.id - cond1.id) as cond2_distance,
(cond3.id - cond1.id) as cond3_distance
FROM
-- 1. These are all the non-distance conditions
(
SELECT * FROM my_table WHERE tag1 = 'a'
) cond1
INNER JOIN
(
SELECT * FROM my_table WHERE
(tag1 = 'b' OR tag2 = 'g')
) cond2
ON cond1.sentence_id = cond2.sentence_id
INNER JOIN
(
SELECT * FROM my_table WHERE token = 'ago'
) cond3
ON cond1.sentence_id = cond3.sentence_id
) conditions
-- 3. Now apply the distance conditions
WHERE cond2_distance BETWEEN 0 AND 2
AND cond3_distance >= 3
ORDER BY sentence_id;
If you apply this query to this SQL fiddle you get:
| sentence_id |
|-------------|
| 1 |
| 4 |
Which is what you want. Now whether it's any faster or not, only you (with your million-row database) can really tell, but from the perspective of having to actually write these queries, you'll find they're much easier to read, understand and maintain.
You need to edit your question and give more details on how these sequences of tokens work (for instance, what does "each time I specify a new token in the sequence" mean in practice?).
In postgresql you can solve this class of queries with a window function. Following your exact specification above:
SELECT *,
CASE
WHEN lead(tag2, 2) OVER w = 'g' THEN lead(token, 2) OVER w
WHEN lead(tag1) OVER w = 'b' THEN lead(token) OVER w
ELSE NULL::text
END AS next_token
FROM my_table
WHERE tag1 = 'a'
AND next_token IS NOT NULL
WINDOW w AS (PARTITION BY sentence_id ORDER BY id);
The lead() function looks ahead a number of rows (default is 1, when not specified) from the current row in the window frame, in this case all rows with the same sentence_id as specified in the partition of the window definition. So, lead(tag1, 2) looks at the value of tag1 two rows ahead to compare against your condition, and lead(token, 2) returns the token from two rows ahead as column next_token in the current row and having the same sentence_id. If the first CASE condition fails, the second is evaluated; if that fails NULL is returned. Note that the order of the conditions in the CASE clause is significant: different ordering gives different results.
Obviously, if you keep on adding conditions for subsequent tokens the query becomes very complex and you may have to put individual search conditions in separate stored procedures and then call these depending on your requirements.