【问题标题】:Reorder columns in final stored procedure SELECT / OUTPUT重新排序最终存储过程 SELECT / OUTPUT 中的列
【发布时间】:2018-05-26 11:03:30
【问题描述】:

我需要在存储过程的最后一个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

【问题讨论】:

  • 所有 T-SQL 解决方案都需要动态 SQL。另一种方法是在应用程序中排序/映射列。
  • 感谢您的回复,除了我所做的之外,在动态 SQL 中还有什么更好的方法吗?

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


【解决方案1】:

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

【讨论】:

  • STRING_AGG(QUOTENAME(ColumnName) -- 在 2012 sql server 上无法识别我的内置函数
【解决方案2】:

SELECT @script = @script + ColumnName + ',' FROM #TempColumnsOrder ORDER BY 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 2020-07-28
    • 2017-09-26
    • 1970-01-01
    • 1970-01-01
    • 2011-03-02
    相关资源
    最近更新 更多