【问题标题】:Sorting by part of a string按字符串的一部分排序
【发布时间】:2012-04-21 14:34:36
【问题描述】:

基本上我有一个像这个例子一样的“歌曲”表。

我需要获取数据并在网格视图中显示。桌子很乱,歌曲可以按任​​何顺序排列,不一定按专辑或歌手分组。我需要先按歌手对行进行排序,它应该按字母顺序对艺术家进行排序。专辑也应该分组。但更重要的是,歌曲应按字母顺序/或数字排序。

上表显示了我想要的理想排序列表。谁能指出如何为此编写T-SQL。我正在使用 SQL Server 2008 R2。

【问题讨论】:

  • 您希望歌曲按字母顺序还是按数字排序?你不能两者都做。
  • 歌曲只需要按编号排序谢谢:)

标签: sql-server tsql sorting sql-server-2008-r2


【解决方案1】:

您需要选择是要按字母顺序(恕我直言,不太可能)还是按数字(更可能,因为我不想以任何顺序听《月亮的黑暗面》)初衷)。正如我在上面的评论中提到的那样,你不能两者都做。

按数字排序:

SELECT Title, Singer, Album
  FROM dbo.Songs
  ORDER BY Singer, Album, 
    CONVERT(INT, SUBSTRING(Title, 1, CHARINDEX('.', Title)));

按字母顺序对标题进行排序:

SELECT Title, Singer, Album
  FROM dbo.Songs
  ORDER BY Singer, Album, 
    SUBSTRING(Title, CHARINDEX('.', Title) + 1, 255); 
    -- 255 or whatever the column is defined as

很多人会建议LEN(Title),但对我来说这是一个不必要的计算。恕我直言,唯一合理的情况是模式发展迅速并且该列的最大长度不能被认为是“稳定的”的情况。在这些情况下,我可能仍然建议只使用一个更高的数字,以适应该列未来的任何大小增加,例如4000

正如@a1ex07 所暗示的,您应该考虑将数字和标题分开存储。你可以这样做:

ALTER TABLE dbo.Songs ADD SongNumber TINYINT;
ALTER TABLE dbo.Songs ADD SongTitle VARCHAR(255);

UPDATE dbo.Songs SET 
  SongNumber = CONVERT(TINYINT, SUBSTRING(Title, 1, CHARINDEX('.', Title))),
  SongTitle  = SUBSTRING(Title, CHARINDEX('.', Title) + 1, 255);

-- once you've verified:    
ALTER TABLE dbo.Songs DROP COLUMN Title;

您还必须更新访问此表的所有进程(或创建一个视图并将它们指向该视图)。现在,如果您想按SongNumberSongTitle 排序,您的ORDER BY 子句要简单得多。 (但您仍然无法同时对两者进行排序,如果您考虑一下,这很有意义。)

【讨论】:

  • +1 不错的答案,除了微优化字符串操作。甚至在 2012 年提到 len 的成本也很奇怪。
  • @Andomar 我不明白,为什么在不需要的时候执行计算,即使增量成本是最小的?
  • 让我明确一点,我并不是说需要重写包含 LEN() 的代码,如“我看到你有 LEN() 在那里,让我们加倍通过删除查询来提高查询的性能。”那是微优化,没有保证。我的反对意见是,当 LEN() 不是必要的、浪费的并且不是原始问题的一部分时,社区中受人尊敬的成员将 LEN() 作为答案提供。虽然是的,“浪费”可以忽略不计,但我认为它背后的想法更有害——整个“嗯,它没那么贵……”有点像“磁盘空间很便宜”的论点。
  • 谢谢亚伦,很好的答案,但我想没有更简单的解决方案了.. 除了打破城镇表,如歌曲表、艺术家表和专辑表......
  • 如果您按数字排序,我认为解决方案不会那么复杂。如果您将 number 放在它自己的列中,您可能可以使它更简单一些,但这并没有真正改变查询。也就是说,如果您要存储 很多 专辑,将艺术家和专辑分到各自的表格中可能会很有意义,这样您就不会重复 Pink Floyd 和 @987654331 @ 表示该专辑中的每一首歌曲。现在,您的架构非常非规范化,在某些情况下还可以,甚至更可取。
【解决方案2】:
select  *
from    Songs
order by
        Singer
,       Album
,       Title

【讨论】:

  • 这将按数字排序,但不考虑 OP 的其他选项(按字母顺序对标题进行排序 - 大概不包括前导 01. 等)。
【解决方案3】:

看起来,按Singer, Album,Title 排序的唯一问题是标题包含数字和字符串(这不好,因为它破坏了 1NF)。如果您对title 格式非常确定,您可以这样做

ORDER BY Singer, Album,
cast(substring(Title,0,CHARINDEX( '.',Title)) as int),
substring(Title,CHARINDEX( '.',Title)+1,LEN(Title))
-- LEN(Title) should work, even though it would be more correct to put the right number of
-- characters (from position of '.' to the end)

【讨论】:

  • 我不认为将标题的其余部分转换为INT 会起作用(也许你的意思是VARCHAR(something)?)。另外我认为您的最后一个括号的位置不正确。
  • @Aaron Bertrand:是的,复印时打印错误。修复
  • 谢谢a1ex07,顺便说一句,你是什么意思它打破了1NF?我承认我不是真正的前端设计师,也不是真正的 db 人。你能为我推荐一个更好的数据库接口吗?谢谢..
  • @Laurence Nyein:您在 1 列中存储 2 个实体:数字(例如,01)和标题(例如“某个时间”)。 1NF 要求所有列都是规则的(只保留一个属性)。我有一列带有数字(整数类型之一)和 varhar/varchar2 作为标题本身。
  • 你认为我是否应该再多一列(可能是 SortOrder)只存储数字(1、2、3)用于排序顺序?
猜你喜欢
  • 2014-02-21
  • 2012-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-20
  • 2017-11-23
  • 2012-11-10
相关资源
最近更新 更多