Update data where ID match and use case to choose what data - sql

I have two tables
T1:
ID, Truck, Trailer
1 null null
2 null null
T2:
ID, Type, ResourceID
1 R 111
1 F 222
1 D 333
2 R 444
2 F 555
I need a result where
ID, Truck, Trailer
1 111 222
2 444 555
How can I update T1.Truck = T2.ResourceID when T2.Type = R and T1.Trailer = T2.ResourceID when T2.Type = F where T1.ID = T2.ID.
This is what I have so far
UPDATE T1
SET T1.Truck = CASE
WHEN T2.Type = 'R' THEN T2.ResourceId
ELSE T1.Truck
END,
T1.Trailer = CASE
WHEN T2.Type = 'F' THEN T2.ResourceId
ELSE T1.Trailer
END
FROM T1 INNER JOIN (SELECT Id, Type, ResourceId
FROM T2) T2
ON T1.Id = T2.Id
This will only Truck, but not trailer.
What am I missing?

The problem with your current update query is that the update will update one column to null as it can't match both conditions at the same time.
If you did a select * instead of the update the result would look like:
ID Truck Trailer Id Type ResourceId
1 NULL NULL 1 R 111 -- this will set R = 111 and F = null
1 NULL NULL 1 F 222 -- this will set F = 222 and R = null
1 NULL NULL 1 D 333 -- this will set R = null and F = null
2 NULL NULL 2 R 444 -- this will set R = 444 and F = null
2 NULL NULL 2 F 555 -- this will set R = null and F = 555
Here you can see that when Type matches R the update for F will update to null et cetera.
One solution is to join the T2 table twice:
UPDATE T1
SET
T1.Truck = T2.ResourceId
,
T1.Trailer = T3.ResourceId
FROM T1
INNER JOIN (SELECT Id, ResourceId FROM T2 WHERE Type = 'R') T2 ON T1.Id = T2.Id
INNER JOIN (SELECT Id, ResourceId FROM T2 WHERE Type = 'F') T3 ON T1.Id = T3.Id
If there might not always be both types (R,F) then use left join instead of inner join and check for null values.
Edit: thinking a bit more gives this query:
UPDATE T1
SET
T1.Truck = ISNULL(T.rValue, T1.Truck),
T1.Trailer = ISNULL(T.fValue, T1.Trailer)
FROM T1
INNER JOIN (
SELECT
Id,
rValue = MAX(CASE WHEN Type = 'R' THEN ResourceId END),
fValue = MAX(CASE WHEN Type = 'F' THEN ResourceId END)
FROM T2 GROUP BY id
) T ON T1.Id = T.Id
On a side note: using an alias for a derived table that is also a table name can be pretty confusing and should be avoided.

you can PIVOT the table t2 before updating the t1 table
Use the following query to pivot the t2 table.
SELECT ID, R, F
FROM t2
PIVOT (Max(resourceID)
FOR type IN ([R],[F]))pv
Now the result will in the format of t1 table you can easily update using the following query
UPDATE A
SET Trailer = F,
Truck = R
FROM t1 A
INNER JOIN (SELECT ID, R, F
FROM t2
PIVOT (Max(resourceID)
FOR type IN ([R],
[F]))pv) B
ON A.ID = b.ID
SQLFIDDLE DEMO

You can use a JOIN with a condition for each case, so you would JOIN to T2 twice. First on the Id and [Type] = 'R' and again, with [Type] = 'F'.
Here's some runnable sample code:
CREATE TABLE #t1 (id INT, Truck INT, Trailer int)
CREATE TABLE #t2 (id INT, [Type] VARCHAR(1), ResourceId int)
INSERT INTO #t1
( id, Truck, Trailer )
VALUES (1, NULL, NULL),
(2, NULL, NULL)
INSERT INTO #t2
( id, [Type], ResourceId )
VALUES ( 1, 'R', 111),
( 1, 'F', 222),
( 1, 'D', 333),
( 2, 'R', 444),
( 2, 'F', 555)
UPDATE #t1
SET Truck = TR.ResourceId, Trailer = TF.ResourceId
FROM #t1
INNER JOIN #t2 AS TR ON TR.id = #t1.id AND TR.[Type] = 'R'
INNER JOIN #t2 AS TF ON TF.id = #t1.id AND TF.[Type] = 'F'
SELECT * FROM #t1
DROP TABLE #t1
DROP TABLE #t2

Related

SQL Query for events that happend in a specific order

I have the following table:
+--------+-------+------+--+
| Object | Event | Time | |
+--------+-------+------+--+
| Obj1 | A | 1 | |
| Obj1 | B | 3 | |
| Obj2 | A | 7 | |
| Obj2 | B | 4 | |
+--------+-------+------+--+
My goal is to get all objects that both had the event A & B with the condition that A happened first (in time). So far I only came up with the query to find me all objects that had A & B without including the time:
SELECT DISTINCT Object
FROM
(SELECT *
FROM
(SELECT *
FROM table
INNER JOIN
(SELECT Object Obj
FROM table
WHERE event LIKE '%A%' AS temp_table) ON table.Object = temp_table.Obj) AS temp_final
WHERE event LIKE '%B%') AS temp2;
So the end result would be that I get a table that includes only:
Obj1
Since this is the only Object that fulfills all criteria.
The time column is a Date stamp in real life, but for simplicity I used integers.
Thanks you for the help
If you are only tracking two events that happened one after the other, than you can solve this with a single JOIN.
This will work regardless of the number of events Obj1 has, as how you mentioned, you are only interested in A and B existing and being one after the other, respectively.
select distinct t1.object
from TABLE t1
inner join TABLE t2 on t1.object = t2.object
and t2.time > t1.time
and t1.event = 'A'
and t2.event = 'B'
Here is a sample of the result of the code:
declare #tbl table (obj varchar(10), event varchar(1), time int)
insert #tbl values ('Obj1', 'A', 1), ('Obj1', 'B', 3), ('Obj2', 'A', 7), ('Obj2', 'B', 4)
select distinct t1.obj
from #tbl t1
inner join #tbl t2 on t1.obj = t2.obj
and t2.time > t1.time
and t1.event = 'A'
and t2.event = 'B'
Here is a compact solution which should run across most RDBMS. This solution does not assume that there are only two events, and should run for any number of events.
SELECT t1.Object
FROM yourTable t1
INNER JOIN
(
SELECT Object, MIN(Time) AS Time
FROM yourTable
GROUP BY Object
) t2
ON t1.Object = t2.Object AND
((t1.Event = 'A' AND t1.Time = t2.Time) OR
t1.Event <> 'A')
GROUP BY t1.Object
HAVING COUNT(*) = 2 -- change this count to match # of events
Demo on MySQL:
SQLFiddle
Try this:
SELECT DISTINCT object
FROM yourtable t
WHERE EXISTS
(SELECT FROM yourtable t3
WHERE t3.object = t.object
AND t3.event = 'A'
AND EXISTS
(SELECT 'B'
FROM yourtbale t4
WHERE t4.object = t3.object
AND t4.event = 'B'
AND t4.time > t3.time)
)
If you are using sql-server:
SELECT
A.[Object]
, A.[Time]
, B.[Time]
FROM
(SELECT
Distinct [Object]
FROM
[table] AS A
WHERE
A.[Event] = 'A'
) AS A
CROSS APPLY
(SELECT
TOP 1 *
FROM
[table] AS B
WHERE
[Event] = 'B'
AND
B.[Object] = A.[Object]
AND
A.[Time] < B.[Time]) AS B
For SQL Server:
;with A as
(select Object, MIN(Time) as Time from table where Event='A' group by Object)
, B as
(select Object, MIN(Time) aS Time from table where Event='B' group by Object)
Select A.Object from A inner join B on B.Object=A.Object where A.Time < B.Time

SQL multiple results on one row when only one column has different values

I currently have a similar query to this one..
select i.App_Id as ApplicationId,
Cast(i.ObjectId as NVARCHAR(50)) as ObjectId,
1 as ActivityId,
Cast(case
when oh.ObjectId is null then 0
else 1
end as BIT) as Highlight,
iu.UserId as UserId
from table0 i
inner join table1 iu
on i.IdeaID = iu.IdeaID
left join table2 oh
on oh.ObjectId = i.IdeaID
left join table3 mIS
on i.IdeaID = mIS.IdeaID
AND mIS.EndTime is null
inner join table4 mISF
on mISF.StateFluxId = mIS.StateFluxId
where (iu.RelationId = 1 or iu.RelationId = 2)
which is returning, for example:
2 | 1 | 1 | 1 | 1
2 | 1 | 1 | 1 | 2
2 | 1 | 1 | 1 | 3
I'm trying to change it in order to merge the results of the 5th column when the other column values are the same:
2 | 1 | 1 | 1 | 1,2,3
Is this possible? Didn't manage to accomplish it using the Stuff function..
Thanks!
Have you tried like this,
SELECT DISTINCT i.App_Id AS ApplicationId
,Cast(i.ObjectId AS NVARCHAR(50)) AS ObjectId
,1 AS ActivityId
,Cast(CASE
WHEN oh.ObjectId IS NULL
THEN 0
ELSE 1
END AS BIT) AS Highlight
,
--iu.UserId as UserId
(stuff(SELECT ',' + userid FROM table1 WHERE Ideaid = iu.IdeaId FOR XML path(''), 1, 1, '')) AS UserId
FROM table0 i
INNER JOIN table1 iu ON i.IdeaID = iu.IdeaID
LEFT JOIN table2 oh ON oh.ObjectId = i.IdeaID
LEFT JOIN table3 mIS ON i.IdeaID = mIS.IdeaID
AND mIS.EndTime IS NULL
INNER JOIN table4 mISF ON mISF.StateFluxId = mIS.StateFluxId
WHERE (
iu.RelationId = 1
OR iu.RelationId = 2
)
Based on your code I have added the XML PATH () .Please do necessary changes according to your requirement
select i.App_Id as ApplicationId,
Cast(i.ObjectId as NVARCHAR(50)) as ObjectId,
1 as ActivityId,
Cast(case
when oh.ObjectId is null then 0
else 1
end as BIT) as Highlight,
stuff(
(
SELECT ',' + CAST(IU.USERID AS VARCHAR(10))
FROM table1 t2 WHERE iu.IdeaID = t2.IdeaID
FOR XML PATH('')
)
,1,1,'') AS USERID
from table0 i
inner join table1 iu
on i.IdeaID = iu.IdeaID
left join table2 oh
on oh.ObjectId = i.IdeaID
left join table3 mIS
on i.IdeaID = mIS.IdeaID
AND mIS.EndTime is null
inner join table4 mISF
on mISF.StateFluxId = mIS.StateFluxId
where (iu.RelationId = 1 or iu.RelationId = 2)
GROUP BY i.App_Id
,i.ObjectId,
oh.ObjectId

how can I swap two records in sql server with script

I want swap two records in sql server for example
How can i do it?
You can do it in one statement with JOIN like this
UPDATE t1
SET t1.id = t2.id
FROM table1 t1 JOIN table1 t2
ON (t1.id = 1 AND t2.id = 2)
OR (t1.id = 2 AND t2.id = 1)
Output after update:
| ID | NAME | FAMILY |
|----|------|--------|
| 1 | Mary | Simson |
| 2 | Jame | Ander |
Here is SQLFiddle demo
SELECT
*,CASE WHEN id=123 then 987 ELSE 123 END AS JoinId
INTO #Temp
FROM YourTable
WHERE ID in (123,987)
--swap values
UPDATE y
SET col1=t.col1
,col2=t.col2
FROM YourTable y
INNER JOIN #Temp t ON y.id =t.JoinId
WHERE ID in (123,987)
in the case that ID is identity you could use a combined solution between #Vaibs_Cool and #user814064
something like this
DECLARE #aID INT, #bID INT
SELECT #aID = 123, #bID = 987
;WITH ToSwap AS
(
SELECT CASE WHEN id = #aID THEN #bID ELSE #aID END AS id, [Name], [Family]
FROM YourTable
WHERE id IN (#aID, #bID)
)
UPDATE YourTable
SET [Name]=ToSwap.[Name], [Family] = ToSwap.[Family]
FROM YourTable
INNER JOIN ToSwap ON YourTable.id =ToSwap.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

Join and a Pivot statement SQL Server

I want to pivot and join to select from 3 tables
Table 1: INT,VARCHAR,FLOAT
ID Name value
---------------------------
1 a1 32116580
2 a2 50785384
3 a3 54327508
4 a4 61030844
Table 2: INT, VARCHAR, FLOAT
ID Name value
---------------------------
1 x11 61326085092
2 x12 80368184260
3 x13 83023398776
4 x14 91144307692
5 x22 95486535484
6 x23 90357090612
7 x24 100588807668
8 x33 707811916752
9 x34 93128452928
10 x44 84566653668
Table 3: INT, VARCHAR, FLOAT
ID Name value
---------------------------
1 q1 61326085092
2 q2 95486535484
3 q3 707811916752
4 q4 84566653668
output table:
column1 column2 column3 column4
--------------------------------------------------------------------------
a1*a1/(q1+q1+x11) a1*a2/(q1+q2+x12) a1*a3/(q1+q3+x13) a1*a4/(q1+q4+x14)
null a2*a2/(q2+q2+x22) a2*a3/(q2+q3+x23) a2*a4/(q2+q4+x24)
null null a3*a3/(q3+q3+x339 a3*a4/(q3+q4+x34)
null null null a4*a4/(q4+q4+x44)
(I'm putting the 'Name' of the column of the 3 different tables instead of numbers)
How to do this?
I guess I have to do two pivots? and
unpivot?...
Well do not how to complete it..
SELECT *
FROM (
SELECT
t1.a1,
t1.a2,
t2.x,
t3.q
FROM table1 t1
INNER JOIN table2 t2
ON t1.id = t2.id
...
) Output
PIVOT (
name IN (
...
PIVOT(name ... )
)
) PivotTable
UPDATE
Previously I have *'s I have changed it to division and sum, the *'s were just an example,
Sample tables
create table Table1(ID int, Name varchar(10), value float)
insert table1 select
1 ,'a1', 32116580 union all select
2 ,'a2', 50785384 union all select
3 ,'a3', 54327508 union all select
4 ,'a4', 61030844
create table Table2(ID int, Name varchar(10), value float)
insert Table2 select
1 ,'x11', 61326085092 union all select
2 ,'x12', 80368184260 union all select
3 ,'x13', 83023398776 union all select
4 ,'x14', 91144307692 union all select
5 ,'x22', 95486535484 union all select
6 ,'x23', 90357090612 union all select
7 ,'x24', 100588807668 union all select
8 ,'x33', 707811916752 union all select
9 ,'x34', 93128452928 union all select
10 ,'x44', 84566653668
create table Table3(ID int, Name varchar(10), value float)
insert Table3 select
1 ,'q1', 61326085092 union all select
2 ,'q2', 95486535484 union all select
3 ,'q3', 707811916752 union all select
4 ,'q4', 84566653668
The query you need, for N = 4. For any other N, just use dynamic SQL to build the query, changing the 2 lines required as indicated by **.
;with coords(i,row,col,total,N) as (
select 1,1,1,N.N*(N.N+1)/2, N.N
from (select count(*) N from table1) N
union all
select i+1,
case when col+1>N then row+1 else row end,
case when col+1>N then row+1 else col+1 end,
total, N
from coords
where i<total
)
select [1],[2],[3],[4] -- **, e.g. ,[5],[6],etc
from
(
select
c.row,
c.col,
cellvalue= ar.value*ac.value/(qr.value+qc.value+x.value)
from coords c
inner join table1 ar on ar.id = c.row
inner join table1 ac on ac.id = c.col
inner join table3 qr on qr.id = c.row
inner join table3 qc on qc.ID = c.col
inner join table2 x on x.ID = c.i
) p
pivot (max(cellvalue) for col in ([1],[2],[3],[4])) pv -- **
order by row
Output:
1 2 3 4
---------------------- ---------------------- ---------------------- ----------------------
5606.50338459295 6876.83326310711 2047.51559459649 8269.17991568225
NULL 9003.55641750708 3087.36780924588 11044.2303130135
NULL NULL 1389.95405212248 3744.35614651666
NULL NULL NULL 14681.7678040306
The dynamic version
declare #Sql nvarchar(max)
select #Sql = ISNULL(#sql + ',', '') + QUOTENAME(RIGHT(number,10))
from master..spt_values
where type='P' and number between 1 and (select COUNT(*) From table1)
set #Sql = '
;with coords(i,row,col,total,N) as (
select 1,1,1,N.N*(N.N+1)/2, N.N
from (select count(*) N from table1) N
union all
select i+1,
case when col+1>N then row+1 else row end,
case when col+1>N then row+1 else col+1 end,
total, N
from coords
where i<total
)
select ' + #sql + '
from
(
select
c.row,
c.col,
cellvalue= ar.value*ac.value/(qr.value+qc.value+x.value)
from coords c
inner join table1 ar on ar.id = c.row
inner join table1 ac on ac.id = c.col
inner join table3 qr on qr.id = c.row
inner join table3 qc on qc.ID = c.col
inner join table2 x on x.ID = c.i
) p
pivot (max(cellvalue) for col in (' + #sql + ')) pv
order by row
option (maxrecursion 0) -- ! use with caution
'
exec(#sql)