Calculating the are of overlap between polygons in the same table - sql

I need to calculate the are of overlap between polygons in the same table. Idealy I would like to use mssql spatial capabilities for this (something like #a.SHAPe.STIntersections(#b.SHAPE).STArea()).
But I do not know how to do this for polygons in the same layer.
Thanks!
Freddie

I have knock up a little example for you that shows you how this can be accomplished.
SELECT
a.Geog1.STIntersection(b.Geog2) AS OverlapGeog
, a.Geog1.STIntersection(b.Geog2).STArea() AS AreaOverlap
FROM
(
SELECT
GEOGRAPHY::STGeomFromText('POINT(0.0 0.0)',4326).STBuffer(100) AS Geog1
) a
INNER JOIN
(
SELECT
GEOGRAPHY::STGeomFromText('POINT(0.001 0.0)',4326).STBuffer(100) AS Geog2
) b
On
a.Geog1.STIntersects(b.Geog2) = 1

Related

how to divide by subset of table by itself, i.e. normalisation (t!=0 rows by t=0 rows)

I'm essentially looking for a way to normalise (t/t0) a bunch of measurements across timepoints with a specific timepoint, e.g. timepoint=0.
I have a table as following:
coordinate,timepoint,quantity
A1,0,50
B2,0,10
C3,0,60
A2,0,20
F1,0,20
A1,1,100
B2,1,150
C3,1,120
A2,1,140
F1,1,160
A1,4,100
B2,4,80
C3,4,80
A2,4,100
F1,4,120
I want to make a table that divides all the other non-zero timepoint rows by the 0 timepoint rows where the coordinates match, i.e. A1-t1 / A1-t0, A1-t4 / A1-t0, B2-t1 / B2-t0, B2-t0 / B2-t4 etc. etc. for wherever there is a join on coordinate available.
The result would be like:
coordinate,timepoint,quantity
A1,0,1
B2,0,1
C3,0,1
A2,0,1
F1,0,1
A1,1,2
B2,1,15
C3,1,2
A2,1,7
F1,1,8
etc.
Something like this mostly works...
select t0.coordinate,t0.quantity,tother.quantity,tother.quantity/t0.quantity as tnorm
(select * from table
where timepoint != 0) as tother
LEFT JOIN (select * from table
where timepoint = 0) as t0
ON (t1.coordinate = t2.coordinate);
Though I ideally would like to have a pivot of the table could be displayed where each column is each normalisation, e.g. columns as
coordinate, t0/t0, t1/t0, t4/t0 etc.
A1,1,2,value etc.
B2,1,15,value etc.
C3,1,2,value etc.
A2,1,7,value etc.
F1,1,8,value etc.
...though this might not be possible and must be done in postprocessing (e.g. pandas pivot).
I couldn't work out the right syntax for this one - any help is appreciated.
WITH t1 AS (
SELECT position, quantity
FROM table
WHERE timepoint = 0
)
SELECT t2.position, t2.timepoint, (t2.quantity/t1.quantity) quantity
FROM table t2
INNER JOIN t1 ON t2.position=t1.position

SQL retrieve info from 2 different ID in a single query

Let's say I have a table that represents soccer matches (X_train in this case) with an away_team_id and a home_team_id, those id points to another table 'team_attributes'.
What I managed to do with a query is to select the attributes of only one of the team but I'm interested in getting both team's attributes.
This is the query I'm using now :
SELECT
X_Train.* , Team_Attributes.*, MAX(Team_Attributes.date)
FROM
X_Train
LEFT JOIN
Team_Attributes ON X_Train.home_team_api_id = Team_Attributes.team_api_id
AND Team_Attributes.date <= X_Train.date
GROUP BY
X_Train.id
ORDER BY
X_Train.date
This works fine but I need to get the same join on the X_train.away_team_api_id, is there an easy way to do this ? I tried using UNION but maybe I didn't look far enough in that direction.
Thank you
You need a second join. For that -- and to simplify the query -- use table aliases:
SELECT t.*, hta.*, ata.*
FROM X_Train t LEFT JOIN
Team_Attributes hta
ON t.home_team_api_id = hta.team_api_id AND
hta.date <= t.date LEFT JOIN
Team_Attributes ata
ON t.away_team_api_id = ata.team_api_id AND
ata.date <= t.date
ORDER BY t.date DESC;
I don't understand what the GROUP BY is doing, so I removed it. Your question appears to be about JOIN logic anyway.

Trouble with PIVOT in SQL (Azure SQL)

I need to list survey responses in one row. The table of survey responses lists a questionID and a ResponseID (these are multiple choice questions), so one row for each response. There are 12 questions. Things like the date of the response, worker who conducted the survey, and worker who entered the survey are kept in other tables.
So, I have a query that gets the responses for one survey into 12 rows. Now I need to get all that into one row. Pivot, right?
But I could never get it to work. :-( Tried several solutions from this and other fora (including Mickey's documentation here: https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-2017).
Then I found this solution, that doesn't use pivot at all, here: SQL Pivot Table Grouping
It worked great, but the example has only two questions. Some of our surveys will have over 50 questions, so I'm guessing that won't be a very elegant solution.
So I'm back to my pivot issue.
Experience level is somewhere between idiot and novice, so I'm probably missing something obvious.
Here's the query by itself (works as expected):
SELECT AssessmentResponses.ID, AssessmentQuestions.QuestionNumber,
AssessmentResponseAnswers.QuestionID,
AssessmentAnswerChoices.AnswerChoiceNumber
FROM (AssessmentResponses RIGHT JOIN AssessmentResponseAnswers
ON AssessmentResponses.ID = AssessmentResponseAnswers.AssessmentResponseID)
LEFT JOIN (AssessmentQuestions RIGHT JOIN AssessmentAnswerChoices
ON AssessmentQuestions.ID = AssessmentAnswerChoices.AssessmentQuestionID)
ON AssessmentResponseAnswers.AnswerChoiceID = AssessmentAnswerChoices.AnswerChoiceID
WHERE AssessmentResponses.AssessmentID = 1 AND AssessmentResponses.RespondentID = 44;
Here's how I tried to make it pivot:
SELECT ID, [1A], [1B], [2A], [2B], [3A], [3B], [4A], [4B], [5A], [5B], [6A], [6B]
FROM (
SELECT AssessmentResponses.ID, AssessmentQuestions.QuestionNumber,
AssessmentResponseAnswers.QuestionID,
AssessmentAnswerChoices.AnswerChoiceNumber
FROM (AssessmentResponses RIGHT JOIN AssessmentResponseAnswers
ON AssessmentResponses.ID = AssessmentResponseAnswers.AssessmentResponseID)
LEFT JOIN (AssessmentQuestions RIGHT JOIN AssessmentAnswerChoices
ON AssessmentQuestions.ID = AssessmentAnswerChoices.AssessmentQuestionID)
ON AssessmentResponseAnswers.AnswerChoiceID = AssessmentAnswerChoices.AnswerChoiceID
WHERE AssessmentResponses.AssessmentID = 1 AND AssessmentResponses.RespondentID = 44
) AS Src
PIVOT
(
MAX(AnswerChoiceNumber)
FOR QuestionNumber IN ([1A], [1B], [2A], [2B], [3A], [3B], [4A], [4B], [5A], [5B], [6A], [6B])
)
AS Pvt;
I was hoping that would give me 1 row with 13 columns (ID plus the twelve questions). But it gave me still 12 rows: the 13 columns are there, and it just gives null values for 11 of the twelve questions. (In row1, 1A has an answer; in row2, 1B has an answer, etc.)
What am I missing?
Tweaked your code just a bit to get rid of "QuestionID" in the subquery. It is not involved in what you're pivoting on, so SQL Server will think it's one of your keys.
SELECT ID, [1A], [1B], [2A], [2B], [3A], [3B], [4A], [4B], [5A], [5B], [6A], [6B]
FROM (
SELECT AssessmentResponses.ID, AssessmentQuestions.QuestionNumber,
AssessmentAnswerChoices.AnswerChoiceNumber
FROM (AssessmentResponses RIGHT JOIN AssessmentResponseAnswers
ON AssessmentResponses.ID = AssessmentResponseAnswers.AssessmentResponseID)
LEFT JOIN (AssessmentQuestions RIGHT JOIN AssessmentAnswerChoices
ON AssessmentQuestions.ID = AssessmentAnswerChoices.AssessmentQuestionID)
ON AssessmentResponseAnswers.AnswerChoiceID = AssessmentAnswerChoices.AnswerChoiceID
WHERE AssessmentResponses.AssessmentID = 1 AND AssessmentResponses.RespondentID = 44
) AS Src
PIVOT
(
MAX(AnswerChoiceNumber)
FOR QuestionNumber IN ([1A], [1B], [2A], [2B], [3A], [3B], [4A], [4B], [5A], [5B], [6A], [6B])
)
AS Pvt;
I imagine you're used to the designer. A few tips (not implemented above) to make code more readable:
You can usually omit parentheses around your join statements
I'd re-work your joins to associate one on-statement per join statement
Aliases!
In my opinion this is not exactly a work to do with pivot. Maybe like this:
SELECT ar.ID
,(
SELECT aac.AnswerChoiceNumber
FROM AssessmentResponseAnswers ara, AssessmentAnswerChoices aac, AssessmentQuestions aq
WHERE ar.ID=ara.AssessmentResponseID
AND ara.AnswerChoiceID=aac.AnswerChoiceID
AND aq.ID=aac.AssessmentQuestionID
AND aq.QuestionNumber='1A'
) 1A
,(
SELECT aac.AnswerChoiceNumber
FROM AssessmentResponseAnswers ara, AssessmentAnswerChoices aac, AssessmentQuestions aq
WHERE ar.ID=ara.AssessmentResponseID
AND ara.AnswerChoiceID=aac.AnswerChoiceID
AND aq.ID=aac.AssessmentQuestionID
AND aq.QuestionNumber='1B'
) 1B
, (...)
FROM AssessmentResponses ar
WHERE ar.AssessmentID=1
AND ar.RespondentID=44
I was having problems with your usage of the joins but I tried to figure it out - maybe it is correct.

SQL Modeling Pyramid or Binary Tree

I'm building a sql server project that have a pyramid or binary tree concept...
I gonna try to explain using some tables!
The first table is
TB_USER(ID, ID_FATHER, LEFT/RIGHT TREE POSITION)
User can sell producs! So when they sell they earn points. Then, the second table is
TB_SELL (ID_USER, ID_PRODUCT, POINT)
As a result I'd like to see in the report format of points of each client below me in the binary model tree. How can I design these tables to make my life easier in this kind of search ? I will always get my soons up to 9 levels down.
I know that with procedure I can solve this problem , however I would like to know an elegant and simple solution.
Thank you
I solve this using a with a recursive query:
with with_user_earns as (
-- get father information (start)
select father.id, father.str_name, father.id_father, father.ind_father_side_type, 1 as int_user_level from tb_user father where id = 9
union all
-- get all soons (stop condition)
select son.id, son.str_name, son.id_father, son.ind_father_side_type, WUE.int_user_level + 1 from tb_user as son inner join with_user_earns as WUE on son.id_father = WUE.id where son.id_father is not null /*and WUE.int_user_level < 9*/
)
-- show result
select with_user_earns.id, with_user_earns.str_name, with_user_earns.id_father, with_user_earns.ind_father_side_type, with_user_earns.int_user_level from with_user_earns order by with_user_earns.int_user_level, with_user_earns.id

Why do I have to use DISTINCT for this to work?

here's my problem: I have an SQL query that makes 4 calls to a lookup table to return their values from a list of combinations in another table. I finally got this working, and for some reason, when I run the query without DISTINCT, I get a ton of data back, so I'm guessing that I'm either missing something or not doing this correctly. It would be really great if this would not only work, but also return the list alphabetically by the first colour name.
I'm putting my SQL here I hope I've explained this well enough:
SELECT DISTINCT
colour1.ColourID AS colour1_ColourID,
colour1.ColourName AS colour1_ColourName,
colour1.ColourHex AS colour1_ColourHex,
colour1.ManufacturerColourID AS colour1_ManufacturerColourID,
colour2.ColourID AS colour2_ColourID,
colour2.ColourName AS colour2_ColourName,
colour2.ColourHex AS colour2_ColourHex,
colour2.QEColourID2 AS colour2_QEColourID2,
colour3.ColourID AS colour3_ColourID,
colour3.ColourName AS colour3_ColourName,
colour3.ColourHex AS colour3_ColourHex,
colour3.QEColourID3 AS colour3_QEColourID3,
colour4.ColourID AS colour4_ColourID,
colour4.ColourName AS colour4_ColourName,
colour4.ColourHex AS colour4_ColourHex,
colour4.QEColourID4 AS colour4_QEColourID4,
Combinations.ID,
Combinations.ManufacturerColourID AS Combinations_ManufacturerColourID,
Combinations.QEColourID2 AS Combinations_QEColourID2,
Combinations.QEColourID3 AS Combinations_QEColourID3,
Combinations.QEColourID4 AS Combinations_QEColourID4,
Combinations.ColourSupplierID,
ColourSuppliers.ColourSupplier
FROM
ColourSuppliers INNER JOIN
(
colour4 INNER JOIN
(
colour3 INNER JOIN
(
colour2 INNER JOIN
(
colour1 INNER JOIN Combinations ON
colour1.ColourID=Combinations.ManufacturerColourID
) ON colour2.ColourID=Combinations.QEColourID2
) ON colour3.ColourID=Combinations.QEColourID3
) ON colour4.ColourID=Combinations.QEColourID4
) ON ColourSuppliers.ColourSupplierID=Combinations.ColourSupplierID
WHERE Combinations.ColourSupplierID = ?
Thanks
Steph
It looks as though you've probably got multiple records for each set of four colour combinations in the Combinations table - posting the structure of the table might help us to work it out.
Adding the clause order by colour1.ColourName to the end of the query should sort it alphabetically by the first colour name.
My guess (and it is a guess because your SQL query is very wide!) is that you're getting the cartesian product.