简体   繁体   中英

Reorder columns in final stored procedure SELECT / OUTPUT

I need to reorder columns in the final SELECT statement in a stored procedure. Column orders needs to be fetched from another table.

I have a solution based on dynamic SQL. Is there any better way to do it? I have around 100 columns to return with millions of rows for an Excel export. Is there any other performance optimized solution other than a dynamic query?

Please find sample code below for my current solution.

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

Thanks for reply, Is there any better way in Dynamic SQL other than what i did?

You can eliminate the unsupported string concatenation you are using, and modernize and simply the code:

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

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

The behavior of aggregate string concatenation with the above technique is not guaranteed. The actual behavior is plan-dependent so you may not get the desired results.

In SQL Server 2017 and Azure SQL Database, STRING_AGG is the proper method:

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

In older SQL Versions like SQL Server 2012, the best method is with XML PATH() :

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

See this answer for details about how the above query works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM