Время прочтения: 6 мин.

Часто при работе с табличными данными из различных источников для их объединения требуется дополнительная подготовка ключевых столбцов. Например, если в одной таблице реквизиты договора или иного документа находятся в разных столбцах, а в другой – в одном. В подобной ситуации, как и во многих других (а может и во всех) есть два пути решения задачи приведения к одному виду: разделение одного столбца на два и слияние (конкатенация) двух столбцов в один. В настоящей публикации остановлюсь на подробном рассмотрении второго варианта. Работает функция конкатенации строк в разных СУБД (Microsoft SQL Server, Oracle) и других программных средствах (Excel, Python).

Каким бы банальным с точки зрения аналитики данных ИТ-специалистами не был вопрос конкатенации строк, в разных реализациях этой функции есть свои нюансы, знание которых поможет избежать возможных ошибок в работе, особенно тем, кто только начинает пользоваться современными средствами анализа, такими как T-SQL в различных СУБД и Python.

Всем, кто занимается анализом данных, известна функция «СЦЕПИТЬ()» в Excel, которая работает почти идеально, соединяя все входящие строки (строковые переменные) в одну. При этом, если одна из строк пустая, то она пропускается, лишние символы не добавляются (Рис. 1). Других вариантов соединения строк в Excel нет, разве что использование встроенного языка VBA, но в данном случае он не рассматривается.

Если же речь идёт о работе с данными в Microsoft SQL Server, то здесь можно использовать два варианта конкатенации. И именно разница между этими вариантами и является тем нюансом, который может привести к ошибкам и искажению данных. Первый вариант, это использование функции «concat», которая работает аналогично функции «СЦЕПИТЬ()» в Excel. Второй способ – это использование знака «+» для соединения столбцов. Применяя его, можно столкнуться с рядом проблем. Например, если в одном из столбцов будет значение NULL, то в результате соединения также будет пустое значение (Рис. 2). В случае пренебрежения данным фактом можно получить искажённые данные, особенно когда конкатенированный столбец является ключевым при объединении двух таблиц. Также обязательно следует помнить и о том, что при использовании знака «+» всегда нужно учитывать типы данных в столбцах, поскольку для разных типов данных этот знак работает по-разному: в случае с числовыми типами (integer, float и т.д.) произойдёт операция сложения чисел, в текстовых данных выполнится конкатенация, для типов date и datetime также выполнится сложение.

Рассмотрю вышесказанное на примере. Создам таблицу, содержащую id, серию и номер документа с типом данных nvarchar и заполню её некоторыми данными:

create table #table (
id nvarchar(100) null,
d_series nvarchar(100) null,
d_number nvarchar(100) null)

insert into #table values ('001', 'Lss110', '0274786'), ('002', null, '0456868'), ('003', 'Ldr127', null)

После этого напишу скрипт с использованием функции «concat()» и знака «+». Результат данного скрипта на рис. 2.

select 
       id,
       d_series,
       d_number,
       concat(d_series, d_number) CONCATENATED,
       d_series + d_number Concat_with_plus
from #table

Также для наглядности создам и заполню такую же таблицу, но типы данных будут установлены числовые (int). Результат показан на рис. 3.

create table #int_table (
id int null,
d_series int null,
d_number int null)

insert into #int_table values (1, 123, 456789), (2, null, 789123), (3, 789, null)

select 
       id,
       d_series,
       d_number,
       concat(d_series, d_number) CONCATENATED,
       d_series + d_number Concat_with_plus
from #int_table

Говоря о конкатенации в Microsoft SQL Server, следует упомянуть ещё об одной версии функции «concat()», позволяющей сократить запись и избежать возможных опечаток, когда необходимо вставить разделитель (пробел или другой символ) между соединяемыми столбцами. Для этого в более поздних версия Microsoft SQL Server существует функция «concat_ws()», которая первым аргументом принимает символ разделителя. Таким образом, запросы вида:

select concat(column_1, ' ', column_2, ' ', column_3) CONCATENATED from table

или

select column_1 + ' ' + column_2 +' ' + column_3 CONCATENATED from table

можно заменить более коротким:

select concat_ws(' ', column_1, column_2, column_3) CONCATENATED from table

Особенно актуален этот вариант тогда, когда запросы на сервер формируются динамически и очень критично не превысить максимальное количество символов в скрипте, отправляемом на сервер.

Похожим образом конкатенация строк в столбцах производится и в библиотеке pandas на языке Python. Разница заключается в том, что функция «pandas.concat()» присоединяет к одному датафрейму строки из другого датафрейма, а для соединения столбцов используется знак «+». На практике это выглядит так, как показано на рис. 4. Создам два датафрейма (df1 и df2) и конкатенирую их в третий датафрейм (df3). В результате датафрейм df3 будет содержать строки из df1 и df2.

Если же нужно получить, например, в df3 столбец, содержащий в себе данные из двух других столбцов разделённые символом «_», то код будет выглядеть так, как показано на рис. 5

Если в одном из конкатенируемых столбцов содержится пустое значение (nan или None), то в результирующий столбец будет записано значение nan, аналогично NULL в Microsoft SQL Server.

Ещё один инструмент, который имеет некоторые особенности и о котором следует упомянуть, – это СУБД Oracle. Здесь примечательно то, что функция «concat()» принимает в себя только два аргумента, если нужно объединить несколько столбцов, то необходимо использовать вложенную функцию, а это напрямую сказывается на производительности и скорости исполнения запросов. Поэтому предпочтительнее использовать символ «||», и тогда скрипт выглядит следующим образом:

select column_1 || ' ' || column_2 || ' ' || column_3 CONCATENATED from table

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