Join and a Pivot statement SQL Server - sql

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)

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

Optimized SQL Query to retrieve a Particular set of records from Microsoft SQL Server DB

I want to retrieve the set of data from a column in the table.
My Scenario is:
Iam having a table with name table1_data , In that table there is a Column with name "clm_Name", The data in the column is like this
a
b
c
a
b
c
a
b
a
b
c
a
a
b
c
I want to retrieve the data when a b c are in order if order changes it should not retrieve.(i.e, If we write a query on given data the output should be a b c a b c a b a b c a a b c) only the bolded letters should be shown in output.
If you have a column to sort you can do as follows:
DECLARE #Tbl TABLE (OrderId INT, val NVARCHAR(1))
INSERT INTO #Tbl
VALUES
(1,'a'),
(2,'b'),
(3,'c'),
(4,'a'),
(5,'b'),
(6,'c'),
(7,'a'),
(8,'b'),
(9,'a'),
(10,'b'),
(11,'c'),
(12,'a'),
(13,'a'),
(14,'b'),
(15,'c')
;WITH CTE
AS
(
SELECT
*,
ROW_NUMBER() OVER (ORDER BY (SELECT OrderId)) RowId
FROM #Tbl
), Result
AS
(
SELECT
CurrRow.RowId
FROM
CTE CurrRow LEFT JOIN
(SELECT CTE.val , CTE.RowId - 1 RowId FROM CTE) NextRow ON CurrRow.RowId = NextRow.RowId LEFT JOIN
(SELECT CTE.val , CTE.RowId + 1 RowId FROM CTE) PrivRow ON CurrRow.RowId = PrivRow.RowId
WHERE
PrivRow.val = 'a' AND
CurrRow.val = 'b' AND
NextRow.val = 'c'
)
SELECT
*
FROM
CTE C
WHERE
C.RowId IN (
SELECT Result.RowId FROM Result
UNION ALL
SELECT Result.RowId - 1 FROM Result
UNION ALL
SELECT Result.RowId + 1 FROM Result
)
ORDER BY C.OrderId
Output:
OrderId val RowId
1 a 1
2 b 2
3 c 3
4 a 4
5 b 5
6 c 6
9 a 9
10 b 10
11 c 11
13 a 13
14 b 14
15 c 15

How to get the Count of the subgroup in SQL

How can I get the Count of the subgroup. I have Table1 and Table2 (below). How can I get the table Result. I tired group by but only manage to get the total rows. I am trying it in Microsoft SQL.
Table1
ID PriID Function
1 500 A
2 500 B
3 500 C
4 501 A
5 501 B
6 502 C
7 503 A
Table2
PriID Color
500 Green
501 Red
502 Green
503 Green
Result
Function Green Red Total
A 2 1 3
B 1 1 2
C 2 0 2
below is the current one I tried
SELECT t1.Function, Count(t1.PriID) as Total FROM Table1 t1
LEFT JOIN Table2 t2 on t1.PriID = t2.PriID
GROUP BY t1.function
and I get this
Result
Function Total
A 3
B 2
C 2
Try this
SELECT t1.Function,
SUM(CASE WHEN Color = 'Green' THEN 1 ELSE 0 END) AS Green,
SUM(CASE WHEN Color = 'Red' THEN 1 ELSE 0 END) AS Red,
Count(t1.PriID) as Total FROM Table1 t1
LEFT JOIN Table2 t2 on t1.PriID = t2.PriID
GROUP BY t1.function
This is the best approach for doing this stuff
;with cte as
(
select [Function],t1.priID,color
from tbl1 t1
join tbl2 t2 on t1.priID = t2.priid
),def as
(
select [Function],[Green],[Red]
from
(
select [Function],color,priID from cte) dk
Pivot (count(priID) for color in([Green],[Red] )
) pvt
) select *,green+red [Total] from def
select [function], ISNULL(Green, 0) Green, ISNULL(Red, 0) Red,
ISNULL(Green, 0) + ISNULL(Red, 0) Total
from
(
select *, count([function]) 'X' from
(
select t2.color, t1.[function] from table1 t1
JOIN table2 t2 on t1.prid = t2.prid
)A
group by color, [function]
)B pivot (max(X) for color IN ([Green],[Red]))as d
Try this:
;with cte as
(select [function],
Sum(CASE WHEN t1.PriId <> 501 Then 1 Else 0 END) over(partition by [function] order by t1.priid) Green,
Sum(CASE WHEN t1.PriId = 501 Then 1 Else 0 END) over(partition by [function] order by t1.priid) Red,
Count(*) over (partition by [function] order by t1.priid) Total,
Row_Number() over (partition by [function] order by t1.priid desc) rn
from
table1 t1
left join table2 t2 on t1.priid = t2.priid)
select [function],green,red,total
from cte
where rn = 1
This query uses windowing functions (available from SQL Server 2005 onwards), which eliminates the need for a GROUP BY clause
Demo
Hi you should use PIVOT to get result. Like this:
CREATE TABLE #table (id int, priID int, [FUNCTION] varchar(5))
INSERT INTO #table ( id,priID,[FUNCTION] )
VALUES ( 1, 500,'a' ), ( 2, 500,'b' ), ( 3, 500,'c' ), ( 4, 501,'a' ), ( 5, 501,'b' ), ( 6, 502,'c' )
CREATE TABLE #table2 (priID int, color varchar(20))
INSERT INTO #table2 (priID,color )
VALUES ( 500,'green' ), ( 501, 'red' ), ( 502,'yellow' )
SELECT t.[FUNCTION], t2.color, COUNT(t.priID) AS cnt
INTO #result
FROM #table AS T
INNER JOIN #table2 AS T2 ON T2.priID = T.priID
GROUP BY t.[FUNCTION], t2.color
SELECT [FUNCTION], green, red, yellow
FROM ( SELECT [FUNCTION], color, cnt
FROM #result AS R) AS p
PIVOT ( MAX(cnt) FOR color IN (green, red, yellow)) AS pvt
http://rextester.com/ROPBBS57014
The best way for all records in table (If you edit, delete or insert new one) is:
With t (F,PriID,Color) as
(
SELECT Table1.F, Table2.PriID, Table2.Color
FROM Table1 INNER JOIN
Table2 ON Table1.PriID = Table2.PriID
GROUP BY Table2.PriID,F,Color)
select F,Color,COUNT(F) as total from t group by F,Color
And you get this:
Result
Function Color total
A Green 2
B Green 1
C Green 2
A Red 1
B Red 1

duplicate entry in union

I have three tables:
1. Flat Discount
2. Promotion
3. weeklyorder
When i join these table and take union i got 2 row with same data but one different .. how to merge it to show only one row.
Query:
SELECT skuMaster.SKU,
(skuMaster.MinimumStock - COUNT(*)) as ReorderQuantity,
'LowInventory' as descp
FROM SKUMaster skuMaster
JOIN InventoryMaster inventoryMaster ON skuMaster.SKU = inventoryMaster.SKU
GROUP BY skuMaster.sku, skuMaster.MinimumStock, skuMaster.Name
HAVING COUNT(*) < skuMaster.MinimumStock
UNION
SELECT WeeklyOrderList.SKU,
WeeklyOrderList.Quantity as ReorderQuantity,
'NoPO' as descp
FROM WeeklyOrderList
WHERE WeeklyOrderList.POCGen = 'true'
result :
SKU ReorderQuantity descp
1 1 LowInventory
2 2 LowInventory
2 2 NoPO
6 5 LowInventory
here 2nd And 3rd are alomost same only description is different.
can we combine them and show only one row with descp as lowinventory and NOPO
SKU ReorderQuantity descp
1 1 LowInventory
2 2 LowInventory NoPo
6 5 LowInventory
same as above suppose we have table below
SKU ReorderQuantity
1 1
2 5
2 10
6 5
here output should be Max reorder quantity of same sku
Result:
SKU ReorderQuantity
1 1
2 10
6 5
;WITH CTE AS
(
SELECT skuMaster.SKU,
(skuMaster.MinimumStock - COUNT(*)) as ReorderQuantity,
'LowInventory' as descp
FROM SKUMaster skuMaster
JOIN InventoryMaster inventoryMaster ON skuMaster.SKU = inventoryMaster.SKU
GROUP BY skuMaster.sku, skuMaster.MinimumStock, skuMaster.Name
HAVING COUNT(*) < skuMaster.MinimumStock
UNION
SELECT WeeklyOrderList.SKU,
WeeklyOrderList.Quantity as ReorderQuantity,
'NoPO' as descp
FROM WeeklyOrderList
WHERE WeeklyOrderList.POCGen = 'true'
)
SELECT DISTINCT
a.SKU,
a.ReorderQuantity,
descp = STUFF((SELECT ', ' + b.descp
FROM CTE b
WHERE b.ReorderQuantity = a.ReorderQuantity
FOR XML PATH('')), 1, 2, '')
FROM CTE a
just an example for above output mentioned
DECLARE #t TABLE
(
SKU INT,
ReorderQuantity INT
)
INSERT INTO #t (SKU,ReorderQuantity)
VALUES (1,1), (2,5), (2,10), (6,5)
SELECT t.SKU,tt.Qty
FROM #t t
INNER JOIN (SELECT MAX(ReorderQuantity)as Qty, SKU
FROM #t
GROUP BY SKU) tt
ON tt.SKU = t.SKU
GROUP BY t.SKU,tt.Qty

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