Unable to create SQL Join query - sql

Table I
ID LinkId
1 0
2 1
3 2
Table 2
ID IntersectionID X Y
1 5 100 200
2 6 300 400
3 7 800 500
Table 3
ID IntersectionID Sequence_number linkId LinkDirection
1 5 0 0 Positive
1 5 1 1 negative
2 6 0 0 negative
I want a single query giving me the following
ID LinkId X(start) Y(Start) X(End) Y(End)
1 0 100 200 300 400
For every row in Table 1, get its IntersectionID from table 3(using linked field),(link direction- positive means start point and negative means end point). Then go to table 2 and fill x,y values.
Help me achieve it.
Tried this query. Unable to get it.
select r1.id id, r1.linkid base_link_id, r2.X startX,r2.Y startY from table1 r1, table2 r2
where startX = (select X from table2 where id = r1.id and intersectionId =
(select intersectionId from table3 where id = r1.id and linkId= r1.linkid and LinkDirection = positive)) and startY
= (select Y from table2 where id = r1.id and intersectionId =
(select intersectionId from table3 where id = r1.id and linkId= r1.linkid and LinkDirection = negative));

With this query you should be able to do it.
Pay attention on LinkDirection if it's text.
SELECT
t1.ID
,t1.LinkId
,t2_start.X as X_Start
,t2_start.Y as Y_Start
,t2_end.X as X_End
,t2_end.Y as Y_End
FROM
table1 t1
LEFT JOIN table3 t3_start
on t1.linkId = t3_start.linkId
and t3_start.LinkDirection = 'Positive'
LEFT JOIN table2 t2_start
on t2_start.IntersectionID = t3_start.IntersectionID
LEFT JOIN table3 t3_end
on t1.linkId = t3_end.linkId
and t3_end.LinkDirection = 'negative'
LEFT JOIN table2 t2_end
on t2_end.IntersectionID = t3_end.IntersectionID
You will get null field in t2_start.X t2_start.Y t2_end.X t2_end.Y if there is no row in table2. You can change it to 0 or -1 with
CASE WHEN t2_start.X is not null THEN t2_start.X ELSE -1 END

Hope the below query is usefull, if you need clarification. Please ask
SELECT ID,LinkID,MAX(StartX) AS StartX ,MAX(Starty) AS StartY,
MAX(EndX) AS EndX,MAX(EndY) AS EndY FROM
(
SELECT a.ID,a.LinkID,X as StartX,Y as StartY,null as EndX,null as EndY
FROM
table1 a JOIN table3 b
ON a.Linkid=b.Linkid
JOIN table2 c
ON b.id=c.id WHERE LinkDirection='Positive'
UNION ALL
SELECT a.ID,a.LinkID,null as StartX,null as StartY,X as EndX,Y as EndYY
FROM
table1 a JOIN table3 b
ON a.Linkid=b.Linkid
JOIN table2 c
ON b.id=c.id WHERE LinkDirection='Negative'
) t
GROUP BY ID,LinkID
This will return
ID LinkID StartX StartY EndX EndY
1 0 100 200 300 400
2 1 NULL NULL 100 200

Related

Complicated SQL query request

I have a table
Number Letter KeyLetter
1 a 1
1 b 0
1 c 0
1 d 0
2 e 0
2 f 0
2 g 0
3 h 1
3 i 1
3 j 0
From it I want this:
Number Letter KeyLetter
1 a 1
2 e 0
2 f 0
2 g 0
3 h 1
3 i 1
For each set of numbers, if a letter is a KeyLetter, I want to ignore any non KeyLetters.
If a set of numbers doesn't have an entry where the letter is a KeyLetter, then show all of the entries in that set of numbers.
What SQL query would be able to do this?
Simple answer, return the rows with KeyLetter = 1, and also those with a Number not having a KeyLetter = 1.
select *
from tablename t1
where t1.KeyLetter = 1
or not exists (select * from tablename t2
where t1.Number = t2.Number
and t2.KeyLetter = 1)
Alternatively:
select t1.*
from tablename t1
join (select Number, max(KeyLetter) maxKeyLetter
from tablename
group by Number) t2
on t1.Number = t2.Number and t1.KeyLetter = t2.maxKeyLetter
Or...
select *
from tablename
where (Number, KeyLetter) in
(select Number, max(KeyLetter)
from tablename
group by Number)
The first two are Core ANSI SQL compliant. The latter one uses extension F641, "Row and table constructors".

Select the row based on the specific key

I have a SQL dataset that looks like this:
SourceId SomeContent
-------------------
1 aaa
2 bbb
3 ccc
4 ddd
SourceId ConditionType CondidionValue
-------------------------------
1 1 2
1 2 200
2 1 3
2 2 201
3 1 4
I need to select the SourceId that have matching specific key,
e.g. (ConditionType=1 and ConditionValue=2) and (ConditionType=2 and ConditionValue=200 ) should return sourceId = 1). Query with specified key can match only one SourceId.
I'm trying to do it this way:
SELECT SourceId
FROM ConditionData
where ConditionType = 2 and ConditionValue = 200
and SourceId in(
SELECT SourceId
FROM ConditionData
where (ConditionType = 1 and ConditionValue = 2))
Is there more elegant query to get it?
You could use aggregation:
SELECT SourceId
FROM ConditionData
WHERE (ConditionType = 2 and ConditionValue = 200)
OR (ConditionType = 1 and ConditionValue = 2)
GROUP BY SourceId
HAVING COUNT(1) = 2 -- Alternatively: COUNT(1) > 1
I think you can use INNER JOIN for each condition
SELECT DISTINCT t1.SourceId
FROM table1 AS t1
INNER JOIN table2 AS condition1 ON t1.SourceId = condition1.SourceId AND condition1.ConditionType = 1 AND condition1.CondidionValue = 2
INNER JOIN table2 AS condition2 ON t1.SourceId = condition2.SourceId AND condition2.ConditionType = 2 AND condition2.CondidionValue = 200

SQL update with aggregate in WHERE clause

I'm trying to set the date field for column date to let's say '10/11/2012' in table 1 when the sum of all amounts table 2 related to that id (via fk_id) = 0. Here's what I mean:
FROM:
table 1
id date
1 10/11/2011
2
3 10/12/2011
table 2
fk_id amount
1 200
2 0
2 0
3 100
TO:
table 1
id date
1 10/11/2011
2 10/11/2012
3 10/12/2011
table 2
fk_id amount
1 200
2 0
2 0
3 100
This is what I have currently:
update table1
set date = '10/11/2012
FROM table1 inner join table 2 on table1.id = table2.fk_id
HAVING sum(table2.amount) = 0
Can someone help me out here?
UPDATE table1
SET date = '10/11/2012'
FROM table1
WHERE id IN (SELECT FK_ID FROM table2 GROUP BY FK_ID HAVING SUM(Amount)=0)
This should work:
UPDATE T1
SET [date] = '20121011'
FROM table1 T1
INNER JOIN (SELECT fk_id, SUM(amount) Amount
FROM table2
GROUP BY fk_id
HAVING SUM(amount) = 0) T2
ON T1.id = T2.fk_id

dynamic operations with 2 tables and 1 insert SQL Server

I have 2 tables:
table1
id someval someatt
-------------------
1 23 name1
2 56 name2
3 76 name3
4 456 name4
5 53 name5
6 67 name6
7 12 name7
8 43 name8
9 99 name9
10 567 name10
table2
id someval someatt
-------------------
1 23.3 name1
2 5.6 name2
3 8.76 name3
4 4.56 name4
5 5.3 name5
6 6.7 name6
7 1.2 name7
8 4.3 name8
9 9.9 name9
10 56.7 name10
I need to insert to a new table some operations of various fields of both tables so, for example
iteration1
x = get value from table1 where id 1
y = get value from table1 where id 2
a = get value from table2 where id 1
b = get value from table2 where id 2
iteration2
r = get value from table1 where id 2
s = get value from table1 where id 3
u = get value from table2 where id 2
v = get value from table2 where id 3
iterationn.
q = get value from table1 where id n-1
p = get value from table1 where id n
o = get value from table2 where id n-1
e = get value from table2 where id n
Then insert into NEWTABLE
(a*b + x+y), (r*s + u*v) ...(q*p+o*e)
sO I was thinking (IF I have to do this 100 times):
SET #counter = 1;
SET #template = '';
SET #N = 100;
WHILE(#counter < #N)
Select #x = value from table 1 where id = #counter
Select #y = value from table 1 where id = #counter + 1
Select #a = value from table 2 where id = #counter
Select #b = value from table 2 where id = #counter + 1
#template = #template + ' (#x*#y + #a*#b), '
end
so at the end of the loop I have a full template
and then EXEC(#template) ,
How could you optimize this?
How to do something like I described?
(table1 and table2 are samll examples of my tables)
Is there a way The 4 select
statements are avoided?
output table:
result1 result2 result3 .... result100
---------------------------------------
float float float ... float
where float is a result of calculating (a*b + x+y) for each value in table1 and table2
This will work with SQL 2005 & up, using the same data you listed.
SELECT t1x.id AS smaller_id,
( t1x.someval * t1y.someval ) + ( t2a.someval * t2b.someval ) AS result
FROM dbo.table1 AS t1x
INNER JOIN dbo.table1 AS t1y ON t1x.id + 1 = t1y.id
INNER JOIN dbo.table2 AS t2a ON t2a.id = t1x.id
INNER JOIN dbo.table2 AS t2b ON t2b.id = t1y.id
If you want it horizontal, you'll have to PIVOT the results.
SELECT 'Calculation Result' AS CalcRes,
[result1], [result2], [result3], [result4], [result5], [result6], [result7], [result8], [result9]
FROM (
SELECT 'result' + cast(t1x.id AS varchar(4)) AS result_name,
( t1x.someval * t1y.someval ) + ( t2a.someval * t2b.someval ) AS result
FROM dbo.table1 AS t1x
INNER JOIN dbo.table1 AS t1y ON t1x.id + 1 = t1y.id
INNER JOIN dbo.table2 AS t2a ON t2a.id = t1x.id
INNER JOIN dbo.table2 AS t2b ON t2b.id = t1y.id
) AS Results
PIVOT (
min( result ) --there needs to be an aggregate function here
FOR result_name IN ([result1], [result2], [result3], [result4], [result5], [result6], [result7], [result8], [result9])
) AS PivotedResults
You'll need to use dynamic SQL for this, because you need to know the names of your result colums before you pivot.
Join all the records together:
insert
NEWTABLE (theid, newval)
select
t1_p.id as theid
(t2_p.someval * t2_n.someval) + (t1_p.someval * t1_n.someval) as newval
from
Table1 t1_p
inner join
Table1 t1_n on t1_p.id + 1 = t1_n.id
inner join
Table2 t2_p on t1_p.id = t2_p.id
inner join
Table2 t2_n on t1_n.id = t2_n.id
Not sure I understand your question fully but....
;with cte1 as
(
select
T1_1.id,
T1_1.someval as x,
T1_2.someval as y
from #T1 as T1_1
inner join #T1 as T1_2
on T1_1.id = T1_2.id-1
),
cte2 as
(
select
T2_1.id,
T2_1.someval as a,
T2_2.someval as b
from #T2 as T2_1
inner join #T2 as T2_2
on T2_1.id = T2_2.id-1
)
select (a*b + x*y)
from cte1 as T1
inner join cte2 as T2
on T1.id = T2.id
Might you try something like
INSERT INTO SomeTable
SELECT
(x.value * y.value) + (a.value * b.value)
FROM
Table1 x
Table1 y on y.id = x.id + 1
Table2 a on a.id = x.id
Table2 b on b.id = x.id + 1
WHERE
x.Id = #counter

Design SQL Query for following case

Consider tables
Table1
id, name
1 xyz
2 abc
3 pqr
Table2
id title
1 Mg1
2 Mg2
3 SG1
Table3
Tb1_id tb2_id count
1 1 3
1 2 3
1 3 4
2 2 1
3 2 2
3 3 2
I want to do query to give result like
id title
1 MG1
2 MG2
3 Two or More Title
MG1 has higher preference if MG1 and count >= 1 then it is given as MG1 title , for others corresponding title is used and for count > 1 as two or more
I think this is what you are going for:
select t3.Tb1_id as id,
case
when mg1cnt.count >= 1 then 'MG1'
when cnt.count = 1 then upper(t2.title)
else 'Two or More Titles'
end as title
from (
select Tb1_id, count(*) as count
from Table3
group by Tb1_id
) cnt
inner join (
select Tb1_id, isnull(SUM(case when t2.title='mg1' then 1 end), 0) as count
from Table3 t3
inner join Table2 t2 on t3.tb2_id = t2.id
group by Tb1_id
) as mg1cnt on cnt.Tb1_id = mg1cnt.Tb1_id
inner join Table3 t3 on cnt.Tb1_id = t3.Tb1_id
inner join Table2 t2 on t3.tb2_id = t2.id
group by t3.Tb1_id,
case
when mg1cnt.count >= 1 then 'MG1'
when cnt.count = 1 then upper(t2.title)
else 'Two or More Titles'
end