SQL按数字排序作为子字符串

时间:2015-05-19 09:30:20

标签: sql-server

我有这样的数据

Name     SortOrder
-------------------
Lower 1      3
Lower 10      2
Lower 2      1
Lower 1%     6 
Lower 1.5%   5
Lower 3%     4
Average      7 
Upper 1      10
Upper 10      8
Upper 1%     12
Upper 1.5%   11
Average       10  /* sorted 
Average Poor  11  * alphabetically
Rich          12  * only */
Min_Low10     17
Min_Low20     18
Min_Low30     19
Min_Up10      20
Min_Up20      21
Min_Up30      22

我想更新排序顺序,这样当我按它排序时,它就像这样

Name     SortOrder
-------------------
Lower 3%     1
Lower 1.5%   2
Lower 1%     3 
Lower 10      4
Lower 2      5
Lower 1      6
Min_Low30     7
Min_Low20     8
Min_Low10     9
Average       10  /* sorted 
Average Poor  11  * alphabetically
Rich          12  * only */
Min_Up10      13
Min_Up20      14
Min_Up30      15
Upper 1      16
Upper 2      17
Upper 10      18
Upper 1%     19
Upper 1.5%   20

即。具有数字的那些子组应该按升序或降序排序(取决于它的低位还是高位),而其他任何没有数字的小组都应该按字母顺序排序并放入其间。

我认为我按每个子组的第一个字符分组然后转换数字和顺序。但是当我尝试转换它时,它会给我一条错误消息:Error converting data type varchar to numeric.

SELECT * 
  ,RowNum =
  CASE 
      WHEN Name LIKE 'Lower %[%]' THEN 
          ROW_NUMBER() over (partition by SUBSTRING(Name,1,5) ORDER By CAST(SUBSTRING(Name,7,LEN(Name)-3) as decimal) DESC)
      WHEN Name LIKE 'Lower %' THEN 
          ROW_NUMBER() over (partition by SUBSTRING(Name,1,5) ORDER By SUBSTRING(Name,7,LEN(Name)) DESC)
      WHEN Name LIKE 'Upper %[%]' THEN 
          (ROW_NUMBER() over (partition by SUBSTRING(Name,1,5) ORDER By SUBSTRING(Name,7,LEN(Name)-3)))
      WHEN Name LIKE 'Upper %' THEN 
          (ROW_NUMBER() over (partition by SUBSTRING(Name,1,5) ORDER By SUBSTRING(Name,7,LEN(Name))))

      ELSE -1
  END
  FROM Table1 
  ORDER BY RowNum

这是sqlfiddle

编辑:更改了数据值,因为它们包含1和10,如果它们是varchars,则排序错误。

3 个答案:

答案 0 :(得分:1)

以下是您可以用来更新表格或直接获得结果的基本SELECT

使用以下方法解决了问题:

public static String getDateInFormate(String oldFormate , String newFormate , String dateToParse){
    //old "yyyy-MM-dd hh:mm"
    //new yyyy-MM-dd
    //dateTopars 2011-04-13 05:00  
    String formatedDate="";
    Format formatter = new SimpleDateFormat();
    Date date;
    try {
        date = (Date)((DateFormat) formatter).parse(dateToParse);
        formatter = new SimpleDateFormat(newFormate);
        formatedDate = formatter.format(date);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return formatedDate;    
} 

答案 1 :(得分:1)

你可以试试这个:

select *
    , RowNum =
     ROW_NUMBER() over (order by 
        case 
            when Name LIKE 'Lower %[%]' then 1
            when Name LIKE 'Lower %' then 2
            when Name LIKE 'Min_Low%' then 3
            when Name LIKE 'Min_Up%' then 5
            when Name LIKE 'Upper %[%]' then 7
            when Name LIKE 'Upper %' then 6
            else 4
        end
        , convert(numeric(6,2), case 
            when Name LIKE 'Lower %[%]' then replace(replace(Name, 'Lower ',''),'%', '')
            when Name LIKE 'Lower %' then replace(Name, 'Lower ','')
            when Name LIKE 'Min_Low%' then replace(Name, 'Min_Low','')
        end) desc
        , convert(numeric(6,2), case 
            when Name LIKE 'Min_Up%' then replace(Name, 'Min_Up','')
            when Name LIKE 'Upper %[%]' then replace(replace(Name, 'Upper ',''),'%', '')
            when Name LIKE 'Upper %' then replace(Name, 'Upper ','')
        end)
        , Name
    ) 
from #Table1

<强>更新

以下是更新声明:

update #Table1 set SortOrder = t2.RowNum
from #Table1 t1
  join (
select *
    , RowNum =
     ROW_NUMBER() over (order by 
        case 
            when Name LIKE 'Lower %[%]' then 1
            when Name LIKE 'Lower %' then 2
            when Name LIKE 'Min_Low%' then 3
            when Name LIKE 'Min_Up%' then 5
            when Name LIKE 'Upper %[%]' then 7
            when Name LIKE 'Upper %' then 6
            else 4
        end
        , convert(numeric(6,2), case 
            when Name LIKE 'Lower %[%]' then replace(replace(Name, 'Lower ',''),'%', '')
            when Name LIKE 'Lower %' then replace(Name, 'Lower ','')
            when Name LIKE 'Min_Low%' then replace(Name, 'Min_Low','')
        end) desc
        , convert(numeric(6,2), case 
            when Name LIKE 'Min_Up%' then replace(Name, 'Min_Up','')
            when Name LIKE 'Upper %[%]' then replace(replace(Name, 'Upper ',''),'%', '')
            when Name LIKE 'Upper %' then replace(Name, 'Upper ','')
        end)
        , Name
    ) 
from #Table1) t2 on t1.Name=t2.Name

答案 2 :(得分:0)

稍微压缩的版本:

SELECT Name 
FROM (SELECT Name, SUBSTRING(Name, PATINDEX('%[0-9]%', Name), LEN(Name)
                                   - PATINDEX('%[0-9]%', Name)
                                   - PATINDEX('%[0-9]%', REVERSE(Name)) + 2) n FROM @t) t
ORDER BY ROW_NUMBER() OVER 
(ORDER BY CASE WHEN Name LIKE 'lower %[%]' THEN 1
               WHEN Name LIKE 'lower %' THEN 2
               WHEN Name LIKE 'min_low%' THEN 3
               WHEN Name LIKE 'min_up%' THEN 5
               WHEN Name LIKE 'upper %[%]' THEN 7
               WHEN Name LIKE 'upper %' THEN 6
               ELSE 4 END, 
          CASE WHEN Name LIKE 'lower%' OR Name LIKE 'min_low%' 
               THEN CAST(n AS DECIMAL(10, 2)) END DESC, 
          CASE WHEN Name LIKE 'upper%' OR Name LIKE 'min_up%' 
               THEN CAST(n AS DECIMAL(10, 2)) END, 
          Name)