【问题标题】:Truncate each word in a string with (T-)SQL使用 (T-)SQL 截断字符串中的每个单词
【发布时间】:2018-08-31 04:47:38
【问题描述】:

在固定数量的字符之后,如何“截断”SQL 中短语中的每个单词?

例如:我想通过查询检索到这个数据

select descrizione 
from mytable

所以都在同一列中。

FISIOPATOLOGIA DELLA RIPRODUZIONE UMANA
ODONTOIATRIA E STOMATOLOGIA
CHIRURGIA MAXILLO FACCIALE

像这样转换(如果超过 6 个字符则截断),仍然在一个列中:

FISIOL. DELLA RIPROD. UMANA
ODONTO. E STOMAT.
CHIRUR. MAXILL. FACCIA.

【问题讨论】:

  • 您使用的是哪个版本的 SQL Server?如果您使用的是 SQL Server 2016,则可以从 STRING_SPLIT() 开始很容易地做到这一点。
  • 需要更多信息。什么是“截断”规则?其中一些词没有被截断。没有明显的所需字符数模式。
  • 为什么所有的反对票?这实际上是一个很好且明确的问题。
  • @DDS 是您的示例数据一个完整的字符串,还是它们是表中的单独行?如果都是一个字符串,字符串中是否有换行符?
  • @HardCode 规则写得很清楚:取每个单词的前 6 个字符,如果单词较长,则 6 个字符在末尾添加一个点

标签: sql sql-server string tsql


【解决方案1】:

这使用了DelimitedSplit8k,因此依赖于你没有超过8000的值。为什么不STRING_SPLIT仍然缺少那个顺序位置列,这对于保持结果顺序相同至关重要。无论如何,我认为这就是你所追求的:

WITH VTE AS(
    SELECT *
    FROM (VALUES ('FISIOPATOLOGIA DELLA RIPRODUZIONE UMANA'),
                 ('ODONTOIATRIA E STOMATOLOGIA'),
                 ('CHIRURGIA MAXILLO FACCIALE')) V(String))
SELECT STUFF((SELECT ' ' + LEFT(DS.Item,6) + CASE WHEN LEN(DS.Item) > 6 THEN '.' ELSE '' END
              FROM dbo.DelimitedSplit8K(V.String,' ') DS
              ORDER BY DS.ItemNumber
              FOR XML PATH('')),1,1,'') AS ShortString
FROM VTE V;

【讨论】:

  • +1000。您击败了我发布几乎相同的解决方案,但您的解决方案比我的更干净、更简单。 :) 太傻了,STRING_SPLIT 错过了序数位置的关键部分。不知道为什么这么多其他分离器也错过了这一点。干得好!!
  • 感谢@SeanLange。缺少序数位置是我的一只巨大的臭虫熊。我确定我已经看到了有关添加它的连接项(或 MS 现在使用的任何内容),但我怀疑它会出现在下一个版本中。
  • 我承认,如果你使用像 ORDER BY ROW_NUMBER() OVER (ORDER BY(SELECT NULL)) 这样愚蠢的东西,STRING_SPLIT 是“相当”可靠的,但我是否想要 信任 SQL Server/函数按照给定的顺序返回它?我宁愿使用“安全”(和已知)选项而不是希望和梦想。 :)
  • @Larnu SQL-Server 在 v2016 中引入了 STRING_SPLIT。并介绍了OPENJSON。有一个很棒的fast and order-safe splitting approach。对于快速测试,您可以检查此SELECT * FROM OPENJSON('[3,1,5]'); SELECT * FROM OPENJSON('["a","b","c"]'); 将拆分字符串转换为 JSON 数组相当容易。
  • @SeanLange 我对 Larnu 的评论可能对你也有用。
【解决方案2】:

此解决方案需要 SQL-Server 2016 (for OPENJSON),但不需要任何功能:

DECLARE @tbl TABLE(ID INT IDENTITY, YourText VARCHAR(100));
INSERT INTO @tbl VALUES
 ('FISIOPATOLOGIA DELLA RIPRODUZIONE UMANA')
,('ODONTOIATRIA E STOMATOLOGIA')
,('CHIRURGIA MAXILLO FACCIALE');

DECLARE @maxLength INT = 6;

SELECT t1.ID
      ,t1.YourText
      ,STUFF((
        SELECT ' ' + CASE WHEN LEN(A.[value])<=6 THEN A.[value] ELSE LEFT(A.[value],@maxLength) + '.' END
        FROM OPENJSON('["' + REPLACE(t1.YourText,' ','","') + '"]') A
        ORDER BY A.[key]
        FOR XML PATH(''),TYPE
       ).value('text()[1]','nvarchar(max)'),1,1,'')
FROM @tbl t1

OPENJSON 在解析数组时返回[key] 列中的序号位置。

【讨论】:

  • 不错。这看起来很有趣。我目前没有 2016+ 实例,但我很快就会站起来看看这个。谢谢分享!!
  • 和 Sean 一样,我没有访问 SQL Server 2016 的权限,所以我没有机会在实践中了解 JSON 语法。 STRING_SPLITDelimitedSplit8K 使用相同,所以很容易记住。 :),我以前见过这个解决方案,如果肯定是一个很好的选择,特别是如果有人在他们的varchar/nvarchar 中有超过 8000/4000 个字符。
猜你喜欢
  • 2019-01-03
  • 2013-09-23
  • 2010-12-09
  • 1970-01-01
  • 2011-10-02
  • 1970-01-01
  • 2021-10-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多