dynamic operations with 2 tables and 1 insert SQL Server - sql

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

Related

how to accumulate values in SQL in one column based on another column?

I am trying to accumulate the results in the first table below containing distinct ItemID based on the quantities and multipliers in second table. I tried UPDATE records and
SET ItemCount = ItemCount + ((SELECT [Multiplier] FROM Table2 WHERE Table1.[ItemID] = Table2.[Item1ID]) * (SELECT [Item1Qty] FROM Table2 WHERE Table1.[ItemID] = Table2.[Item1ID])) + ((SELECT [Multiplier] FROM Table2 WHERE Table1.[ItemID] = Table2.[Item2ID]) * (SELECT [Item2Qty] FROM Table2 WHERE Table1.[ItemID] = Table2.[Item2ID]))
but this failed because the SELECT statement returns multiple values. What is the most efficient way to get the results shown in table3
ItemID ItemCount
10001
10002
10003
10004
Item1ID Item1Qty Item2ID Item2Qty Multiplier
10001 1 10003 3 4
10004 3 10002 5 2
10003 3 10001 4 3
ItemID ItemCount
10001 16
10002 10
10003 21
10004 6
One way is to use union all to count total quantity for each item. Then update table1
with cte as (
select
itemID, totalQty = sum(qty)
from (
select itemID, qty = item1Qty * Multiplier from table2
union all select itemID, item2Qty * Multiplier from table2
) t
group by itemID
)
update a
set b.ItemCount = b.qty
from
table1 a
join cte b on a.itemID = b.itemID
This will work :
Declare #Table as Table (Item1ID varchar(10),Item1Qty int,Item2ID varchar(10),Item2Qty int,Multiplier int)
Insert into #Table Values
('10001',1,'10003',3,4),
('10004',3,'10002',5,2),
('10003',3,'10001',4,3)
Declare #Table1 as Table (Item1ID varchar(10),ItemCount int)
Insert into #Table1 Values
('10001',NULL),
('10002',NULL),
('10003',NULL),
('10004',NULL)
;With T AS
(
Select Item1ID,Item1Qty,Multiplier from #Table
UNION
Select Item2ID,Item2Qty,Multiplier from #Table
)
Update T set T.ItemCount = S.ItemCount from #Table1 T
Inner Join (
Select Item1ID,SUM(Item1Qty*Multiplier) 'ItemCount' from T
Group by Item1ID
) S on S.Item1ID = T.Item1ID
Working sample
UPDATE T3
SET T3.ItemCount = ISNULL(T3.ItemCount,0) + ((T2.Multiplier * T1.Item1Qty) + (T2.Multiplier * T2.Item2Qty))
FROM Table3 T3
INNER JOIN Table1 AS T1 ON T1.Item1ID = T3.ItemID
INNER JOIN Table2 AS T2 On T2.Item2ID = T1.Item1ID

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

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

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

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)

SQL: 3 self-joins and then join them together

I have 2 tables to join in a specific way. I think my query is right, but not sure.
select t1.userID, t3.Answer Unit, t5.Answer Demo
FROM
table1 t1
inner join (select * from table2) t3 ON t1.userID = t3.userID
inner join (select * from table2) t5 ON t1.userID = t5.userID
where
NOT EXISTS (SELECT * FROM table1 t2 WHERE t2.userID = t1.userID AND t2.date > t1.date)
and NOT EXISTS (SELECT * FROM table2 t4 WHERE t4.userID = t3.userID and t4.counter > t3.counter)
and NOT EXISTS (SELECT * FROM table2 t6 WHERE t6.userID = t5.userID and t6.counter > t5.counter)
and t1.date_submitted >'1/1/2009'
and t3.question = Unit
and t5.question = Demo
order by
t1.userID
From table1 I want distinct userID where date > 1/1/2009
table1
userID Date
1 1/2/2009
1 1/2/2009
2 1/2/2009
3 1/2/2009
4 1/1/2008
So The result I want from table1 should be this:
userID
1
2
3
I then want to join this on userID with table2, which looks like this:
table2
userID question answer counter
1 Unit A 1
1 Demo x 1
1 Prod 100 1
2 Unit B 1
2 Demo Y 1
3 Prod 100 1
4 Unit A 1
1 Unit B 2
1 Demo x 2
1 Prod 100 2
2 Unit B 2
2 Demo Z 2
3 Prod 100 2
4 Unit A 2
I want to join table1 with table2 with this result:
userID Unit Demo
1 B X
2 B Z
In other words,
select distinct userID from table2 where question = Unit for the highest counter
and then
select distinct userID from table2 where question = Demo for the highest counter.
I think what I've done is 3 self-joins then joined those 3 together.
Do you think it's right?
SELECT du.userID, unit.answer, demo.answer
FROM (
SELECT DISTINCT userID
FROM table1
WHERE date > '1/1/2009'
) du
LEFT JOIN
table2 unit
ON (userID, question, counter) IN
(
SELECT du.userID, 'Unit', MAX(counter)
FROM table2 td
WHERE userID = du.userID
AND question = 'Unit'
)
LEFT JOIN
table2 demo
ON (userID, question, counter) IN
(
SELECT du.userID, 'Demo', MAX(counter)
FROM table2 td
WHERE userID = du.userID
AND question = 'Demo'
)
Having an index on table2 (userID, question, counter) will greatly improve this query.
Since you mentioned SQL Server 2005, the following will be easier and more efficient:
SELECT du.userID,
(
SELECT TOP 1 answer
FROM table2 ti
WHERE ti.user = du.userID
AND ti.question = 'Unit'
ORDER BY
counter DESC
) AS unit_answer,
(
SELECT TOP 1 answer
FROM table2 ti
WHERE ti.user = du.userID
AND ti.question = 'Demo'
ORDER BY
counter DESC
) AS demo_answer
FROM (
SELECT DISTINCT userID
WHERE date > '1/1/2009'
FROM table1
) du
To aggregate:
SELECT answer, COUNT(*)
FROM (
SELECT DISTINCT userID
FROM table1
WHERE date > '1/1/2009'
) du
JOIN table2 t2
ON t2.userID = du.userID
AND t2.question = 'Unit'
GROUP BY
answer