Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 对SQL Server中存储为字符的虚线数字进行正确排序_Sql Server_Tsql_Sql Server 2005_Sql Order By - Fatal编程技术网

Sql server 对SQL Server中存储为字符的虚线数字进行正确排序

Sql server 对SQL Server中存储为字符的虚线数字进行正确排序,sql-server,tsql,sql-server-2005,sql-order-by,Sql Server,Tsql,Sql Server 2005,Sql Order By,我有一个存储自定义项目编号的SQL表。每一个都可以使用分隔符从中断开一个子项。。每个人也可以有一个孩子 这又是一个什么样的例子,动态的,不知道会是什么样的: Item Number 1 1.1 1.1.1 1.1.1.1 1.1.1.1.a 1.1.1.1.b 10 11 2.1 2.10 2.2 2.20 20 3 30 使这一点变得困难的是,这些数字是动态创建的,不一定是按顺序创建的。您可以创建5个数字1、2、3、4、5,然后创建1的子项,这样它就不会按顺序存储在数据库中 如何从表中选择并

我有一个存储自定义项目编号的SQL表。每一个都可以使用分隔符从中断开一个子项。。每个人也可以有一个孩子

这又是一个什么样的例子,动态的,不知道会是什么样的:

Item Number
1
1.1
1.1.1
1.1.1.1
1.1.1.1.a
1.1.1.1.b
10
11
2.1
2.10
2.2
2.20
20
3
30
使这一点变得困难的是,这些数字是动态创建的,不一定是按顺序创建的。您可以创建5个数字1、2、3、4、5,然后创建1的子项,这样它就不会按顺序存储在数据库中

如何从表中选择并按项目编号排序,以便在数据未按该顺序存储时,如上文所述正确显示


我尝试过的大多数解决方案要么给我1、2、3、4、5…1.1、1.2,要么给我1、1.1、1.1、10、11…2、2.1、20…3、30等等。这对我来说很好:

select cast(ItemNumber as nvarchar(25))
from (
    select '3.1' as ItemNumber
    union all
    select '1'
    union all
    select '3.2'
    union all
    select '3.2.1'
    union all
    select '3.2.1.1'
    union all
    select '3.2.1.2'
    union all
    select '2'
    union all
    select '3'
    union all
    select '3.1.1'
) a
order by ItemNumber
输出:

-------------------------
1
2
3
3.1
3.1.1
3.2
3.2.1
3.2.1.1
3.2.1.2

(9 row(s) affected)

如果您想对事物进行数字排序,请不要将它们存储为nvarchar

实际的解决方案是让这些数字成为自己的int字段,比如Version、Versiona、Versionb

然后按版本、版本A、版本B排序


如果您将数字存储为字符,不要期望它们像数字一样工作。

如果您有SQL 2008,则可以使用新的hierarchyid数据类型:

WITH Items (ItemNumber) AS (
    SELECT '1' UNION ALL SELECT '1.1' UNION ALL SELECT '1.1.1'
    UNION ALL SELECT '10' UNION ALL SELECT '11' UNION ALL SELECT '2'
    UNION ALL SELECT '2.1' UNION ALL SELECT '20' UNION ALL SELECT '3'
    UNION ALL SELECT '30'
)
SELECT *
FROM Items 
ORDER BY Convert(hierarchyid, '/' + ItemNumber + '/');
一些问题:

可以有多少子类别? 这些永远只是数字还是字母? 点与点之间的最大值是多少? 如果您使用的是SQL 2008,那么我推荐@Vito的答案,因为这是目前为止最好的方法

如果您使用的是早期版本,那么您必须做一些工作

这是一个SQL2005版本。我假设以上问题的答案是100,总是数字和99999999 10位数

WITH Items (ItemNumber) AS (
    SELECT '1' UNION ALL SELECT '1.1' UNION ALL SELECT '1.1.1'
    UNION ALL SELECT '10' UNION ALL SELECT '11' UNION ALL SELECT '2'
    UNION ALL SELECT '2.1' UNION ALL SELECT '20' UNION ALL SELECT '3'
    UNION ALL SELECT '30' UNION ALL SELECT '9999999999.9999999999'
), Padded AS (
   SELECT
      ItemNumber,
      Convert(nvarchar(max), '') SortValue,
      ItemNumber Remainder,
      0 Selector
   FROM Items
   UNION ALL
   SELECT
      ItemNumber,
      SortValue + Right('000000000' + Left(Remainder, CharIndex('.', Remainder + '.') - 1), 10),
      Substring(Remainder, CharIndex('.', Remainder + '.') + 1, 2147483647),
      CASE WHEN Remainder LIKE '%.%' THEN 0 ELSE 1 END
   FROM Padded
   WHERE
      Remainder <> ''
)
SELECT ItemNumber
FROM Padded
WHERE Selector = 1
ORDER BY SortValue;

对于SQL 2000来说,它将变得更加困难…

这更多的是一个玩笑,而不是一个真正的答案。如果

您的类别最多有4个级别 你真的不喜欢表演吗 然后试试这个:

WITH Items (ItemNumber) AS (
              SELECT '1' UNION ALL SELECT '1.1' UNION ALL SELECT '1.1.1'
    UNION ALL SELECT '-1' UNION ALL SELECT '1.-1' UNION ALL SELECT '1.-1.1'
    UNION ALL SELECT '10' UNION ALL SELECT '11' UNION ALL SELECT '2'
    UNION ALL SELECT '1.2000' UNION ALL SELECT '1.-2000' UNION ALL SELECT '2.1'
    UNION ALL SELECT '2.2' UNION ALL SELECT '20' UNION ALL SELECT '3'
    UNION ALL SELECT '30' UNION ALL SELECT '30.1' UNION ALL SELECT '10.10'
    UNION ALL SELECT '1.-10' UNION ALL SELECT '1.1.1.1'
)

SELECT ItemNumber
FROM 
  ( SELECT
          ItemNumber
        , CASE WHEN ItemNumber LIKE '%.%.%.%' THEN ItemNumber
               WHEN ItemNumber LIKE '%.%.%' THEN ItemNumber + '.0'
               WHEN ItemNumber LIKE '%.%' THEN ItemNumber + '.0.0'
               ELSE ItemNumber + '.0.0.0'
          END AS ItemNumberToParse
    FROM Items
  ) AS tmp
ORDER BY CAST(PARSENAME(ItemNumberToParse, 4) AS INT),
         CAST(PARSENAME(ItemNumberToParse, 3) AS INT),
         CAST(PARSENAME(ItemNumberToParse, 2) AS INT),
         CAST(PARSENAME(ItemNumberToParse, 1) AS INT) ;
结果:

  ItemNumber
    -1
    1.-2000
    1.-10
    1.-1
    1.-1.1
    1
    1.1
    1.1.1
    1.1.1.1
    1.2000
    2
    2.1
    2.2
    3
    10
    10.10
    11
    20
    30
    30.1

我在另一个论坛上讨论了这一点,我们提出了一个非常动态的XML解决方案。Adam Haines帮助对其进行了优化,从而显著提高了性能。此版本包括一个修复程序,用于正确排序字母数字

给定以下值:

declare @temp table (id varchar(255))

insert into @temp (id) values
  ('1.1.a.1'),('1.1.aa.2'),
  ('1.1.b.3'),('1.1.a.4'),
  ('1.1.a.5'),('1.1.a.6'),
  ('1.1.a.7'),('1.1.a.8'),
  ('1.1.a.9'),('1.1.a.10'),
  ('1.1.a.11'),('1.1.b.1'),
  ('1.1.b.2'),('1.2.a.1'),
  ('1.10.a.1'),('1.11.a.1'),
  ('1.20.a.1'),('101.20.a.2'),
  ('1.20.a.150'),('1.1'),
  ('1.2'),('1')
此查询:

declare @xml xml,
        @max_len int

set @xml =
(
select id as id, cast('<i>' + replace(id,'.','</i><i>') + '</i>' as xml)
from @temp
for xml path('id_root'),type
)

select @max_len = max(len(x.i.value('.','varchar(10)')))
from @xml.nodes('/id_root/i') x(i)

select [id]--, srt.srtvalue
from @temp
cross apply(
    select case when ISNUMERIC(x.i.value('.','varchar(10)')) = 1 then right(replicate('0',@max_len) + x.i.value('.','varchar(10)'),@max_len) else x.i.value('.','varchar(10)') end + '.'
    from @xml.nodes('/id_root/i') x(i)
    where x.i.value('../id[1]','varchar(50)') = [@temp].id
    for xml path('')
) as srt(srtvalue)
order by srt.srtvalue
如果一个数字中有超过10个字符,则必须适当更改varchar10


-James

请按位置按顺序尝试此查询,它在我的案例中起作用。我在varcharmax列中有相同的版本格式值

order by CAST (Substring( ItemNumberToParse, 1, CharIndex( '.', ItemNumberToParse ) - 1)as int)

将ItemNumber“10”添加到列表中。那会发生什么?期望的结果:“10”应该是列表中的最后一个。虽然我同意这一点,但有时很难重新设计您的数据库和所有使用它的依赖系统。@Vito我同意。一种选择是规范化实际数据,然后在视图中用旧表的名称重新组合它。基础数据是好的,他可以随心所欲地订购,而且应用程序没有损坏。你说得对。那就行了!使用这种方法,数据肯定会更有用。不幸的是,因为它是自定义的,所以他们可以使用字母和数字,例如1.2.a.1。还有,因为所有的。这不是一个数字。@Scott-我意识到句点使它成为非数字的,我要说的是将它分解成一系列整型字段,忽略句点。我假设数字实际上代表某个东西,比如Version.SubVersion.Build.Beta或类似的东西。它是SQL 200,子类别没有限制,可以是字母,除了SQL自身的限制之外,最大的数据没有上限。它是动态的,所以我不会提前知道所有值来编写带有“1”和“1.1”等的查询。您缺少实际答案,这只是选择查询。WITH仅用于提供一组数据来测试SELECT查询。查询在处理动态数据时仍然可以正常工作。下面的部分完成了这一切:ORDER BY CONVERThierarchyid,'/'+{your data here}+'/';这适用于所有数字。字母数字会导致.Net framework错误,该错误表示该值对于hierarchyid无效。字母将如何排序以及点之间项目的最大长度是多少?应排序为a-z、aa zz、aaa zzz等。无最大长度。Scott,看起来您的需求正在增长。你只提到开始时的数字,我花时间帮你,现在突然有字母了?而且,没有最大长度的声音,老实说,是不现实的。你真的会有8层,每层5000个字符?你需要对它们进行分类吗?为什么?
order by CAST (Substring( ItemNumberToParse, 1, CharIndex( '.', ItemNumberToParse ) - 1)as int)