I want to get 3 tables from one table named @X_Table (this table has the name of columns of original table) in SQL 2008:
The Original table has lots of rows and 5 atributes (I could have more atributes like 30, but in the example I have 5 atributes):
x1 x2 x3 x4 x5
----------------------------
438 498 3625 3645 5000
438 498 3625 3648 5000
438 498 3625 3629 5000
437 501 3625 3626 5000
438 498 3626 3629 5000
439 498 3626 3629 5000
440 5000 3627 3628 5000
444 5021 3631 3634 5000
451 5025 3635 3639 5000
458 5022 3640 3644 5000
465 525 3646 3670 5000
473 533 3652 3676 5000
481 544 3658 3678 5000
484 544 3661 3665 5000
484 532 3669 3662 2945
482 520 3685 3664 2952
481 522 3682 3661 2955
480 525 3694 3664 2948
481 515 5018 3664 2956
479 5000 3696 3661 2953
**...(EVEN MORE ROWS LIKE 100,000)** ...
First I am getting in other table the names of the columns(the var @table_name refers to the table above):
INSERT @X_Table (ID,NAME)
SELECT [ID] = ORDINAL_POSITION, [NAME] = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @table_name
So I get the @X_Table:
@X_Table:
ID NAME
------------
1 x1
2 x2
3 x3
4 x4
5 x5
Then for each column I want the sum of all values in that column
so all the values in xi, so
sum(x1), sum(x2), sum(x3), sum(x4), sum(x5)`
Table 1: INT,VARCHAR,FLOAT
ID Name value
---------------------------
1 x1 48431
2 x2 138420
3 x3 192071
4 x4 192041
5 x5 204602
Then for each column I want the sum of all values in that column multiplied by each column for example
for column x1: sum(x1*x1), sum(x1*x2), sum(x1*x3), sum(x1*x4), sum(x1*x5)
for column x2: sum(x2*x2), sum(x2*x3), sum(x2*x4), sum(x2*x5)
for column x3: sum(x3*x3), sum(x3*x4), sum(x3*x5)
for column x4: sum(x4*x4), sum(x4*x5)
for column x5: sum(x5*x5)
Table 2: INT, VARCHAR, FLOAT
ID Name value
---------------------------
1 SUM(x1*x1) 83926421
2 SUM(x1*x2) 162997894
3 SUM(x1*x3) 186865166
4 SUM(x1*x4) 156224385
5 SUM(x1*x5) 168573557
6 SUM(x2*x2) 598228836
7 SUM(x2*x3) 542331010
8 SUM(x2*x4) 460990820
9 SUM(x2*x5) 512335365
10 SUM(x3*x3) 797430261
11 SUM(x3*x4) 659040569
12 SUM(x3*x5) 723779398
13 SUM(x4*x4) 677091478
14 SUM(x4*x5) 722922237
15 SUM(x5*x5) 808976398
Then for the last table I want the diagonal, or in other the xii of the table above
Table 3: INT, VARCHAR, FLOAT
ID Name value
---------------------------
1 SUM(x1*x1) 83926421
2 SUM(x2*x2) 598228836
3 SUM(x3*x3) 797430261
4 SUM(x4*x4) 677091478
5 SUM(x5*x5) 808976398
So To do so I am doing this approach, but I know This can be optimized,
SET @d = 5
WHILE (@counterI <= @d) BEGIN
SELECT @nameThird = NAME FROM @X_Table where ID = @counterI;
SET @nameFirst = @nameThird;
--INSERT FIRST TABLE
SET @queryFirst = 'INSERT #FIRST_T (ID,NAME,Value) SELECT '+ CAST(@counterI AS VARCHAR)+' , '''+@nameFirst+''', SUM('+@nameFirst+') FROM '+ @table_name;
EXEC (@queryFirst);
--GET VALUE TO INSERT IN THIRD TABLE
SET @queryThird = 'INSERT #THIRD_T (ID,NAME,Value) SELECT '+CAST(@counterI AS VARCHAR)+' , '''+@nameThird+'*'+@nameThird+''', SUM('+@nameThird +'*'+@nameThird+') FROM '+ @table_name;
EXEC (@queryThird);
--Xij
WHILE (@counterJ <= @d) BEGIN
SELECT @nameThird2 = NAME FROM @X_Table where ID = @counterJ;
SET @queryThird = 'INSERT #SECOND_T (ID,NAME,Value) SELECT '+CAST(@n AS VARCHAR)+' , '''+@nameThird+'*'+@nameThird2+''', SUM('+@nameThird +'*'+@nameThird2+') FROM '+ @table_name;
EXEC (@queryThird);
SET @counterJ = @counterJ + 1;
SET @n = @n +1
END
SET @counterI = @counterI + 1; --reduce space
SET @counterJ = @counterI;
END
(It takes a lot of time for tables with more than 30 attributes...)
-----------------------------EDIT----------------------------
When having more than 10 columns I am getting for the @table1 (answer by @Thomas)
ID Name Value
1 x1 8029145
2 x10 15453498
3 x11 13909514
4 x12 11336348
5 x13 11598240
6 x14 11951291
7 x15 12034693
8 x16 6558719
9 x17 5400520
10 x18 4966450
11 x19 5773049
12 x2 12696346
13 x20 5872404
14 x21 5542875
15 x22 9700954
16 x23 8484327
17 x24 8612340
18 x25 129470
19 x3 135818770
Is there some way to sort them by Name
x1,x2,x3,x4,x5...,x9,x10,x11....
instead of
x1,x10,x11,x19,x2,x3....?
So we get
ID Name Value
-----------------
1 x1 8029145
2 x2 12696346
3 x3 135818770
...
(Expanded source data to illustrate use of ordinal)
This problem is much easier if you normalize the structure. Since you are trying to do arithmetic on the columns, they need to be rows instead of columns.
Declare @X_Table Table
(
Id int not null Identity(1,1) Primary Key
, x1 float not null
, x2 float not null
, x3 float not null
, x4 float not null
, x5 float not null
, x111 float not null
, x112 float not null
, x113 float not null
, x114 float not null
, x115 float not null
, x11 float not null
, x12 float not null
, x13 float not null
, x14 float not null
, x15 float not null
)
Insert @X_Table( x1, x2, x3, x4, x5
, x111, x112, x113, x114, x115
, x11, x12, x13, x14, x15
)
Select 438, 498, 3625, 3645, 5000, 438, 498, 3625, 3645, 5000, 438, 498, 3625, 3645, 5000
Union All Select 438, 498, 3625, 3648, 5000, 438, 498, 3625, 3648, 5000, 438, 498, 3625, 3648, 5000
Union All Select 438, 498, 3625, 3629, 5000, 438, 498, 3625, 3629, 5000, 438, 498, 3625, 3629, 5000
Union All Select 437, 501, 3625, 3626, 5000, 437, 501, 3625, 3626, 5000, 437, 501, 3625, 3626, 5000
Union All Select 438, 498, 3626, 3629, 5000, 438, 498, 3626, 3629, 5000, 438, 498, 3626, 3629, 5000
Union All Select 439, 498, 3626, 3629, 5000, 439, 498, 3626, 3629, 5000, 439, 498, 3626, 3629, 5000
Union All Select 440, 5000, 3627, 3628, 5000, 440, 5000, 3627, 3628, 5000, 440, 5000, 3627, 3628, 5000
Union All Select 444, 5021, 3631, 3634, 5000, 444, 5021, 3631, 3634, 5000, 444, 5021, 3631, 3634, 5000
Union All Select 451, 5025, 3635, 3639, 5000, 451, 5025, 3635, 3639, 5000, 451, 5025, 3635, 3639, 5000
Union All Select 458, 5022, 3640, 3644, 5000, 458, 5022, 3640, 3644, 5000, 458, 5022, 3640, 3644, 5000
Union All Select 465, 525, 3646, 3670, 5000, 465, 525, 3646, 3670, 5000, 465, 525, 3646, 3670, 5000
Union All Select 473, 533, 3652, 3676, 5000, 473, 533, 3652, 3676, 5000, 473, 533, 3652, 3676, 5000
Union All Select 481, 544, 3658, 3678, 5000, 481, 544, 3658, 3678, 5000, 481, 544, 3658, 3678, 5000
Union All Select 484, 544, 3661, 3665, 5000, 484, 544, 3661, 3665, 5000, 484, 544, 3661, 3665, 5000
Union All Select 484, 532, 3669, 3662, 2945, 484, 532, 3669, 3662, 2945, 484, 532, 3669, 3662, 2945
Union All Select 482, 520, 3685, 3664, 2952, 482, 520, 3685, 3664, 2952, 482, 520, 3685, 3664, 2952
Union All Select 481, 522, 3682, 3661, 2955, 481, 522, 3682, 3661, 2955, 481, 522, 3682, 3661, 2955
Union All Select 480, 525, 3694, 3664, 2948, 480, 525, 3694, 3664, 2948, 480, 525, 3694, 3664, 2948
Union All Select 481, 515, 5018, 3664, 2956, 481, 515, 5018, 3664, 2956, 481, 515, 5018, 3664, 2956
Union All Select 479, 5000, 3696, 3661, 2953, 479, 5000, 3696, 3661, 2953, 479, 5000, 3696, 3661, 2953
The following table is clearly static. However, if you were going to involve dynamic SQL (which is not recommended in T-SQL but obviously doable), the population of this next table would be the only part.
Declare @X_Table_Normalized Table
(
Id int not null
, Ordinal int not null
, Name varchar(10) not null
, Value float not null
)
Insert @X_Table_Normalized( Id, Ordinal, Name, Value )
Select Id, 1, 'x1', x1 From @X_Table
Union All Select Id, 2, 'x2', x2 From @X_Table
Union All Select Id, 3, 'x3', x3 From @X_Table
Union All Select Id, 4, 'x4', x4 From @X_Table
Union All Select Id, 5, 'x5', x5 From @X_Table
Union All Select Id, 6, 'x111', x111 From @X_Table
Union All Select Id, 7, 'x112', x112 From @X_Table
Union All Select Id, 8, 'x113', x113 From @X_Table
Union All Select Id, 9, 'x114', x114 From @X_Table
Union All Select Id, 10, 'x115', x115 From @X_Table
Union All Select Id, 11, 'x11', x11 From @X_Table
Union All Select Id, 12, 'x12', x12 From @X_Table
Union All Select Id, 13, 'x13', x13 From @X_Table
Union All Select Id, 14, 'x14', x14 From @X_Table
Union All Select Id, 15, 'x15', x15 From @X_Table
Declare @Table1 Table
(
Id int not null
, Name varchar(25) not null
, Ordinal int not null
, Value float not null
)
Insert @Table1( Id, Name, Ordinal, Value )
Select Row_Number() Over( Order By Ordinal, Name )
, Name, Ordinal, Sum(Value)
From @X_Table_Normalized
Group By Ordinal, Name
Declare @Table2 Table
(
Id int not null
, Name varchar(25) not null
, Ordinal int not null
, Value float not null
)
Insert @Table2( Id, Name, Ordinal, Value )
Select Row_Number() Over ( Order By T1.Ordinal, T1.Name, T2.Ordinal, T2.Name ) As Id
, 'Sum(' + T1.Name + '*' + T2.Name + ')' As Name
, T1.Ordinal + 100 * T2.Ordinal
, Sum( T1.Value * T2.Value ) As Value
From @X_Table_Normalized As T1
Join @X_Table_Normalized As T2
On T2.Id = T1.Id
Where T1.Ordinal <= T2.Ordinal
Group By T1.Name, T1.Ordinal, T2.Name, T2.Ordinal
Declare @Table3 Table
(
Id int not null
, Name varchar(25) not null
, Ordinal int not null
, Value float not null
)
Insert @Table3( Id, Name, Ordinal, Value )
Select Row_Number() Over ( Order By T1.Ordinal, T1.Name, T2.Ordinal, T2.Name ) As Id
, 'Sum(' + T1.Name + '*' + T2.Name + ')' As Name
, T1.Ordinal + 100 * T2.Ordinal
, Sum( T1.Value * T2.Value ) As Value
From @X_Table_Normalized As T1
Join @X_Table_Normalized As T2
On T2.Id = T1.Id
Where T1.Ordinal = T2.Ordinal
Group By T1.Name, T1.Ordinal, T2.Name, T2.Ordinal
Select * From @Table1 Order By Ordinal
Select * From @Table2 Order By Ordinal
Select * From @Table3 Order By Ordinal
Depending on how this is used, you might encapsulate the population of the normalized table using dynamic SQL. If you do, you will need to use real tables or temp tables as opposed to temp variables. That code might look something like:
Declare @Sql nvarchar(max)
Set @Sql = 'Insert #X_Table_Normalized_Dynamic( Id, Ordinal, Name, Value )|'
Select @Sql = @Sql + ' Union All Select Id'
+ ', ' + Cast( Row_Number() Over ( Order By ORDINAL_POSITION ) As varchar(10) )
+ ', ' + QuoteName(COLUMN_NAME, '''')
+ ', ' + QuoteName(COLUMN_NAME)
From INFORMATION_SCHEMA.COLUMNS
Where TABLE_NAME = 'MySourceTable'
Set @Sql = Replace( @Sql, '| Union All ', ' ')
Exec( @Sql )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With