【问题标题】:String truncate on length, but no chopping up of words allowed字符串长度截断,但不允许截断单词
【发布时间】:2011-10-02 19:08:13
【问题描述】:

我想将 MYSQL 中的字符串字段长度限制在一定长度,但我不希望发生任何切词。

当我这样做时:

SELECT SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 28)

我得到这个作为输出:

Business Analist met focus o

但我愿意

Business Analist met focus

如何执行 28 个字符的限制,但又能防止切词?当然,[在此处插入选择的编程语言]很容易;-),但我想知道在 MYSQL 中是否可以通过简单的语句来实现。

【问题讨论】:

  • 您正在 MySQL 中寻找“自动换行”。有点。
  • 这里需要逻辑。换句话说,您需要一个 if 语句。如果 MySQL 支持 if,则使用 that,否则,没办法
  • 我认为这对 mysql 来说是相当昂贵的操作。只需在您使用的任何编程语言中砍掉这个词并在以后摆脱它。
  • @keymone 并非如此,请参阅sitepoint.com/mysql-mistakes-php-developers 的第 5 点(5. 优先使用 PHP 而不是 SQL)
  • @bicycle 在你的 PHP 中实现 AVG 和做子字符串是有区别的。很有可能,如果您正在执行子字符串,则无论如何您都需要在 php 中执行其他更复杂的操作。

标签: mysql sql substring


【解决方案1】:

如何在空格上分割:

SELECT SUBSTRING_INDEX('Business Analist met focus op wet- en regelgeving',' ',4)

会回来

Business Analist met focus

【讨论】:

    【解决方案2】:

    @str 成为您的字符串,@len 是要剪切的初始位置。那么必要的步骤可能是:

    1. @str最左边的@len字符。

    2. 反转子串。

    3. 找到反转子串中第一个空格的位置。

    4. 从该位置减去1。但是如果没有找到空格,就让位置保持0

    5. @len 中减去找到的位置,并将其命名为cutpos

    6. @str的第一个(最左边)cutpos字符作为str1,将所有其他字符(从cutpos+1开始)作为str2

    SELECT
      LEFT(str, cutpos) AS str1,
      SUBSTRING(str, cutpos + 1) AS str2
    FROM (
      SELECT
        @str AS str,
        @len - IFNULL(NULLIF(LOCATE(' ', REVERSE(LEFT(@str, @len))), 0) - 1, 0) AS cutpos
    ) s
    

    【讨论】:

      【解决方案3】:

      非常有趣的问题。我是这样做的:

      //gets initial string - use 29 instead of 28 to see if the 29th  character is a space
      SELECT SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29) 
      
      //inverts the string, so we can get the first 
      SELECT REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29))
      
      // find the charindex of the first space (last space in the string not reversed)
      SELECT CHARINDEX(' ', REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29)))
      
      // get the substring from the first (last) space
      SELECT  SUBSTRING(REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29)), CHARINDEX(' ', REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29))), 29)
      
      // reverse the string again to unfold it.
      SELECT REVERSE(SUBSTRING(REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29)), CHARINDEX(' ', REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29))), 29))
      
      
      // to try different lengths...
      DECLARE  @size  int
      select @size = 24
      SELECT REVERSE(SUBSTRING(REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, @size)), 
      CHARINDEX(' ', REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, @size))), @size))
      

      【讨论】:

      • charindex 不是有效的 mysql 函数。它应该是 LOCATE 。顺便说一句,这应该是最好的答案。
      • 这对我有用,但我必须将 CHARINDEX 更改为 LOCATE
      【解决方案4】:

      在 SQL 中它会是...

      select Substring('Business Analist met focus op wet- en regelgeving', 0 , 28 + 2 - CharIndex(' ',  REVERSE(SUBSTRING('Business Analist met focus op wet- en regelgeving', 0, 28 + 1 )),0))
      

      我不知道这些功能在MYSQL中是否都可用

      编辑:我认为 MYSQL 用“Locate”替换“CharIndex”

      【讨论】:

        【解决方案5】:

        以纳尼安的回答为基础,这是一个适用于两个字段 (a.product,a.descr) 的回答,其中在字符串被截断时添加了“...”。 a.descr 也可以为空。

          IF (
        CHARACTER_LENGTH(
          IF(
            a.descr = '',
            a.product,
            CONCAT_WS(' - ',a.product,a.descr)
          )
        )>35,
        IF(
          a.descr = '',
          CONCAT(
            REVERSE(SUBSTRING(REVERSE( SUBSTRING(a.product, 1, 35)), locate(' ', REVERSE( SUBSTRING(a.product, 1, 35))), 35)),
            '...'
          ),
          CONCAT(
            REVERSE(SUBSTRING(REVERSE( SUBSTRING(CONCAT_WS(' - ',a.product,a.descr), 1, 35)), locate(' ', REVERSE( SUBSTRING(CONCAT_WS(' - ',a.product,a.descr), 1, 35))), 35)),
            '...'
          )
        ),
        CONCAT_WS(' - ',a.product,a.descr)
        )
        

        我需要这样的东西,所以我添加了它。可能会帮助别人。

        【讨论】:

        • 是不是你在 3 小时前否决了我的回答?如果是这样,如果您详细说明您的原因,我将不胜感激。顺便说一句,当您检查开头的长度时,您正在验证descr 是否为空,并根据此情况单独检查product 的长度或以- 分隔的两列的长度。但是稍后,当您真正找到要剪切的位置时,您不再检查descr 是否为空。我认为,有时这可能不会导致最精确的切割。
        • 确实如此,好点。我刚刚调整了一下。是的,我对你投了反对票,因为另一个答案在没有太多定制的情况下更容易实现。不过应该调整它,因为 charindex 不是有效的 mysql 方法,而问题是关于 mysql。应该改为定位。
        • 但不包括在指定长度内找不到空格的情况。事实上,你的也没有。不过,我意识到省略这种情况可能会使该解决方案看起来更容易。无论哪种方式,感谢您解释您的反对意见!
        【解决方案6】:

        @Andriy M. 我非常喜欢你的回答 :) 无论如何,我在我的数据库上发现,如果您像这样更改第 2 行和第 3 行,效果会更好:

        SELECT
          IF(LENGTH(str)<=@len,str,LEFT(str, cutpos)) AS str1,
          IF(LENGTH(str)<=@len,'',SUBSTRING(str, cutpos + 1)) AS str2
        FROM (
          SELECT
            @str AS str,
            @len - IFNULL(NULLIF(LOCATE(' ', REVERSE(LEFT(@str, @len))), 0) - 1, 0) AS cutpos
          FROM @table
        ) s
        

        不知道是我的错还是什么,但另一方面它有时会在第一个字母的长度为

        我给你发布一个工作示例:

        CREATE TABLE `test` (
          `sometext` varchar(65)
        );
        
        INSERT INTO `test` (`sometext`) VALUES
        ('Firs strin'),
        ('Alll right'),
        ('third string'),
        ('fourth string'),
        ('a longer example string'),
        ('Supercalifragilisticexpialidocious');
        
        SELECT
          IF(LENGTH(str)<=12,str,LEFT(str, cutpos)) AS str1,
          IF(LENGTH(str)<=12,'',SUBSTRING(str, cutpos + 1)) AS str2
        FROM (
          SELECT
            sometext AS str,
            12 - IFNULL(NULLIF(LOCATE(' ', REVERSE(LEFT(sometext, 12))), 0) - 1, 0) AS cutpos
          FROM test
        ) s
        

        这是一个使用您的原始代码的不工作示例:

        SELECT
          LEFT(str, cutpos) AS str1,
          SUBSTRING(str, cutpos + 1) AS str2
        FROM (
          SELECT
            sometext AS str,
            12 - IFNULL(NULLIF(LOCATE(' ', REVERSE(LEFT(sometext,12))), 0) - 1, 0) AS cutpos
          FROM test
        ) s
        

        我不确定这是不是 utf8 问题,或者我只是误解了您的代码,或者其他什么...

        【讨论】:

          【解决方案7】:

          简单功能:

          DROP FUNCTION IF EXISTS fn_maxlen;
          delimiter //
          CREATE FUNCTION fn_maxlen(s TEXT, maxlen INT) RETURNS VARCHAR(255)
          BEGIN
          
           RETURN LEFT(s, maxlen - LOCATE(' ', REVERSE(LEFT(s, maxlen))));
          
          END//
          delimiter ;
          

          用途:

          SELECT fn_maxlen('Business Analist met focus op wet- en regelgeving', 28);
          

          【讨论】:

            【解决方案8】:

            似乎人们不阅读mysql手册:

            原文:SELECT SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 28) 给出断句。

            修改:SELECT SUBSTRING_INDEX('Business Analist met focus op wet- en regelgeving', ' ' , 4) 给出完整的单词

            SUBSTRING_INDEX(string, delimiter, number) 将根据找到分隔符的次数截断字符串。 让你的分隔符成为一个空格,你只会得到整个单词。所以:

            SUBSTRING_INDEX( LEFT('Business Analist met focus op wet- en regelgeving',28), ' ' , 4) 应该这样做。

            【讨论】:

            • 似乎有些人不假设通用输入......答案应该适用于任意数量的单词,而不仅仅是 4 个!无论如何,SUBSTRING_INDEX 函数很有趣。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-01-03
            • 1970-01-01
            • 2021-10-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多