Разрыв подстроки SQL Server на словах, а не на символах

Я хотел бы показывать не более n символов текстового поля в результатах поиска, чтобы дать пользователю представление о содержании. Тем не менее, я не могу найти способ легко разбивать слова, поэтому в конце я получаю неполное слово в разрыве.

Когда я хочу показать: «Этот учащийся не сдал свои последние несколько заданий», система может показать: «Этот учащийся не сдал свои последние несколько заданий».

Я бы предпочел, чтобы система отображалась до предела n символов, при котором слова сохраняются, поэтому я хотел бы видеть:

"Этот студент не сдал свои последние несколько"

Есть ли ближайшая функция слова, которую я мог бы написать на T-SQL, или мне следует сделать это, когда я получу результаты обратно в ASP или .NET?


person Caveatrob    schedule 06.04.2009    source источник


Ответы (7)


Если вы должны сделать это в T-SQL:

DECLARE @t VARCHAR(100)
SET @t = 'This student has not submitted his last few assignments'

SELECT LEFT(LEFT(@t, 50), LEN(LEFT(@t, 50)) - CHARINDEX(' ', REVERSE(LEFT(@t, 50))))

Это не будет катастрофически медленно, но определенно будет медленнее, чем на уровне представления.

Помимо этого, просто отрезать слово и добавить многоточие для более длинных строк тоже неплохой вариант. Таким образом, по крайней мере, все усеченные строки имеют одинаковую длину, что может пригодиться, если вы форматируете вывод с фиксированной шириной.

person Tomalak    schedule 06.04.2009

Я согласен делать это за пределами базы данных, чтобы другие приложения с различными ограничениями длины могли принимать собственные решения о том, что показывать/скрывать. Возможно, это может быть параметром вызова базы данных.

Вот быстрый удар по решению:

DECLARE @OriginalData NVARCHAR(MAX)
    ,@ReversedData NVARCHAR(MAX)
    ,@MaxLength INT 
    ,@DelimiterPosition INT ;

SELECT @OriginalData = 'This student has not submitted his last few assignments'
    ,@MaxLength = 45;

SET @ReversedData = REVERSE(
                        LEFT(@OriginalData, @MaxLength)
                    );

SET @DelimiterPosition = CHARINDEX(' ', @ReversedData);

PRINT LEFT(@OriginalData, @MaxLength - @DelimiterPosition);

/*
This student has not submitted his last few assignments
1234567890123456789012345678901234567890123456789012345
*/
person Bennett Dill    schedule 06.04.2009

Я рекомендую использовать такую ​​логику вне базы данных. С C# это может выглядеть примерно так:

static string Cut(string s, int length)
{
    if (s.Length <= length)
    {
        return s;
    }

    while (s[length] != ' ')
    {
        length--;
    }

    return s.Substring(0, length).Trim();
}

Конечно, вы могли бы сделать это с помощью T-SQL, но это плохая идея (плохая производительность и т. д.). Если вам действительно нужно поместить его в БД, я бы вместо этого использовал хранимую процедуру на основе CLR.

person Konstantin Tarkus    schedule 06.04.2009

Я хотел бы добавить к уже предложенным решениям, что логика разбиения слов намного сложнее, чем кажется на первый взгляд. Чтобы сделать это хорошо, вам нужно будет определить ряд правил для того, что составляет слово. Рассмотрим следующее:

  • Пробелы - без проблем.
  • Дефисы - Ну, это зависит. В переэкспонированном скорее всего, в реанимированном скорее всего нет. А как насчет таких дат, как 01-02-1985?
  • Месячные - это не проблема. Ой, подождите, а как насчет адреса [email protected] или $79,95?
  • Запятые — в числах, таких как 1239, нет, а в предложениях — да.
  • Апострофы — в O'Reily нет, в SQL является инструментом корпоративной базы данных да.
  • Составляют ли слова только специальные символы?: В Пункте 1: Покупка TP считается ли двоеточие словом?
person JohnFx    schedule 06.04.2009
comment
Определенно. Я думаю, именно по этой причине обычные сетки данных используют метод «вырезать и добавить многоточие». - person Tomalak; 06.04.2009

Я нашел ответ на этом сайте и изменил его. :

  • актерский состав (150) должен быть больше, чем количество возвращаемых символов (100)

    LEFT (Cast(myTextField As varchar(150)), CHARINDEX(' ', CAST(flag_myTextField AS VARCHAR(150)), 100)) AS myTextField_short

person Caveatrob    schedule 06.04.2009

Я не уверен, насколько быстро это будет работать, но это сработает....

DECLARE @Max  int

SET @Max=??

SELECT
   REVERSE(RIGHT(REVERSE(LEFT(YourColumnHere,@Max)),@Max- CHARINDEX(' ',REVERSE(LEFT(YourColumnHere,@Max)))))
    FROM YourTable
    WHERE X=Y
person KM.    schedule 06.04.2009

Я бы тоже не советовал этого делать, но если вам нужно, вы можете сделать что-то вроде этого:

DECLARE @text nvarchar(max);
DECLARE @end_char int;
SELECT @text  = 'This student has not submitted his last few assignments', @end_char = 50 ;

WHILE @end_char > 0 AND SUBSTRING( @text, @end_char+1, 1 ) <> ' '
    SET @end_char = @end_char - 1

SELECT @text = SUBSTRING( @text, 1, @end_char ) ;

SELECT @text
person galets    schedule 06.04.2009