【问题标题】:SQL Server: Want to use variable in ORDER BY on UNIONSQL Server:想要在 UNION 上的 ORDER BY 中使用变量
【发布时间】:2015-01-23 04:29:18
【问题描述】:

我读到这应该是可能的,但我无法让它发挥作用!我试过两种方式设置字段名称 - 没有骰子。

USE RTIDatastore;
DECLARE @PAYE AS VARCHAR(20) = 'T6901' -- 'F1867' -- 'S860'
DECLARE @Product AS VARCHAR(20) = 'ADPFREEDOMAS2';
DECLARE @TaxYear AS CHAR(2) = '15';     -- NB No EMP data for FPS14s
DECLARE @EndPeriod AS INTEGER = 6;
DECLARE @OrderBy AS CHAR(1) = 'S';
DECLARE @OrderTest AS VARCHAR(10) = 'NINO'; -- 'Name';
-- this gets all the EMP records, and the first associated NI records (if any)
SELECT
   R.[EmployerPAYE]                                                AS PAYE
 , H.[ICR]                                                         AS ICR
 , E.[NINO]                                                        AS NINo
 , E.[Surname] + ', ' + E.[Forename]                               AS Name
 , E.[Surname]                              AS SurName          -- added for testing
 , E.[Forename]                             AS ForeName         -- added for testing
 , EMP.[EmploymentID]                                              AS EmploymentID
 , EMP.[ATT3_19_PayrollID]                                         AS ATT3_19_PayrollID     -- identifies EMP record
 , EMP.[ALC14_TaxCode]                                             AS ALC1_4_TaxCode
 , NI.[Employee_NI]                                                AS NI_PK
 , NI.[Emp2_NILetter]                                              AS EMP2_NILetter
FROM [RTIDatastore].[dbo].[Header] H
 JOIN      [RTIDatastore].[dbo].[Employer]    R   ON H.[HeaderID] = R.[HeaderID_FK]
 LEFT JOIN [RTIDatastore].[dbo].[Employee]    E   ON R.[EmployerID] = E.[EmployerID_FK]
 LEFT JOIN [RTIDatastore].[dbo].[Employment]  EMP ON E.[EmployeeID] = EMP.[EmployeeID_FK]
 LEFT JOIN [RTIDatastore].[dbo].[Employee_NI] NI  ON EMP.[EmploymentID] = NI.[EmploymentID_FK]
WHERE H.[SenderID] = @Product
 AND H.[MessageType] = 'FPS' + @TaxYear
 AND R.[EmployerPAYE] = @PAYE
 AND (NI.[Employee_NI] LIKE '%_NI_1' OR NI.[Employee_NI] IS NULL)
UNION
-- this gets any additional NI records
SELECT
   R.[EmployerPAYE]                                                AS PAYE
 , H.[ICR]                                                         AS ICR
 , E.[NINO]                                                        AS NINo
 , E.[Surname] + ', ' + E.[Forename]                               AS Name
 , E.[Surname]                              AS SurName
 , E.[Forename]                             AS ForeName
 , EMP.[EmploymentID]                                              AS EmploymentID
 , EMP.[ATT3_19_PayrollID]                                         AS ATT3_19_PayrollID     -- identifies EMP record
 , EMP.[ALC14_TaxCode]                                             AS ALC1_4_TaxCode
 , NI.[Employee_NI]                       AS NI_PK
 , NI.[Emp2_NILetter]                     AS EMP2_NILetter
FROM [RTIDatastore].[dbo].[Header] H
 JOIN      [RTIDatastore].[dbo].[Employer]    R   ON H.[HeaderID] = R.[HeaderID_FK]
 LEFT JOIN [RTIDatastore].[dbo].[Employee]    E   ON R.[EmployerID] = E.[EmployerID_FK]
 LEFT JOIN [RTIDatastore].[dbo].[Employment]  EMP ON E.[EmployeeID] = EMP.[EmployeeID_FK]
 LEFT JOIN [RTIDatastore].[dbo].[Employee_NI] NI  ON EMP.[EmploymentID] = NI.[EmploymentID_FK]
WHERE H.[SenderID] = @Product
 AND H.[MessageType] = 'FPS' + @TaxYear
 AND R.[EmployerPAYE] = @PAYE
 AND NI.[Employee_NI] NOT LIKE '%_NI_1'
-- generally Surname is safer than NINo or PayrollID, but not always!
--ORDER BY CASE WHEN @OrderBy = 'N' THEN NINo
--              WHEN @OrderBy = 'P' THEN ATT3_19_PayrollID
--              ELSE Surname
--         END
--     , ICR
--     , EmploymentID
--     , NI_PK
ORDER BY @OrderTest -- Name
 --, NINo
 --, ATT3_19_PayrollID
 , ICR
 , EmploymentID
 , NI_PK

上述两个 ORDER 子句都失败了,但这工作正常:

ORDER BY Name
 --, NINo
 --, ATT3_19_PayrollID
 , ICR
 , EmploymentID
 , NI_PK

我需要将代码放入存储过程中,所以我真的不想写3次,因为可能不同的顺序要求...

【问题讨论】:

    标签: sql-server select sql-order-by union


    【解决方案1】:

    您也可以使用 Exec 执行 proc 并构建您的 order by 子句,但我认为在一个答案中演示的条件 Order by 更好,除非您想在字符串中指定 order by

    DECLARE @PAYE AS VARCHAR(20) = 'T6901' -- 'F1867' -- 'S860'
    DECLARE @Product AS VARCHAR(20) = 'ADPFREEDOMAS2';
    DECLARE @TaxYear AS CHAR(2) = '15';     -- NB No EMP data for FPS14s
    DECLARE @EndPeriod AS INTEGER = 6;
    DECLARE @OrderBy AS CHAR(1) = 'S';
    DECLARE @OrderTest AS VARCHAR(10) = 'NINO'; -- 'Name';
    -- this gets all the EMP records, and the first associated NI records (if any)
    
    DECLARE @SqlString nvarchar(max)
    Select @SqlString = 'SELECT
       R.[EmployerPAYE]                                                AS PAYE
     , H.[ICR]                                                         AS ICR
     , E.[NINO]                                                        AS NINo
     , E.[Surname] + '', '' + E.[Forename]                               AS Name
     , E.[Surname]                              AS SurName          -- added for testing
     , E.[Forename]                             AS ForeName         -- added for testing
     , EMP.[EmploymentID]                                              AS EmploymentID
     , EMP.[ATT3_19_PayrollID]                                         AS ATT3_19_PayrollID     -- identifies EMP record
     , EMP.[ALC14_TaxCode]                                             AS ALC1_4_TaxCode
     , NI.[Employee_NI]                                                AS NI_PK
     , NI.[Emp2_NILetter]                                              AS EMP2_NILetter
    FROM [RTIDatastore].[dbo].[Header] H
     JOIN      [RTIDatastore].[dbo].[Employer]    R   ON H.[HeaderID] = R.[HeaderID_FK]
     LEFT JOIN [RTIDatastore].[dbo].[Employee]    E   ON R.[EmployerID] = E.[EmployerID_FK]
     LEFT JOIN [RTIDatastore].[dbo].[Employment]  EMP ON E.[EmployeeID] = EMP.[EmployeeID_FK]
     LEFT JOIN [RTIDatastore].[dbo].[Employee_NI] NI  ON EMP.[EmploymentID] = NI.[EmploymentID_FK]
    WHERE H.[SenderID] = @Product
     AND H.[MessageType] = ''FPS'' + @TaxYear
     AND R.[EmployerPAYE] = @PAYE
     AND (NI.[Employee_NI] LIKE ''%_NI_1'' OR NI.[Employee_NI] IS NULL)
    UNION
    -- this gets any additional NI records
    SELECT
       R.[EmployerPAYE]                                                AS PAYE
     , H.[ICR]                                                         AS ICR
     , E.[NINO]                                                        AS NINo
     , E.[Surname] + '', '' + E.[Forename]                               AS Name
     , E.[Surname]                              AS SurName
     , E.[Forename]                             AS ForeName
     , EMP.[EmploymentID]                                              AS EmploymentID
     , EMP.[ATT3_19_PayrollID]                                         AS ATT3_19_PayrollID     -- identifies EMP record
     , EMP.[ALC14_TaxCode]                                             AS ALC1_4_TaxCode
     , NI.[Employee_NI]                       AS NI_PK
     , NI.[Emp2_NILetter]                     AS EMP2_NILetter
    FROM [RTIDatastore].[dbo].[Header] H
     JOIN      [RTIDatastore].[dbo].[Employer]    R   ON H.[HeaderID] = R.[HeaderID_FK]
     LEFT JOIN [RTIDatastore].[dbo].[Employee]    E   ON R.[EmployerID] = E.[EmployerID_FK]
     LEFT JOIN [RTIDatastore].[dbo].[Employment]  EMP ON E.[EmployeeID] = EMP.[EmployeeID_FK]
     LEFT JOIN [RTIDatastore].[dbo].[Employee_NI] NI  ON EMP.[EmploymentID] = NI.[EmploymentID_FK]
    WHERE H.[SenderID] = @Product
     AND H.[MessageType] = ''FPS'' + @TaxYear
     AND R.[EmployerPAYE] = @PAYE
     AND NI.[Employee_NI] NOT LIKE ''%_NI_1''
    ORDER BY ' + @OrderTest + '
     , ICR
     , EmploymentID
     , NI_PK'
    
     exec sp_executesql @stmt = @sqlString, @params = N'@Product AS VARCHAR(20), @TaxYear AS CHAR(2), @EndPeriod AS INTEGER, @PAYE AS VARCHAR(20)', @Product = @Product, @TaxYear = @TaxYear, @EndPeriod = @EndPeriod, @PAYE = @PAYE
    

    【讨论】:

      【解决方案2】:

      也许您可以将查询包装到新的 SELECT 中,并将 order by 应用于整体结果。像这样:

      SELECT * FROM (
      
        -- Your original unioned query without order by here --
      
      ) T
      
      ORDER BY ...
      

      【讨论】:

      • 这是一种享受,也很简单!感谢@Jaques 的其他建议...
      【解决方案3】:

      不能直接使用参数进行排序.. 使用类似的东西

      SELECT * FROM TableName WHERE [Condition] ORDER BY 
      CASE @OrderByColumn
          WHEN Condition1 THEN Value1
          WHEN Condition2 THEN Value2
      

      【讨论】:

      • 谢谢 - 我试过这两种方法:'ORDER BY CASE @OrderBy WHEN 'N' THEN NINo WHEN 'P' THEN ATT3_19_PayrollID WHEN 'S' THEN Name END , ICR , EmploymentID , NI_PK '给出错误“Msg 207, Level 16, State 1, Line 76 Invalid column name 'Name'. Msg 104, Level 16, State 1, Line 77 ORDER BY 项必须出现在选择列表中,如果语句包含 UNION, INTERSECT或 EXCEPT 运算符。”
      • 和 'ORDER BY CASE @OrderBy WHEN 'N' THEN NINo WHEN 'P' THEN ATT3_19_PayrollID WHEN 'S' THEN SurName END , ICR , EmploymentID , NI_PK '错误“如果语句包含 UNION、INTERSECT 或 EXCEPT 运算符,则消息 104、级别 16、状态 1、第 77 行 ORDER BY 项必须出现在选择列表中。”
      • 这可能是因为您的 order by 使用了别名。尝试使用您在 select 语句中的内容,或者在插入 #temp 表中使用 select 查询,然后在该临时表中使用 Order by ..
      • 这可能是原因 - 使用额外的 SELECT 可以解决这个问题,所以我走了那条路。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-10
      • 2010-09-17
      • 1970-01-01
      • 2014-09-26
      • 2010-10-04
      • 2016-09-01
      • 1970-01-01
      相关资源
      最近更新 更多