Получите 3 таблицы в SQL Server 2008, избегайте использования двух циклов и динамического SQL - PullRequest
3 голосов
/ 03 мая 2011

Я хочу получить 3 tables из одной таблицы с именем @X_Table (эта таблица имеет имя столбцов original table) в SQL 2008:

Исходная таблица содержит многострок и 5 атрибутов (я мог бы иметь больше атрибутов, например 30, но в примере у меня есть 5 атрибутов):

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)** ...

Сначала я получаю в другой таблице имена столбцов (the var @table_name относится к таблице выше):

INSERT  @X_Table (ID,NAME) 
SELECT  [ID] = ORDINAL_POSITION, [NAME] = COLUMN_NAME 
        FROM INFORMATION_SCHEMA.COLUMNS 
        WHERE TABLE_NAME = @table_name

Итак, я получаю @X_Table:

@ X_Table:

ID  NAME
------------
1   x1
2   x2
3   x3
4   x4
5   x5

Тогда for each column Я хочу sum of all values in that column, поэтому все значения в xi, поэтому сумма (x1), сумма (x2), сумма (x3), сумма (x4), сумма (x5) `

Таблица 1: INT, VARCHAR, FLOAT

ID Name  value
---------------------------
1   x1  48431
2   x2  138420
3   x3  192071
4   x4  192041
5   x5  204602

Затем for each column Я хочу sum of all values in that column multiplied by each column, например
для столбца x1: sum(x1*x1), sum(x1*x2), sum(x1*x3), sum(x1*x4), sum(x1*x5)
для столбца x2: sum(x2*x2), sum(x2*x3), sum(x2*x4), sum(x2*x5)
для столбца x3: sum(x3*x3), sum(x3*x4), sum(x3*x5)
для столбца x4: sum(x4*x4), sum(x4*x5)
для столбца x5: sum(x5*x5)

Таблица 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

Тогда для последней таблицы я хочу диагональ, или в другом случае xii таблицы выше

Таблица 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

Итак, для этого я использую этот подход, но я знаю, что это можно оптимизировать,

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
  • Как бы вы сделали это без этих 2 циклов?,

(это занимает много времени для таблиц с более чем 30 атрибутами ...)

-----------------------------РЕДАКТИРОВАТЬ----------------------------

Когда у меня более 10 столбцов, я получаю @ table1 (ответ @Thomas)

ID Имя Значение


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 

Есть ли способ сортировать их по имени

x1,x2,x3,x4,x5...,x9,x10,x11.... 

вместо

x1,x10,x11,x19,x2,x3....?

Итак, мы получаем

ID Name Value
 -----------------
    1   x1  8029145
    2   x2  12696346
    3   x3  135818770
    ...

Ответы [ 2 ]

2 голосов
/ 04 мая 2011

(Расширенные исходные данные для иллюстрации использования порядкового номера)

Эта проблема намного проще, если вы нормализуете структуру.Поскольку вы пытаетесь сделать арифметику для столбцов, они должны быть строками, а не столбцами.

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

Следующая таблица явно статична.Однако, если вы собираетесь использовать динамический SQL (который не рекомендуется в T-SQL, но, очевидно, выполнимый), заполнение этой следующей таблицы будет единственной частью.

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

Таблица 1 - Сумма по(оригинал) столбец

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

Таблица 2 - Суммы продуктов по (оригиналу) столбец

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

Таблица 3 - Суммы продуктов по диагонали по (оригиналу) столбцу

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

Заполнение нормализованной таблицы динамическим SQL

В зависимости от того, как это используется, вы можете инкапсулировать заполнение нормализованной таблицы с использованием динамического SQL.Если вы это сделаете, вам нужно будет использовать реальные таблицы или временные таблицы в отличие от временных переменных.Этот код может выглядеть примерно так:

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 )
2 голосов
/ 04 мая 2011

Здесь я делаю еще один подход, но почему бы вам просто не создать представление и не извлечь из него другие таблицы?

Преимущество

  • Гораздо быстрее, так как все еще установлено на основе.
  • более читабельно

Динамический просмотр с созданием

DECLARE @Statement VARCHAR(MAX) = 'CREATE VIEW VIEW_OriginalTable (ID, Name, Value) AS (' + CHAR(13) + CHAR(10)
SELECT  @Statement =  @Statement 
                      + 'UNION ALL SELECT ' 
                      + CAST(ORDINAL_POSITION AS VARCHAR(32)) 
                      + ', ''' 
                      + COLUMN_NAME
                      + ''', SUM('
                      + COLUMN_NAME
                      + ') FROM OriginalTable'
                      + CHAR(13) + CHAR(10)
FROM    INFORMATION_SCHEMA.COLUMNS 
WHERE   TABLE_NAME = 'OriginalTable'
SELECT @Statement = REPLACE(@Statement, 'UNION ALL SELECT 1,', 'SELECT 1,') + ')'
EXEC (@Statement)
GO        

Три таблицы результатов

/*
  Table1
*/    
SELECT  *
FROM    VIEW_OriginalTable

/*
  Table2
*/    
SELECT  [ID] = ROW_NUMBER() OVER (ORDER BY t1.ID)
        , [Name] = t1.Name + '*' + t2.Name
        , [Value] = t1.Value * t2.Value
FROM    VIEW_OriginalTable t1
        INNER JOIN VIEW_OriginalTable t2 ON t2.ID >= t1.ID

/*
  Table3
*/    
SELECT  [ID] = t1.ID
        , [Name] = t1.Name + '*' + t1.Name
        , [Value] = t1.Value * t1.Value
FROM    VIEW_OriginalTable t1        
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...