在最终存储过程SELECT / OUTPUT中重新排序列

时间:2018-05-26 11:03:31

标签: sql sql-server sql-server-2012

我需要在存储过程的最后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 :(得分:0)

  

感谢您的回复,除了我做的事情之外,动态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

答案 1 :(得分:0)

  

SELECT @script = @script + ColumnName +','FROM #TempColumnsOrder   订单按ColumnOrder

无法保证聚合字符串连接与上述技术的行为。实际行为取决于计划,因此您可能无法获得所需的结果。

在SQL Server 2017和Azure SQL数据库中,STRING_AGG是正确的方法:

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

在SQL Server 2012等较旧的SQL版本中,最好的方法是使用XML PATH()

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

有关上述查询如何运作的详细信息,请参阅this answer