Переупорядочить столбцы в окончательной хранимой процедуре SELECT / OUTPUT - PullRequest
0 голосов
/ 26 мая 2018

Мне нужно изменить порядок столбцов в заключительном операторе SELECT в хранимой процедуре.Порядок столбцов должен быть получен из другой таблицы.

У меня есть решение, основанное на динамическом SQL.Есть ли лучший способ сделать это?У меня есть около 100 столбцов для возврата с миллионами строк для экспорта в Excel.Есть ли другое решение, оптимизированное по производительности, кроме динамического запроса?

Ниже приведен пример кода для моего текущего решения.

IF OBJECT_ID( 'tempdb..#TempColumns') IS NOT NULL
BEGIN
    DROP TABLE #TempColumns
END

IF OBJECT_ID( 'tempdb..#TempColumnsOrder') IS NOT NULL
BEGIN
    DROP TABLE #TempColumnsOrder
END

CREATE TABLE #TempColumns 
(
    ID INT IDENTITY,
    FirstName VARCHAR(MAX),
    LastName VARCHAR(MAX),
    Gender VARCHAR(MAX)
)

INSERT INTO #TempColumns 
VALUES ('ABC', 'DEF', 'MALE'), ('PR', 'ZA', 'FEMALE'), ('ERT', 'GFG', 'MALE')

CREATE TABLE #TempColumnsOrder 
(
    ID INT IDENTITY,
    ColumnName VARCHAR(MAX),
    ColumnOrder INT
)

INSERT INTO #TempColumnsOrder 
VALUES ('FirstName', 3), ('LastName', 2), ('Gender', 1)

SELECT * FROM #TempColumns
SELECT * FROM #TempColumnsOrder

DECLARE @script VARCHAR(MAX)
SELECT @script = 'SELECT '

SELECT @script = @script + ColumnName + ','
FROM #TempColumnsOrder
ORDER BY ColumnOrder

PRINT @script

SELECT @script = SUBSTRING(RTRIM(@script), 1, LEN(RTRIM(@script)) - 1)
SELECT @script = @script + ' FROM #TempColumns'

EXEC (@script)

IF OBJECT_ID( 'tempdb..#TempColumns') IS NOT NULL
BEGIN
    DROP TABLE #TempColumns
END

IF OBJECT_ID( 'tempdb..#TempColumnsOrder') IS NOT NULL
BEGIN
    DROP TABLE #TempColumnsOrder
END

Ответы [ 2 ]

0 голосов
/ 26 мая 2018

SELECT @script = @script + ColumnName + ',' FROM #TempColumnsOrder ORDER BY ColumnOrder

Поведение конкатенации агрегированных строк с помощью описанной выше техники не гарантируется.Фактическое поведение зависит от плана, поэтому вы можете не получить желаемых результатов.

В SQL Server 2017 и базе данных SQL Azure, STRING_AGG является правильным методом:

SELECT STRING_AGG(ColumnName, ',') WITHIN GROUP(ORDER BY ColumnOrder)
FROM #TempColumnsOrder;

В более старых версиях SQL, таких как SQL Server 2012, наилучшим методом является использование XML PATH():

SELECT @script = @script + 
         STUFF((SELECT ',' + ColumnName
          FROM #TempColumnsOrder
          ORDER BY ColumnOrder
          FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'');

См. этот ответ для получения подробной информации о том, как работает вышеуказанный запрос.

0 голосов
/ 26 мая 2018

Спасибо за ответ, есть ли лучший способ в динамическом SQL, кроме того, что я сделал?

Вы можете исключить неподдерживаемую конкатенацию строк, которую вы используете, а также модернизировать и просто код:

DROP TABLE IF EXISTS #TempColumns
DROP TABLE IF EXISTS #TempColumnsOrder

CREATE TABLE #TempColumns 
(
    ID INT IDENTITY,
    FirstName VARCHAR(MAX),
    LastName VARCHAR(MAX),
    Gender VARCHAR(MAX)
)

INSERT INTO #TempColumns
Values('ABC','DEF','MALE'),('PR','ZA','FEMALE'),('ERT','GFG','MALE')

CREATE TABLE #TempColumnsOrder 
(
    ID INT IDENTITY,
    ColumnName VARCHAR(MAX),
    ColumnOrder INT
)

INSERT INTO #TempColumnsOrder 
Values('FirstName',3), ('LastName',2), ('Gender',1)

SELECT * FROM #TempColumns
SELECT * FROM #TempColumnsOrder

DECLARE @script VARCHAR(MAX) =  concat(
        'SELECT ', 
        (select STRING_AGG(QUOTENAME(ColumnName),', ') WITHIN GROUP (ORDER BY ColumnOrder) 
         FROM #TempColumnsOrder), 
        ' FROM #TempColumns')

print @script

EXEC (@script)

DROP TABLE IF EXISTS #TempColumns
DROP TABLE IF EXISTS #TempColumnsOrder
...