SQL Server динамический ORDER BY со смешанными типами данных: это хорошая идея? - PullRequest
3 голосов
/ 07 сентября 2010

У меня есть хранимая процедура, которая возвращает результаты, отсортированные динамически.Родительская папка (это для управления контентом) имеет поле RankTypeID, которое позволяет сортировать по рангу (0), дате начала в порядке возрастания (1), дате начала в порядке убывания (2) и заголовку документа (3)

Ранг - целое число, дата - smalldatetime, а заголовок - nvarchar.

...

ORDER BY
    Case Parent.RankTypeID
      When 0 Then dbo.Folders.Rank
      When 1 Then Cast(dbo.Documents.SortableDateStart As bigint)
      When 2 Then (1 - Cast(dbo.Documents.SortableDateStart As bigint))
      When 3 Then Cast(dbo.Documents.Title as sql_variant)
    End

Я настроил SortableDateStart как вычисляемый столбец, чтобы использовать DateStart smalldatetimeстолбец и преобразовать его в bigit для сортировки.Он принимает дату ISO8601 (разработана для использования в формате xml, а также удобна для сортировки) и заменяет символы T,: и -

(replace(replace(replace(CONVERT([varchar](16),[DateStart],(126)),'T',''),'-',''),':',''))

Это довольно уродливо.Есть лучший способ сделать это?Я также открыт для более эффективных способов обработки этой динамической сортировки.

Редактировать: Настройка данных теста

DECLARE @Temp TABLE
(
[Rank] int,
[Title] nvarchar(100),
[DateStart] datetime
)

INSERT into @Temp
SELECT 1, 'title1', '1/1/2010 10:01:00AM'
UNION
SELECT 2, 'atitle1', '1/1/2010 10:03:00AM'
UNION
SELECT 3, 'title1', '1/1/2010 10:10:00AM'
UNION
SELECT 4, 'btitle1', '1/1/2010 10:04:00AM'
UNION
SELECT 10, 'title1', '1/1/2010 10:07:00AM'
UNION
SELECT 11, 'dtitle1', '1/1/2010 10:09:00AM'
UNION
SELECT 12, 'ctitle1', '1/1/2010 10:00:01AM'
UNION
SELECT 13, 'title1', '1/1/2010 10:10:00AM'

DECLARE @RankTypeID tinyint
--SET @RankTypeID = 0 -- rank
--SET @RankTypeID = 1 -- date start asc
SET @RankTypeID = 2 -- date start desc
--SET @RankTypeID = 3 -- title

SELECT 
    [Rank],
    [DateStart],
    [Title]
FROM
    @Temp
ORDER BY
    Case @RankTypeID
      When 0 Then [Rank]
      When 1 Then Cast([DateStart] As sql_variant)
      When 3 Then [Title]
      else null
    End,      
    Case @RankTypeID
      When 2 Then Cast([DateStart] As sql_variant)
    End DESC

Ответы [ 3 ]

7 голосов
/ 07 сентября 2010

Попробуйте что-то подобное

ORDER BY
    Case Parent.RankTypeID
      When 0 Then dbo.Folders.Rank
      When 1 Then dbo.Documents.DateStart
      When 3 Then Cast(dbo.Documents.Title as sql_variant)
      else null
    End,      
    case Parent.RankTypeID
      when 2 Then dbo.Documents.DateStart
    end desc

Обновление.

Нет, вам не нужно ничего разыгрывать.Вот полное решение для ваших тестовых данных.

order by 
case @RankTypeID when 0 then [Rank] else null end,      
case @RankTypeID when 1 then [DateStart] else null end,
case @RankTypeID when 2 then [DateStart] else null end desc,
case @RankTypeID when 3 then [Title] else null end 
2 голосов
/ 07 сентября 2010

Один из способов - отделить значение сортировки от фактического ORDER BY

SELECT
   col1, col2, ...
FROM
   (
   SELECT
      col1, col2, ...,
      ROW_NUMBER() OVER (ORDER BY Rank) AS RankASC,
      ROW_NUMBER() OVER (ORDER BY DateStart) AS DateStartASC,
      ROW_NUMBER() OVER (ORDER BY Title) AS TitleASC
   FROM
      MyTable
   ) foo
ORDER BY
    Case foo.RankTypeID
      When 0 Then foo.RankAsc
      When 1 Then foo.DateStartAsc
      When 2 Then -1 * foo.DateStartAsc
      When 3 Then foo.TitleAsc
      --else null needed?
    End

Если вы хотите определить @SortOrder (или как столбец) как 1 = ASC, -1 = DESC, тогда вы можетесделай это

SELECT
   col1, col2, ...
FROM
   (
   SELECT
      col1, col2, ...,
      ROW_NUMBER() OVER (ORDER BY Rank) AS RankOrder,
      ROW_NUMBER() OVER (ORDER BY DateStart) AS DateStartOrder,
      ROW_NUMBER() OVER (ORDER BY Title) AS TitleOrder
   FROM
      MyTable
   ) foo
ORDER BY
    @SortOrder *
      Case foo.RankTypeID
        When 0 Then foo.RankOrder
        When 1 Then foo.DateStartOrder
        When 3 Then foo.TitleOrder
      End
0 голосов
/ 21 августа 2013

Другой пример рабочего полного решения приведен ниже

--TEST DATA
DECLARE @MYTable TABLE (EmpID INT, EmpName VARCHAR(10) , JoinDate DATETIME)

INSERT INTO @MYTable VALUES (1,'E1','1/1/2001');
INSERT INTO @MYTable VALUES (2,'E2','2/2/2002');
INSERT INTO @MYTable VALUES (3,'E3','5/5/2001');

--INPUT Parameters
DECLARE @SortParam VARCHAR(MAX)
SET @SortParam = 'JoinDate'

DECLARE @SortDirection VARCHAR(MAX)
SET @SortDirection = 'DESC'


--@RankTypeID Variable
DECLARE @RankTypeID  INT

--EMPNAME
IF (@SortParam = 'EmpName' AND @SortDirection = 'ASC')
BEGIN 
    SET @RankTypeID = 1 
END

IF (@SortParam = 'EmpName' AND @SortDirection = 'DESC')
BEGIN
    SET @RankTypeID = -1    
END

--EmpID
IF (@SortParam = 'EmpID' AND @SortDirection = 'ASC')
BEGIN 
    SET @RankTypeID = 2 
END

IF (@SortParam = 'EmpID' AND @SortDirection = 'DESC')
BEGIN
    SET @RankTypeID = -2
END

--JoinDate
IF (@SortParam = 'JoinDate' AND @SortDirection = 'ASC')
BEGIN 
    SET @RankTypeID = 3 
END

IF (@SortParam = 'JoinDate' AND @SortDirection = 'DESC')
BEGIN
    SET @RankTypeID = -3
END


-- SELECT
SELECT * 
FROM @MYTable M
ORDER BY 
        CASE @RankTypeID WHEN 1 then EmpName ELSE null end ASC,
        CASE @RankTypeID WHEN -1 then EmpName ELSE null end DESC,

        CASE @RankTypeID WHEN 2 then [EmpID] else null end ASC ,
        CASE @RankTypeID WHEN -2 then [EmpID] else null end DESC ,

        CASE @RankTypeID WHEN 3 then JoinDate else null end  ASC,
        CASE @RankTypeID WHEN -3 then JoinDate else null end  DESC


--END
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...