How restart the incremenal from a temp table in SQL - sql

I want to try to do an incremental number for a table, that has to return to 0 when seeing from the previous column (LAG) 0.
This is what I tried to do:
DROP TABLE IF EXISTS #a
DROP TABLE IF EXISTS #b
CREATE table #a (
aa varchar(50),
bb varchar(50) )
CREATE table #b (
bb varchar(50)
)
INSERT INTO #a
SELECT 'PR1','D10'
UNION SELECT 'PR1','D20'
UNION SELECT 'PR1','D30'
UNION SELECT 'PR1','D40'
UNION SELECT 'PR1','D80'
UNION SELECT 'PR1','D90'
UNION SELECT 'PR2','D50'
UNION SELECT 'PR2','D60'
UNION SELECT 'PR3','D70'
INSERT INTO #b
SELECT 'D30'
UNION SELECT 'D60'
;WITH tablee (a,b,c,d)
AS
(
SELECT #a.*, CASE WHEN #b.bb is NULL THEN 1 ELSE 0 END xx
--,RANK () OVER (PARTITION BY PR ORDER bY PR)
,SUM (CASE WHEN #b.bb is NULL THEN 1 ELSE 0 END) OVER ( PARTITION BY aa ORDER BY aa,#a.bb) - CASE WHEN #b.bb is NULL THEN 1 ELSE 0 END
FROM #a
left join #b
on #a.bb=#b.bb
)
SELECT * FROM tablee
----------
a b c d
PR1 D10 1 0
PR1 D20 1 1
PR1 D30 0 2
PR1 D40 1 2
PR1 D80 1 3
PR1 D90 1 4
PR2 D50 1 0
PR2 D60 0 1
PR3 D70 1 0
----------
And this is what I am expecting to get out:
----------
a b c d
PR1 D10 1 0
PR1 D20 1 1
PR1 D30 0 2
PR1 D40 1 0
PR1 D80 1 1
PR1 D90 1 2
PR2 D50 1 0
PR2 D60 0 1
PR3 D70 1 0
I'm not familiar with the WITH common_table_expression is the right way to solve my problem?

You can use apply to fill blank value to next c :
with cte as (
select a.aa, a.bb, b.bb as c
from #a a left join
#b b
on b.bb = a.bb
)
select c.aa, c.bb,
(case when c.c is null then 1 else 0 end) as c,
row_number() over (partition by c.aa, ct.c order by c.aa) - 1 as d
from cte c outer apply
( select top (1) c1.*
from cte c1
where c1.aa = c.aa and c1.c is not null and c1.bb >= c.bb
order by c1.c
) ct
order by c.aa, c.bb;

Related

Recursive CTE - recalculate the tree after exclusions

Lets say I have a table called #OrgList
CREATE TABLE #OrgList (
OrgUnitId int,
ParentOrgUnitId int,
PersonId int,
isExcluded bit
);
INSERT INTO #OrgList(OrgUnitId, ParentOrgUnitId, PersonId, isExcluded) VALUES
(1, NULL, 100, 0), (2,1, 101, 0), (3,1,102,0), (4,2,103,1), (5,2,104,0), (6,3,105,0), (7,4,106,0), (8,4,107,0), (9,4,108,0), (10,4,109,0), (11,4,110,1), (12,11,111,0)
My hierarchy tree structure looks like this
and my cte like this:
;
with cte as (
select OrgUnitId, ParentOrgUnitId, PersonId, isExcluded , 0 as level_num
from #OrgList
where ParentOrgUnitId is null
UNION ALL
select o.OrgUnitId, o.ParentOrgUnitId, o.PersonId, o.isExcluded , level_num+1 as level_num
from #OrgList o
join cte on o.ParentOrgUnitId=cte.OrgUnitId
)
select * from cte
I exclude OrgUnitId=4 and =11, then I want to update my recursive query that will recalculate the tree and show the new tree details, including level moves (there can be more levels and more consecutive exclusions, of course except the root node):
You should just add a second UNION ALL in your cte:
with cte as (
select OrgUnitId, ParentOrgUnitId, PersonId, isExcluded , 0 as level_num
from #OrgList
where ParentOrgUnitId is null
UNION ALL
select o.OrgUnitId, o.ParentOrgUnitId, o.PersonId, o.isExcluded , level_num+1 as level_num
from #OrgList o
join cte on o.ParentOrgUnitId=cte.OrgUnitId
where cte.isExcluded = 0
UNION ALL
select o.OrgUnitId, cte.ParentOrgUnitId, o.PersonId, o.isExcluded , level_num as level_num
from #OrgList o
join cte on o.ParentOrgUnitId=cte.OrgUnitId
where cte.isExcluded = 1
)
select * from cte
My approach:
Extend your initial CTE with an exclusion counter (ExclusionCount), counting the number of excluded nodes going from root to leaf nodes.
Add another recursive CTE to construct the upward path (cte_upwards) for each leaf node. Now decrement the counter added in the initial CTE.
Use a cross apply to select the first node where the upward path reaches an exlusion count of zero.
Solution:
with cte as -- initial CTE
(
select OrgUnitId,
ParentOrgUnitId,
PersonId,
IsExcluded,
convert(int, IsExcluded) as 'ExclusionCount', -- new counter
0 as 'level_num'
from #OrgList
where ParentOrgUnitId is null
union all
select o.OrgUnitId,
o.ParentOrgUnitId,
o.PersonId,
o.IsExcluded,
cte.ExclusionCount + convert(int, o.isExcluded), -- increment counter
cte.level_num + 1
from #OrgList o
join cte on o.ParentOrgUnitId = cte.OrgUnitId
),
cte_upwards as
(
select cte.OrgUnitId,
cte.ParentOrgUnitId as 'NewParentOrgUnitId',
cte.IsExcluded,
cte.ExclusionCount,
cte.level_num
from cte
where cte.ParentOrgUnitId is not null -- only leaf nodes (not a root)
and not exists ( select top 1 'x' -- only leaf nodes (not an intermediate node)
from cte cp
where cp.ParentOrgUnitId = cte.OrgUnitId )
union all
select cte_upwards.OrgUnitId,
cte.ParentOrgUnitId,
cte.IsExcluded,
cte_upwards.ExclusionCount - cte.IsExcluded, -- decrement counter
cte.level_num
from cte_upwards
join cte
on cte.OrgUnitId = cte_upwards.NewParentOrgUnitId
)
select cte.OrgUnitId,
cte.ParentOrgUnitId,
cte.IsExcluded,
x.NewParentOrgUnitId,
coalesce(x.NewParentOrgUnitId, cte.ParentOrgUnitId) as 'Recalculated'
from cte
outer apply ( select top 1 cu.NewParentOrgUnitId
from cte_upwards cu
where cu.OrgUnitId = cte.OrgUnitId
and cu.ExclusionCount = 0 -- node without excluded parent nodes
order by cu.level_num desc ) x -- select lowest node in upwards path
order by cte.OrgUnitId;
Result:
OrgUnitId ParentOrgUnitId IsExcluded NewParentOrgUnitId Recalculated
----------- --------------- ---------- ------------------ ------------
1 NULL 0 NULL NULL
2 1 0 NULL 1
3 1 0 NULL 1
4 2 1 NULL 2
5 2 0 2 2
6 3 0 3 3
7 4 0 2 2
8 4 0 2 2
9 4 0 2 2
10 4 0 2 2
11 4 1 NULL 4
12 11 0 2 2
I've added a VirtualParentOrgUnitId, which contains the parent with excluded nodes taken into account. I've also added a counter, VirtualDistance, which will report how many real hops there are between this node and it's virtual parent.
VirtualParentOrgUnitId will use the parent's ID if is not excluded, otherwise it will use it's parents's VirtualParentOrgUnitId, which allows chaining of multiple levels.
DROP TABLE IF EXISTS #OrgList
CREATE TABLE #OrgList (
OrgUnitId int,
ParentOrgUnitId int,
PersonId int,
isExcluded bit
);
INSERT INTO #OrgList(OrgUnitId, ParentOrgUnitId, PersonId, isExcluded) VALUES
(1, NULL, 100, 0), (2,1, 101, 0), (3,1,102,0), (4,2,103,1), (5,2,104,0), (6,3,105,0), (7,4,106,0), (8,4,107,0), (9,4,108,0), (10,4,109,0), (11,4,110,1), (12,11,111,0)
DROP TABLE IF EXISTS #Excludes
CREATE Table #Excludes (
OrgUnitId int
);
INSERT INTO #Excludes VALUES (4), (11);
with cte as (
select OrgUnitId, ParentOrgUnitId, ParentOrgUnitId VirtualParentOrgUnitId, 1 as VirtualDistance , PersonId, isExcluded , 0 as level_num
from #OrgList
where ParentOrgUnitId is null
UNION ALL
select o.OrgUnitId, o.ParentOrgUnitId, IIF(o.ParentOrgUnitId IN (SELECT OrgUnitId FROM #Excludes),cte.VirtualParentOrgUnitId, o.ParentOrgUnitId ), IIF(o.ParentOrgUnitId IN (SELECT OrgUnitId FROM #Excludes),VirtualDistance + 1, 1 ), o.PersonId, o.isExcluded , level_num+1 as level_num
from #OrgList o
join cte on o.ParentOrgUnitId=cte.OrgUnitId
)
select * from cte
Here are the results:
OrgUnitId ParentOrgUnitId VirtualParentOrgUnitId VirtualDistance PersonId isExcluded level_num
----------- --------------- ---------------------- --------------- ----------- ---------- -----------
1 NULL NULL 0 100 0 0
2 1 1 0 101 0 1
3 1 1 0 102 0 1
6 3 3 0 105 0 2
4 2 2 0 103 1 2
5 2 2 0 104 0 2
7 4 2 1 106 0 3
8 4 2 1 107 0 3
9 4 2 1 108 0 3
10 4 2 1 109 0 3
11 4 2 1 110 1 3
12 11 2 2 111 0 4
;
with cte as (
select OrgUnitId, ParentOrgUnitId, PersonId, isExcluded , 0 as level_num, 0 as level_after_exclusions,
cast(',' as varchar(max)) + case isExcluded when 1 then cast(OrgUnitId as varchar(20)) else '' end as excludedmembers,
case isExcluded when 1 then ParentOrgUnitId end as newParentId
from #OrgList
where ParentOrgUnitId is null
UNION ALL
select o.OrgUnitId, o.ParentOrgUnitId, o.PersonId, o.isExcluded , level_num + 1, level_after_exclusions + case o.isExcluded when 1 then 0 else 1 end,
excludedmembers + case o.isExcluded when 1 then cast(o.OrgUnitId as varchar(20))+',' else '' end,
case when excludedmembers like '%,'+cast(o.ParentOrgUnitId as varchar(20))+',%' then newParentId else o.ParentOrgUnitId end
from #OrgList o
join cte on o.ParentOrgUnitId=cte.OrgUnitId
)
select *, level_num - level_after_exclusions as shiftbylevels
from cte

Assign weight based on hierarchical depth

Take a table with values like below with two columns. I want the output in such a way that the count should be based on the depth of the hierarchy. Eg. A has a dependency on B,D and B has a dependency on C (C has not dependency) and D has dependencies on B,E and E has dependency on C and hence the weight of A is 6.
A B
A D
B C
D B
D E
E C
A 6
B 1
C 0
D 4
E 1
How can I write a SQL server query to achieve this output.
I think does what you want:
with cte as (
select col1, col2
from t
union all
select cte.col1, t.col2
from cte join
t
on t.col1 = cte.col2
)
select col1, sum(w)
from (select cte.col1, col2, 1 as w
from cte
union all
select col2, null, 0
from t
) t
group by col1;
Here is a db<>fiddle.
You could use cte for this:
select
child=cast(child as varchar(10)),
parent=cast(parent as varchar(10))
into #dat
from (values
('A','B'),('A','D'),('B','C'),('D','B'),('D','E'),('E','C')
) x (child,parent)
;with cte
as (
select distinct
parent as node,
0 as level,
parent as chain,
isleaf = case when exists (select 1 from #dat dpy where dpy.child=dp.parent) then 1 else 0 end
from #dat dp
where not exists (select 1 from #dat dpx where dp.parent=dpx.child)
union all
select
dc.child,
c.level+1,
cast(c.chain+dc.child as varchar(10)),
isleaf = case when exists (select 1 from #dat dcx where dcx.parent=dc.child) then 1 else 0 end
from #dat dc
join cte c
on c.node=dc.parent
)
select
node, sum(level)
from cte
group by node
result:
node weight
A 8
B 1
C 0
D 4
E 1
result of just select * from cte gives you structure overview:
node level chain isleaf
C 0 C 0
B 1 CB 1
E 1 CE 1
D 2 CED 1
A 3 CEDA 0
A 2 CBA 0
D 2 CBD 1
A 3 CBDA 0

Reversed group by with multiple columns?

Hi i'm not sure if this possible in oracle database or any one but is possible to make this:
What i have:
Document | Volume | BAC | CO
-----------|-----------|---------|---------
TA1 | 4 | 2 | 0
What i want:
Document | Volume | BAC | CO | ID
-----------|-----------|---------|---------|---------
TA1 | 1 | 0 | 0 | 1
TA1 | 1 | 0 | 0 | 2
TA1 | 1 | 0 | 0 | 3
TA1 | 1 | 0 | 0 | 4
TA1 | 0 | 1 | 0 | 5
TA1 | 0 | 1 | 0 | 6
I tried using WITH but it's just mess in my Sqldevelopper now couldn't even come close to it knowing that WITH can't be used twice or been in UNION.
PS: Number of rows need to be equal to (Volume + Bac + CO).
Is this operation possible in ORACLE 12?
This should work and it only goes over the data once. It's a simple application of hierarchical query.
I added more test data; note that in the case of TA3, there should be no rows in the output (because all three values in the row are 0).
with
test_data ( document, volume, bac, co ) as (
select 'TA1', 4, 2, 0 from dual union all
select 'TA2', 0, 0, 1 from dual union all
select 'TA5', 0, 0, 0 from dual
)
-- end of test data; actual solution (SQL query) begins below this line
select document,
case when level <= volume then 1 else 0 end as volume,
case when level > volume and level <= volume + bac then 1 else 0 end as bac,
case when level > volume + bac then 1 else 0 end as co,
level as id
from test_data
where volume + bac + co > 0
connect by level <= volume + bac + co
and prior document = document
and prior sys_guid() is not null
order by document, id -- ORDER BY is optional
;
DOC VOLUME BAC CO ID
--- ---------- ---------- ---------- ----------
TA1 1 0 0 1
TA1 1 0 0 2
TA1 1 0 0 3
TA1 1 0 0 4
TA1 0 1 0 5
TA1 0 1 0 6
TA2 0 0 1 1
7 rows selected
You can try this -> First, create a temporary derived table containing the amount of rows equal to the maximum number allowed :
CREATE TABLE TMP_TABLE AS
SELECT s.num_col,ROW_NUMBER() OVER(ORDER BY 1) as rnk
FROM (
SELECT 1 as num_col FROM dual
UNION ALL SELECT 1 as num_col FROM dual
UNION ALL SELECT 1 as num_col FROM dual
UNION ALL SELECT 1 as num_col FROM dual
...... As many necessary) s
Then, use this:
SELECT p.num_col as volume,0 as BAC,0 as CO
FROM TMP_TABLE p
JOIN YourTable t
ON(t.Volume >= p.rnk)
UNION ALL
SELECT 0 as volume,p.num_col as BAC,0 as CO
FROM TMP_TABLE p
JOIN YourTable t
ON(t.BAC >= p.rnk)
UNION ALL
SELECT 0 as volume,0 as BAC,p.num_col as CO
FROM TMP_TABLE p
JOIN YourTable t
ON(t.CO >= p.rnk)
select t.document
,decode(t.col,'V',1,0) as volume
,decode(t.col,'B',1,0) as bac
,decode(t.col,'C',1,0) as co
,row_number () over
(
partition by t.document order by decode(t.col,'V',1,'B',2,'C',3)
) as id
from t unpivot (n for col in (volume as 'V',bac as 'B',co as 'C')) t
join (select level as n from dual connect by level <= (select max(greatest(volume,bac,co)) from t)) c
on c.n <= t.n
;
or
select t.document
,decode(t.col,'V',1,0) as volume
,decode(t.col,'B',1,0) as bac
,decode(t.col,'C',1,0) as co
,t.pre + c.n as id
from (select t.*,0 as pre_v,volume as pre_b,volume+bac as pre_c from t) t
unpivot ((n,pre) for col in ((volume,pre_v) as 'V',(bac,pre_b) as 'B',(co,pre_c) as 'C')) t
join (select level as n from dual connect by level <= (select max(greatest(volume,bac,co)) from t)) c
on c.n <= t.n
order by 1,id
;
or
with r (col,Document,col_val,n,id) as
(
select c.col,t.Document,decode (c.col,1,t.Volume,2,t.BAC,3,t.CO),1,decode (c.col,1,1,2,t.Volume+1,3,t.Volume+t.BAC+1)
from t cross join (select level as col from dual connect by level <= 3) c
where decode (c.col,1,t.Volume,2,t.BAC,3,t.CO) > 0
union all
select r.col,r.Document,r.col_val,r.n+1,r.id+1
from r join (select level as col from dual connect by level <= 3) c
on c.col = r.col and r.n < r.col_val
)
select Document
,decode (col,1,1,0) as Volume
,decode (col,2,1,0) as BAC
,decode (col,3,1,0) as CO
,id
from r
order by 1,5
;
or
with r_Volume (Document,col_val,Volume,Bac,Co,n) as (select Document,Volume,1,0,0,1 from t where Volume > 0 union all select Document,col_val,Volume,Bac,Co,n+1 from r_Volume where n < col_val)
,r_Bac (Document,col_val,Volume,Bac,Co,n) as (select Document,Bac ,0,1,0,1 from t where Bac > 0 union all select Document,col_val,Volume,Bac,Co,n+1 from r_Bac where n < col_val)
,r_Co (Document,col_val,Volume,Bac,Co,n) as (select Document,Co ,0,0,1,1 from t where Co > 0 union all select Document,col_val,Volume,Bac,Co,n+1 from r_Co where n < col_val)
select Document,Volume,Bac,Co,row_number () over (partition by Document order by Volume desc,Bac desc,Co desc) as id
from ( select Document,Volume,Bac,Co from r_Volume
union all select Document,Volume,Bac,Co from r_Bac
union all select Document,Volume,Bac,Co from r_Co
) r
;
Here's another way to solve this problem:
WITH sample_data( document, volume, bac, co ) AS (
SELECT 'TA1', 4, 2, 0
FROM dual
)
, recursive( document, col_id, col_cnt, id ) AS (
SELECT document -- First unpivot the data for each document
, col_id
, col_cnt
, SUM( col_cnt ) over( partition BY document order by col_id ) - col_cnt + 1
FROM sample_data UNPIVOT( col_cnt FOR col_id IN( volume AS 1,
bac AS 2,
co AS 3 ) )
WHERE col_cnt > 0 -- But throw away rows with zero col_cnts.
UNION ALL
SELECT document
, col_id
, col_cnt - 1 -- Recursively decrement the col_cnt
, id + 1 -- and increment id
FROM recursive
WHERE col_cnt > 1 -- until col_cnt is no longer > 1
)
SELECT document -- Finally pivot the recursive data
, volume -- back to its original columns
, bac
, co
, id
FROM recursive PIVOT( COUNT( * ) FOR col_id IN( 1 AS volume, 2 AS bac, 3 AS co ) )
ORDER BY document
, id;

Add summarizing column with calculation

I need to show serial numbers for each row of an invoice. That means, that on one position there can be several serial numbers. Along with the serial number there needs to be a quantity, which is obviously allways one. Unfortunately, there could be rows with more items than serial numbers. This happens when serial numbers are not scanned in the shipping process. In my output I need an extra row for these positions where I show the number of REMAINING items. So let's say, that there is a position with 10 items in it and only four are scanned in the shipping process. That would mean I print four rows with the serials and quantity one and a fith row with no serial and the quantity six.
I work with SQL Server 2008 and would prefer a solution without temp tables or CTEs.
Here is an example of what I mean:
CREATE TABLE #data (doc int, pos int, qty int)
CREATE TABLE #serial (doc int, pos int, serial varchar(10))
INSERT INTO #data
SELECT 1,1,6
UNION ALL
SELECT 1,2,3
UNION ALL
SELECT 2,1,4
INSERT INTO #serial
select 1,1,'aaaaaaaaaa'
UNION ALL
select 1,1,'bbbbbbbbbb'
UNION ALL
select 1,1,'cccccccccc'
UNION ALL
select 1,1,'dddddddddd'
UNION ALL
select 1,2,'eeeeeeeeee'
UNION ALL
select 1,2,'ffffffffff'
UNION ALL
select 1,2,'gggggggggg'
UNION ALL
select 2,1,'hhhhhhhhhh'
SELECT d.doc, d.pos, s.serial, CASE WHEN s.serial IS NOT NULL THEN 1 ELSE d.qty END qty
FROM #data d
INNER JOIN #serial s ON s.doc = d.doc and s.pos = d.pos
This is the desired output:
doc | pos | serial | qty
1 | 1 |'aaaaaaaaaa'| 1
1 | 1 |'bbbbbbbbbb'| 1
1 | 1 |'cccccccccc'| 1
1 | 1 |'dddddddddd'| 1
1 | 1 | NULL | 2
1 | 2 |'eeeeeeeeee'| 1
1 | 2 |'ffffffffff'| 1
1 | 2 |'gggggggggg'| 1
2 | 1 |'hhhhhhhhhh'| 1
2 | 1 | NULL | 3
select
s.doc, s.pos, s.serial, d.qty - s.cnt qty
from
( select
s.doc, s.pos, s.serial, count(*) cnt,
case when grouping(s.doc) = 0 and grouping(s.pos) = 0 and grouping(s.serial) = 1 then 1 else 0 end grp
from
#serial s
group by
s.doc, s.pos, s.serial with cube
having
grouping(s.doc) = 0 and grouping(s.pos) = 0 and grouping(s.serial) = 1
or grouping(s.doc) = 0 and grouping(s.pos) = 0 and grouping(s.serial) = 0
) s
left join #data d on s.doc = d.doc and s.pos = d.pos and s.grp = 1
where
s.grp = 0 or d.qty - s.cnt > 0
order by
s.doc, s.pos, s.grp
Dynamic approach
SELECT d.doc, d.pos, s.serial, 1 qty
FROM #data d
INNER JOIN #serial s ON s.doc = d.doc and s.pos = d.pos
UNION
select t1.doc,t1.pos,null,t1.qty-ss from
(
SELECT d.doc,d.pos, SUM(1) SS , d.qty
FROM #data d
INNER JOIN #serial s ON s.doc = d.doc and s.pos = d.pos
group by d.doc,d.pos,d.qty
)t1 where SS<>qty
Order by d.doc,d.pos,s.serial
Are you looking for this ..?
SELECT d.doc, d.pos, s.serial, CASE WHEN s.serial IS NOT NULL THEN 1 ELSE d.qty END qty
FROM #data d
INNER JOIN #serial s ON s.doc = d.doc AND s.pos = d.pos
UNION ALL
SELECT d.doc, d.pos, NULL serial, d.qty - s.qty
FROM #data d
INNER JOIN (
SELECT doc, pos, count(*) AS qty
FROM #serial
GROUP BY doc, pos
) s ON s.doc = d.doc AND s.pos = d.pos
WHERE d.qty - s.qty <> 0
ORDER BY doc, pos
Output
doc pos serial qty
1 1 aaaaaaaaaa 1
1 1 bbbbbbbbbb 1
1 1 cccccccccc 1
1 1 dddddddddd 1
1 1 NULL 2
1 2 eeeeeeeeee 1
1 2 ffffffffff 1
1 2 gggggggggg 1
2 1 hhhhhhhhhh 1
2 1 NULL 3

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)