Создание динамических таблиц в MS-SQL (выполнимость) - PullRequest
0 голосов
/ 18 октября 2018

Есть ли способ создать массив таблиц (или динамически создаваемых таблиц) на основе динамического значения?Например, я знаю, что в C ++ вы можете использовать указатели и динамическую память, но мне нужно сделать что-то подобное в SQL.

Пользователь указывает, что он хочет видеть данные за X лет для каждого года. Нам нужно увидеть более 15 столбцов, которые можно встроить во временную таблицу (идентичные для каждого года).

пользователь выбирает данные 5 лет и текущий год как 2018, поэтому я хочу динамически создать локальную таблицу для 2018, 2017, 2016, 2015 and 2014. Каждая таблица будет отслеживать данные клиентов, продажи и т. Д. То же для каждогоТаблица.

, если вышеприведенное невозможно, можем ли мы ограничить пользователя только выбором года и динамически всегда придерживаться, например, 5 лет.Пользователь указывает, что он хочет начать с 2017, и мы по умолчанию создадим для него 2017, 2016 ... 2013.

Я могу пойти дальше и сказать, создать таблицу #year1, #year2, #year3 etc. Но это требует много кодирования (в основном копирование и вставказаблаговременно).Есть ли способ избежать этого - например, создать таблицу #years[] или указатель?а затем динамически построить какой-то массив таблицы #years.

То, что мы в итоге сделаем, будет проходить через один и тот же запрос / логику, извлекая из года в год одни и те же наборы данных.Затем в конце сравниваем кто / в какой год и каким образом.Суть в том, чтобы не копировать и не вставлять одни и те же операторы объявления / выбора / вставки 5 или более раз?(и если это вообще возможно, чтобы избежать курсоров / циклов)

Я пытался кодировать что-то вроде этого

DECLARE @season_counter int = 5

    DECLARE @cnt int = 0
    Declare @cnt_v varchar(1)  =  CONVERT(varchar(10), @cnt)

    DECLARE @SQL NVARCHAR(max) = ''

     WHILE @cnt <= @season_counter
     BEGIN
        select   @SQL =  @SQL + ' create table #year' + @cnt_v
         +  ' (customer_no int, order_no int, perf_no int, due_amt money, paid_amt money, status int ) ' 

        exec sp_executesql @SQL
        print @SQL 

        set @cnt = @cnt + 1
        set @cnt_v = CONVERT(varchar(10), @cnt)
        set @sql = ''


    END

select * from #year1
select * from #year2

Выше сгенерированные ошибки

Msg 208, Level 16, State 0, Line 81
Invalid object name '#year1'. 

IЯ не могу использовать глобальные переменные, и я уверен, что, черт возьми, не хочу объявлять операторы Create для 20 таблиц (как некоторое максимальное значение).Я хочу, чтобы он был динамичным и на лету.Пожалуйста, порекомендуйте.

Ответы [ 2 ]

0 голосов
/ 18 октября 2018

Определенно, динамический SQL может быть вашим другом здесь: например, для создания нужного вам центра вы можете использовать скрипт, как показано ниже:

GO
DECLARE @startYear AS INT = 2000
DECLARE @endYear AS INT =2100
--Magic insert
;
WITH L0
AS ( SELECT c
     FROM   (   SELECT 1
                UNION ALL
                SELECT 1 ) AS D(c) ) , -- 2^1
     L1
AS ( SELECT NULL AS c
     FROM   L0 AS A
            CROSS JOIN L0 AS B ) ,       -- 2^2
     L2
AS ( SELECT NULL AS c
     FROM   L1 AS A
            CROSS JOIN L1 AS B ) ,       -- 2^4
     L3
AS ( SELECT NULL AS c
     FROM   L2 AS A
            CROSS JOIN L2 AS B ) ,       -- 2^8
     L4
AS ( SELECT NULL AS c
     FROM   L3 AS A
            CROSS JOIN L3 AS B ) ,       -- 2^16
     L5
AS ( SELECT NULL AS c
     FROM   L4 AS A
            CROSS JOIN L4 AS B ) ,       -- 2^32
     Nums
AS ( SELECT ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL )) AS id
     FROM   L5 ) ,
     years
AS ( SELECT id AS [year]
     FROM   Nums
     WHERE  id >= @startYear AND id<=@endYear )

SELECT [year] INTO #years
FROM   years


DECLARE @columns VARCHAR(MAX)='' 
DECLARE @curentYear int = @startYear;
WHILE @curentYear <= (SELECT MAX([year]) from #years)
BEGIN
    SET @columns+= '['+(SELECT Cast([year] as VARCHAR(4)) FROM #years WHERE [year] = @curentYear)+'],'
    SET @curentYear += 1;
END

SET @columns = SUBSTRING(@columns,1,LEN(@columns)-1)

DECLARE @SQL NVARCHAR(max)=
'SELECT * FROM #years PIVOT(MAX([year]) FOR [year] IN ('+   @columns+')) AS piv'

EXEC sys.sp_executesql @SQL

enter image description here

0 голосов
/ 18 октября 2018

Я не вижу способа сделать это без использования какого-либо цикла и динамического SQL.[Добавлено:] Ваш цикл сталкивается с известным ограничением SQL Server: вы не можете создать временную таблицу с помощью динамического SQL.Если временная таблица создается первой, вы можете ссылаться на нее в динамическом SQL, но это противоречит цели.Однако вы можете создать таблицу с помощью функции SELECT INTO.Это создает фактическую таблицу, но вы можете удалить и заново создать их в своем коде.

Лично мне также нравится создавать новую схему для таких вещей - обычно "x" - чтобы в Management Studio они отображались только внизу, после всех таблиц схемы "dbo".Вы создаете схему только один раз, поэтому не включайте эту часть в свой цикл:

CREATE SCHEMA x;
GO

DECLARE @SQLCmd NVARCHAR(MAX)
--Loopify this part:
SET @SQLCmd = 
'IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''Temp1'')
    DROP TABLE Temp1;

SELECT *
INTO x.Temp1
FROM YourDB.dbo.YourTable
WHERE foo = ''bar'';'

--PRINT @SQLCmd
EXEC(@SQLCmd);
...