Функции STR, SPACE, LTRIM и RTRIM

Функция STR() преобразует число к его символьному представлению:

STR(<число с плавающей точкой> [, <длина> [, <число десятичных знаков> ] ] )

При этом преобразовании выполняется округление, а длина задает длину результирующей строки. Например,

STR(3.3456, 5, 1)3.3
STR(3.3456, 5, 2)3.35
STR(3.3456, 5, 3)3.346
STR(3.3456, 5, 4)3.346
STR(12345,4,0)****

Обратите внимание, что если полученное строковое представление числа меньше заданной длины, то добавляются лидирующие пробелы. Если же результат больше заданной длины, то усекается дробная часть (с округлением); в случае же целого числа получаем соответствующее число звездочек «*»:

Кстати, по умолчанию используется длина в 10 символов.

Имея в виду, что год представлен четырьмя цифрами, напишем:

SELECT name, STUFF(name, 6, LEN(name), '_'+STR(launched, 4))
FROM Ships;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]

Уже почти все правильно (мы продолжаем решать задачу, начатую здесь). Осталось учесть случай, когда число символов в имени менее 6, так как в этом случае функция STUFF дает NULL. Ну что ж, вытерпим до конца мучения, связанные с использованием этой функции в данном примере, попутно применив еще одну строковую функцию.

Добавим конечные пробелы, чтобы длина имени была заведомо больше 6. Для этого имеется специальная функция SPACE(<число пробелов>):

SELECT name, STUFF(name + SPACE(6), 6, LEN(name), '_'+STR(launched,4))
FROM Ships;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]

Функции LTRIM(<строковое выражение>) и RTRIM(<строковое выражение>) Отсекают, соответственно, лидирующие и конечные пробелы строкового выражения, которое неявно приводится к типу varchar.

Пусть требуется построить такую строку:

<имя пассажира>_<идентификатор пассажира>

на базе таблицы Passenger. Если мы напишем:

SELECT name + '_' + CAST(id_psg AS VARCHAR)
FROM Passenger;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]

то в результате получим что-то типа:

A _1

Это связано с тем, что столбец name имеет тип CHAR(30). Для этого типа короткая строка дополняется пробелами до заданного размера (у нас это 30 символов). Здесь нам как раз и поможет функция RTRIM:

SELECT RTRIM(name) + '_' + CAST(id_psg AS VARCHAR)
FROM Passenger;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]

Для усечения концевых пробелов в SQL Server изначально имелось две функции - LTRIM и RTRIM - для усечения пробелов слева и справа соответственно. Чтобы удалить пробелы с обеих сторон строки, последовательно применялись обе функции (в примере для наглядности используется функция DATALENGTH, возвращающая число символов с учетом пробелов):

declare @s varchar(10) =' x ' -- слева 2 пробела, справа - 1
select datalength(@s) s, datalength(ltrim(@s)) ls,
       datalength(rtrim(@s)) rs, datalength(ltrim(rtrim(@s))) bs;
slsrsbs
4231

Начиная с версии SQL Server 2017, к ним добавилась новая функция - TRIM, которая выполняет усечение с обеих сторон строки-аргумента:

select datalength(@s) s, datalength(trim(@s)) ts;
sts
41

Кроме того, функция TRIM приобрела дополнительный функционал - возможность усекать произвольные концевые символы.

При этом усекаемые символы можно задавать списком, перечисляя их в произвольном порядке. Усекаться (с обеих сторон) будут все входящие в список символы, пока не появится “посторонний”, т.е. не входящий в список. Лучше всего продемонстрировать сказанное на примере.

declare @s1 varchar(10)='xxaxbxy'
select trim('yx' from @s1) ts1, trim('x' from @s1) ts2;
ts1ts2
axbaxbxy

Конечно, это еще не стандартное поведение, но уже близко. А вот что говорит стандарт относительно функции TRIM:

< trim function> ::= TRIM < left paren> < trim operands> < right paren>

< trim operands> ::= [ [ < trim specification> ] [ < trim character> ] FROM ] < trim source>

< trim source> ::= < character value expression>

< trim specification> ::= LEADING | TRAILING | BOTH

< trim character> ::= < character value expression>

MySQL

В MySQL используется стандартный синтаксис функции TRIM. При этом, в отличие от SQL Server, удаляется указанная подстрока, а не все символы из списка:

SELECT TRIM(LEADING 'xy' FROM 'xyxybarxyx') ls,
       TRIM(TRAILING 'xy' FROM 'xyxybarxyx') rs,
       TRIM(BOTH 'yx' FROM 'xyxybarxyx') bs;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]
lsrsbs
barxyxxyxybarxyxxyxybarx

PostgreSQL

PostgreSQL сочетает поведение MySQL и SQL Server, т.е. удаляются все символы из списка:

SELECT TRIM(LEADING 'xy' FROM 'xyxybarxyx') ls,
       TRIM(TRAILING 'xy' FROM 'xyxybarxyx') rs,
       TRIM(BOTH 'yx' FROM 'xyxybarxyx') bs;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]
lsrsbs
barxyxxyxybarbar

Oracle

Oracle допускает усечение только одного символа, а не подстроки или символов из списка:

SELECT TRIM(LEADING 'x' FROM 'xxybarxyx') ls,
       TRIM(TRAILING 'x' FROM 'xxybarxyx') rs,
       TRIM(BOTH 'x' FROM 'xxybarxyx') bs
from dual;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]
lsrsbs
ybarxyxxxybarxyybarxy