Разное

Ms sql конкатенация строк: + (объединение строк) (Transact-SQL) — SQL Server

Содержание

+ (объединение строк) (Transact-SQL) — SQL Server



  • Чтение занимает 4 мин

В этой статье

Применимо к:Applies to: SQL ServerSQL Server (все поддерживаемые версии) SQL ServerSQL Server (all supported versions) База данных SQL AzureAzure SQL DatabaseБаза данных SQL AzureAzure SQL Database Управляемый экземпляр SQL AzureAzure SQL Managed InstanceУправляемый экземпляр SQL AzureAzure SQL Managed Instance Azure Synapse AnalyticsAzure Synapse AnalyticsAzure Synapse AnalyticsAzure Synapse Analytics Параллельное хранилище данныхParallel Data WarehouseПараллельное хранилище данныхParallel Data WarehouseПрименимо к:Applies to: SQL ServerSQL Server (все поддерживаемые версии) SQL ServerSQL Server (all supported versions) База данных SQL AzureAzure SQL DatabaseБаза данных SQL AzureAzure SQL Database Управляемый экземпляр SQL AzureAzure SQL Managed InstanceУправляемый экземпляр SQL AzureAzure SQL Managed Instance Azure Synapse AnalyticsAzure Synapse AnalyticsAzure Synapse AnalyticsAzure Synapse Analytics Параллельное хранилище данныхParallel Data WarehouseПараллельное хранилище данныхParallel Data Warehouse

Оператор в строковом выражении, объединяющий две или более символьных или двоичных строки, два или более столбцов или несколько строк и имен столбцов в одно выражение (строковый оператор).An operator in a string expression that concatenates two or more character or binary strings, columns, or a combination of strings and column names into one expression (a string operator). Например, SELECT 'book'+'case'; возвращает bookcase.For example SELECT 'book'+'case'; returns bookcase.

Синтаксические обозначения в Transact-SQLTransact-SQL Syntax Conventions

СинтаксисSyntax

expression + expression  

АргументыArguments

expressionexpression
Любое действительное выражение любого типа данных в категории символьных и двоичных данных, за исключением типов данных image, ntext и text.Is any valid expression of any one of the data types in the character and binary data type category, except the image, ntext, or text data types. Оба выражения должны иметь одинаковый тип данных, или одно из выражений должно допускать неявное преобразование к типу данных другого выражения.Both expressions must be of the same data type, or one expression must be able to be implicitly converted to the data type of the other expression.

При сцеплении двоичных строк с любыми символами между двоичными строками необходимо использовать явное преобразование в символьные данные.An explicit conversion to character data must be used when concatenating binary strings and any characters between the binary strings. В следующем примере показано, когда CONVERT или CAST должны использоваться с двоичной конкатенацией и когда CONVERT или CAST не нужно использовать.The following example shows when CONVERT, or CAST, must be used with binary concatenation and when CONVERT, or CAST, does not have to be used.

DECLARE @mybin1 VARBINARY(5), @mybin2 VARBINARY(5)  
SET @mybin1 = 0xFF  
SET @mybin2 = 0xA5  
-- No CONVERT or CAST function is required because this example   
-- concatenates two binary strings.  
SELECT @mybin1 + @mybin2  
-- A CONVERT or CAST function is required because this example  
-- concatenates two binary strings plus a space.  
SELECT CONVERT(VARCHAR(5), @mybin1) + ' '   
   + CONVERT(VARCHAR(5), @mybin2)  
-- Here is the same conversion using CAST.  
SELECT CAST(@mybin1 AS VARCHAR(5)) + ' '   
   + CAST(@mybin2 AS VARCHAR(5))  

Типы результатаResult Types

Возвращает тип данных аргумента с самым высоким приоритетом.Returns the data type of the argument with the highest precedence. Дополнительные сведения см. в разделе Приоритет типов данных (Transact-SQL).For more information, see Data Type Precedence (Transact-SQL).

КомментарииRemarks

При работе с пустыми строками нулевой длины оператор + (объединение строк) ведет себя иначе, чем при работе со значениями NULL или с неизвестными значениями.The + (String Concatenation) operator behaves differently when it works with an empty, zero-length string than when it works with NULL, or unknown values. Символьная строка символа нулевой длины может быть указана в виде двух одинарных кавычек без каких-либо символов между ними.A zero-length character string can be specified as two single quotation marks without any characters inside the quotation marks. Двоичная строка нулевой длины может быть указана как 0x без указания каких-либо байтовых значений в шестнадцатеричной константе.A zero-length binary string can be specified as 0x without any byte values specified in the hexadecimal constant. При сцеплении строки нулевой длины всегда сцепляются две указанные строки.Concatenating a zero-length string always concatenates the two specified strings. При работе со строками со значением NULL результат объединения зависит от настроек сеанса.When you work with strings with a null value, the result of the concatenation depends on the session settings. При присоединении нулевого значения к известному значению результатом будет неизвестное значение, объединение строк с нулевым значением также дает нулевое значение, как и в арифметических действиях с нулевыми значениями.Just like arithmetic operations that are performed on null values, when a null value is added to a known value the result is typically an unknown value, a string concatenation operation that is performed with a null value should also produce a null result. Однако можно изменить данное поведение, поменяв значение CONCAT_NULL_YIELDS_NULL для текущего сеанса.However, you can change this behavior by changing the setting of CONCAT_NULL_YIELDS_NULL for the current session. Дополнительные сведения см. в разделе SET CONCAT_NULL_YIELDS_NULL (Transact-SQL).For more information, see SET CONCAT_NULL_YIELDS_NULL (Transact-SQL).

Если результат объединения строк превышает предел в 8 000 байт, то он усекается.If the result of the concatenation of strings exceeds the limit of 8,000 bytes, the result is truncated. Однако усечения не произойдет, если хотя бы одна из сцепляемых строк принадлежит к типу больших значений.However, if at least one of the strings concatenated is a large value type, truncation does not occur.

ПримерыExamples

A.A. Использование объединения строкUsing string concatenation

В следующем примере создается единственный столбец с заголовком Name из нескольких символьных столбцов, где за фамилией лица следуют запятая, один пробел и имя того же лица.The following example creates a single column under the column heading Name from multiple character columns, with the last name of the person followed by a comma, a single space, and then the first name of the person. Результирующий набор сортируется в алфавитном порядке по возрастанию, сначала по фамилии, а затем по имени.The result set is in ascending, alphabetical order by the last name, and then by the first name.

-- Uses AdventureWorks  
  
SELECT (LastName + ', ' + FirstName) AS Name  
FROM Person.Person  
ORDER BY LastName ASC, FirstName ASC;  

Б.B. Объединение числовых типов данных и датCombining numeric and date data types

В приведенном ниже примере функция CONVERT используется для объединения типов данных numeric и date.The following example uses the CONVERT function to concatenate numeric and date data types.

-- Uses AdventureWorks  
  
SELECT 'The order is due on ' + CONVERT(VARCHAR(12), DueDate, 101)  
FROM Sales.SalesOrderHeader  
WHERE SalesOrderID = 50001;  
GO  

Результирующий набор:Here is the result set.

------------------------------------------------  
The order is due on 04/23/2007  
(1 row(s) affected)

В.C. Использование объединения нескольких строкUsing multiple string concatenation

Следующий пример сцепляет несколько строк в одну длинную строку для отображения фамилии и первой буквы инициалов вице-президентов в Компания Adventure Works CyclesAdventure Works Cycles.The following example concatenates multiple strings to form one long string to display the last name and the first initial of the vice presidents at Компания Adventure Works CyclesAdventure Works Cycles. После фамилии ставится запятая, а после первой буквы инициалов — точка.A comma is added after the last name and a period after the first initial.

-- Uses AdventureWorks  
  
SELECT (LastName + ',' + SPACE(1) + SUBSTRING(FirstName, 1, 1) + '.') AS Name, e.JobTitle  
FROM Person.Person AS p  
    JOIN HumanResources.Employee AS e  
    ON p.BusinessEntityID = e.BusinessEntityID  
WHERE e.JobTitle LIKE 'Vice%'  
ORDER BY LastName ASC;  
GO  

Результирующий набор:Here is the result set.

Name               Title  
-------------      ---------------`  
Duffy, T.          Vice President of Engineering  
Hamilton, J.       Vice President of Production  
Welcker, B.        Vice President of Sales  

(3 row(s) affected)

Г.D. Использование больших строк при объединенииUsing large strings in concatenation

В приведенном ниже примере выполняется объединение нескольких строк в одну длинную строку, а затем предпринимается попытка вычислить длину итоговой строки.The following example concatenates multiple strings to form one long string and then tries to compute the length of the final string. Итоговая длина результирующего набора равна 16 000, так как вычисление выражения начинается слева, то есть @x + @z + @y => (@x + @z) + @y.The final length of resultset is 16000, because expression evaluation starts from left that is, @x + @z + @y => (@x + @z) + @y. В этом случае результат (@x + @z) усекается до 8000 байт, а затем в результирующий набор добавляется значение @y, из-за чего длина итоговой строки становится равна 16 000.In this case the result of (@x + @z) is truncated at 8000 bytes and then @y is added to the resultset, which makes the final string length 16000. Так как @y — это строка типа с большим значением, усечения не происходит.Since @y is a large value type string, truncation does not occur.

DECLARE @x VARCHAR(8000) = REPLICATE('x', 8000)
DECLARE @y VARCHAR(max) = REPLICATE('y', 8000)
DECLARE @z VARCHAR(8000) = REPLICATE('z',8000)
SET @y = @x + @z + @y
-- The result of following select is 16000
SELECT LEN(@y) AS y
GO

Результирующий набор:Here is the result set.

y        
-------  
16000  
 
(1 row(s) affected)

Примеры: Azure Synapse AnalyticsAzure Synapse Analytics и Параллельное хранилище данныхParallel Data WarehouseExamples: Azure Synapse AnalyticsAzure Synapse Analytics and Параллельное хранилище данныхParallel Data Warehouse

Д.E. Использование объединения нескольких строкUsing multiple string concatenation

В приведенном ниже примере несколько строк сцепляются в одну длинную строку для отображения фамилий и инициалов имен вице-президентов из образца базы данных.The following example concatenates multiple strings to form one long string to display the last name and the first initial of the vice presidents within a sample database. После фамилии ставится запятая, а после первой буквы инициалов — точка.A comma is added after the last name and a period after the first initial.

-- Uses AdventureWorks  
  
SELECT (LastName + ', ' + SUBSTRING(FirstName, 1, 1) + '.') AS Name, Title  
FROM DimEmployee  
WHERE Title LIKE '%Vice Pres%'  
ORDER BY LastName ASC;  

Результирующий набор:Here is the result set.

Name               Title                                           
-------------      ---------------  
Duffy, T.          Vice President of Engineering  
Hamilton, J.       Vice President of Production  
Welcker, B.        Vice President of Sales  

См. такжеSee Also

+= (присваивание объединения строк) (Transact-SQL) += (String Concatenation Assignment) (Transact-SQL)
ALTER DATABASE (Transact-SQL) ALTER DATABASE (Transact-SQL)
Функции CAST и CONVERT (Transact-SQL) CAST and CONVERT (Transact-SQL)
Преобразование типов данных (ядро СУБД) Data Type Conversion (Database Engine)
Типы данных (Transact-SQL) Data Types (Transact-SQL)
Выражения (Transact-SQL) Expressions (Transact-SQL)
Встроенные функции (Transact-SQL) Built-in Functions (Transact-SQL)
Операторы (Transact-SQL) Operators (Transact-SQL)
SELECT (Transact-SQL) SELECT (Transact-SQL)
Инструкции SET (Transact-SQL)SET Statements (Transact-SQL)



Что такое и как делается конкатенация строк в языке T-SQL?

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

Конкатенацией строк называют их объединение посредством различных операторов. На сайте https://self-learning.ru/string-concatenation-in-t-sql Вы сможете найти подробную инструкцию, касающуюся конкатенации строк в T-SQL. Ниже обозначим самые доступные способы решения.

Актуальные подходы к объединению строк

Сегодня специалисты используют следующие методы:

  • оператор +;
  • функция Concat;
  • функция CONCAT_WS;
  • функция STAFF.

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

Ввиду этого, специалист должен соотносить синтаксис языка с конкретной версией MS SQL Server. К примеру, оператор «+» — это нативный метод для конкатенации. Он доступен в любой версии ПО.

Минус его заключается в том, что пользоваться им не всегда удобно. Кроме того, специалист всегда должен стремиться к оптимизации кода.

Функция CONCAT – метод конкатенации, доступный с 2012 года

В версии MS SQL Server с 2012 года доступна функция CONCAT. Она позволяет объединить все требуемые параметры и описать их в качестве аргументов. Допустимо минимально 2 параметра.

Функция работает по аналогии с оператором «+».

Однако, вышеупомянутая функция не всегда применима на практике. Ведь объединять приходится строки. Часто случается так, что информация требует разделения. В такой ситуации рекомендуется использовать функцию Concat_WS.

Она позволяет дополнительно использовать разделитель (символ).

Типичным разделителем остаётся «,». Пример синтаксиса данной функции выглядит следующим образом: SELECT CONCAT_WS(‘ ‘, ‘мастер’,’закупщик’) AS Result. Отметим, что Microsoft предлагается технология SQL CLR. С её помощью можно дополнять функционал в MS SQL Server 2005 (актуально и для более поздних версий).

В видео наглядно демонстрируется спектр примеров использования конкретных способов конкатенации строк в T-SQL:

Твитнуть

Добавить комментарий

Соединение строк SQL | CODE BLOG | Программирование

В процессе работы я столкнулся с необходимостью объединения строк в базе данных. Казалось бы, это достаточно тривиальная задача, но не все так просто, как кажется на первый взгляд. Давайте подробнее рассмотрим различные методы конкатенации строк в SQL и те проблемы, с которыми я столкнулся.

Оператор +

Наиболее простым методом объединения строк является использование обычного оператора +. При этом к первому аргументу будет добавлен второй. Например если мы возьмем слово «Чудо» и слово «Женщина» в результате получим строку «ЧудоЖенщина».

SELECT ‘чудо’ + ‘женщина’ AS Result

Пока все просто, но это не то, что было мне нужно. Потому что, мне было нужно объединять большое количество значений, а делать это через знак + было не удобно. Давайте рассмотрим и другие способы конкатенации.

Функция CONCAT

Данная функция позволяет объединить все параметры, передаваемые в нее в качестве аргументов. Минимальное количество параметров два. Добавлю очень важное замечание, данная функция появилась в SQL Server начиная с 2012 версии. Это, кстати, принципиально. Потому что зачастую используются старые версии сервера, и вы не сможете использовать новые возможности языка. Всегда проверяйте, поддерживает ли ваша версия SQL сервера используемые возможности. Особенно при переносе с одного сервера на другой.

Работает данная функция аналогично оператору +. Например:

SELECT CONCAT(‘чудо’,’женщина’) AS Result

Но этот вариант меня тоже не устраивал, потому что мне нужно было объединить результаты через запятую.

Функция CONCAT_WS

Данная функция позволяет конкатенировать строки через разделитель. Но ее основной проблемой, как и многих других, которые мы рассмотрим в дальнейшем, что она была добавлена только в версии SQL Server 2017, который пока практически нигде не используется. Первым параметром указывается разделитель, затем перечисляются параметры.

SELECT CONCAT_WS(‘ ‘, ‘чудо’,’женщина’) AS Result

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

Функция STAFF

Переходим к более сложным примерам, и для начала рассмотрим предметную область. У нас есть три таблицы, это Человек, Проект и Назначение. Все достаточно просто, обычная реализация связи многие к многим человека и проекта.

Если очень упростить, то задача состояла в том, чтобы вывести через запятую все проекты назначенные на человека. Сначала я попытался воспользоваться функцией STAFF. Рассмотрим элементарный, но бесполезный пример

SELECT
STUFF(
(SELECT ‘;’ + proj.Name
FROM Project AS proj
FOR XML PATH (»))
, 1, 1, ») AS Projects
FROM Assignment AS assign

Здесь, в подзапросе мы получаем все элементы таблицы Project, и соединяем их через точку с запятой, начиная именно с точки запятой, а затем просто удаляем первый символ (как раз не нужную точку с запятой). И выводим для каждого назначения.

Но когда я захотел сгруппировать результаты по идентификатору пользователя с помощью GROUP BY я узнал, что сделать этого не смогу, так как STAFF не является агрегирующей функцией. Поэтому пошел дальше изучать просторы интернета.

Функция STRING_AGG

Отличная функция которая полностью решила все мои проблемы. За исключением одного, она появилась в SQL Server 2017, поэтому оказалась хоть и очень хорошей, но бесполезной

SELECT assign.PersonId,
STRING_AGG (proj.Name, ‘,’) AS Projects
FROM Assignment AS assign
LEFT JOIN Project AS proj ON assign.ProjectId = proj.Id
GROUP BY assign.PersonId

Функция GROUP_CONCAT

Ну и наконец самое сладкое. Не найдя ни одной подходящей конкатенирующей агрегирующей функции, я нашел возможность с помощью кастомной агрерирующей функции. Есть проект на github orlando-colamatteo/ms-sql-server-group-concat-sqlclr, который предоставляет готовый скрипт, который добавляет новую конкатенирующую функцию GROUP_CONCAT. Посмотрим пример.

SELECT assign.PersonId,
dbo.GROUP_CONCAT(proj.Name) AS Projects
FROM Assignment AS assign
LEFT JOIN Project AS proj ON assign.ProjectId = proj.Id
GROUP BY assign.PersonId

Именно благодаря этой функции я решил все свои проблемы и выполнил поставленную задачу. Моя огромная благодарность ее создателю. Ну а теперь давайте рассмотрим процесс установки и что это вообще такое.

Установка GROUP_CONCAT в MS SQL Server

Для начала заходим на github и скачиваем проект. Распаковываем его в любую директорию. Заходим в папку D:\ms-sql-server-group-concat-sqlclr-master\GroupConcat\Installation Scripts и открываем файл GroupConcatInstallation.sql. Он уже практически готов к использованию. Единственно что нужно сделать, это изменить имя базы данных на используемое у вас.

— !! MODIFY TO SUIT YOUR TEST ENVIRONMENT !!
USE GroupConcatTest /*МЕНЯТЬ ЗДЕСЬ!*/

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

Что такое SQL CLR?

SQL CLR это технология компании Microsoft, которая позволяет добавлять новый функционал в MS SQL Server 2005 и более поздних версий при помощи внедрения сборок написанных с помощью языков входящих в .NET, такие как VB.NET или C#.

С ее помощью предоставляется возможность создания пользовательских функций, типов данных, аргегатных функций, триггеров, хранимых процедур, написанных на высокопроизводительных языках. Благодаря этому можно значительно увеличить производительность, а также расширять функционал стандартного SQL. Пример можно изучить в статье на Habr.

Заключение

На этом у меня все. Надеюсь данный материал будет полезен. Но больше всего меня поражает то, что компания Microsoft ввела агрегирующую функцию конкатенации строк только в 2017 году…

Источник: CODE BLOG

String aggregation in the SQL Server world / Хабр

На практике, задачи по объединению строк в одну попадаются достаточно часто. Весьма печально, но стандарт T-SQL не предусматривает возможности использовании строковых данных внутри агрегирующей функции SUM:

Msg 8117, Level 16, State 1, Line 1

Operand data type char is invalid for sum operator.

Хотя для решения подобного рода задач, для MySQL была добавлена функция GROUP_CONCAT, а в Oracle LISTAGG. В свою же очередь, SQL Server такого встроенного функционала пока не имеет.

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


Предположим, что нам необходимо объединить через запятую несколько строк в одну, используя для этого данные из следующей таблицы:

IF OBJECT_ID('dbo.Chars', 'U') IS NOT NULL
    DROP TABLE dbo.Chars
GO

CREATE TABLE dbo.Chars ([Char] CHAR(1) PRIMARY KEY)
INSERT INTO dbo.Chars ([Char])
VALUES ('A'), ('B'), ('C'), ('F'), ('D')

Наиболее очевидным решением данной задачи является применение курсора:

DECLARE 
      @Chars VARCHAR(100)
    , @Char CHAR(1)

DECLARE cur CURSOR LOCAL READ_ONLY FAST_FORWARD FOR
    SELECT [Char]
    FROM dbo.Chars

OPEN cur
FETCH NEXT FROM cur INTO @Char

WHILE @@FETCH_STATUS = 0 BEGIN
    SET @Chars = ISNULL(@Chars + ', ' + @Char, @Char) 
    FETCH NEXT FROM cur INTO @Char
END

CLOSE cur
DEALLOCATE cur

SELECT @Chars

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

Чтобы избавится от него, можно конкатенировать строки через присваивание переменных:

DECLARE @Chars VARCHAR(100)
SELECT @Chars = ISNULL(@Chars + ', ' + [Char], [Char])   
FROM dbo.Chars

SELECT @Chars

С одной стороны, конструкция получилась очень простой, с другой стороны, ее производительность на большой выборке оставляет желать лучшего.

Для агрегации строк также возможно сделать через XML, применяя следующую конструкцию:

SELECT Chars = STUFF((
	SELECT ', ' + [Char]
	FROM dbo.Chars
	FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 2, '')

Если посмотреть на план, то можно заметить высокую стоимость вызова метода value:

Чтобы избавится от этой операции, можно переписать запрос применяя свойства XQuery:

SELECT Chars = STUFF(CAST((
	SELECT [text()] = ', ' + [Char]
	FROM dbo.Chars
	FOR XML PATH(''), TYPE) AS VARCHAR(100)), 1, 2, '')

В результате – получим очень простой и быстрый план выполнения:

В принципе, конкатенация строк по одному столбцу не вызывает особых сложностей.

Более интересна ситуация, когда требуется выполнить конкатенацию сразу по нескольким столбцам. Например, в наличии у нас следующая таблица:

IF OBJECT_ID('dbo.EntityValues', 'U') IS NOT NULL
    DROP TABLE dbo.EntityValues
GO

CREATE TABLE dbo.EntityValues (
      EntityID INT
    , Value1 CHAR(1)
    , Value2 CHAR(1) 
)

CREATE NONCLUSTERED INDEX IX_WorkOut_EntityID 
	ON dbo.EntityValues (EntityID)
GO

INSERT INTO dbo.EntityValues (EntityID, Value1, Value2)
VALUES (1, 'A', 'X'), (2, 'B', 'Y'), (2, 'C', 'Z'), (2, 'F', 'H'), (1, 'D', 'R')

в которой необходимо сгруппировать данные следующим образом:

Как вариант, можно скопировать вызовы XML, но тогда мы получим дублирующие чтения, которые могут существенно повлиять на эффективность выполнения запроса:

SELECT 
      ev.EntityID
    , Values1 = STUFF(CAST((
        SELECT [text()] = ', ' + ev2.Value1
        FROM dbo.EntityValues ev2
        WHERE ev2.EntityID = ev.EntityID
        FOR XML PATH(''), TYPE) AS VARCHAR(100)), 1, 2, '')
    , Values2 = STUFF(CAST((
        SELECT [text()] = ', ' + ev2.Value2
        FROM dbo.EntityValues ev2
        WHERE ev2.EntityID = ev.EntityID
        FOR XML PATH(''), TYPE) AS VARCHAR(100)), 1, 2, '')             
FROM ( 
    SELECT DISTINCT EntityID
    FROM dbo.EntityValues
) ev

В этом можно легко убедится, если взглянуть на план выполнения:

Чтобы сократить повторные чтения можно воспользоваться небольшим XML хаком:

SELECT
      ev.EntityID
    , Values1 = STUFF(REPLACE(
            CAST([XML].query('for $a in /a return xs:string($a)') AS VARCHAR(100)), ' ,', ','), 1, 1, '') 
    , Values2 = STUFF(REPLACE(
            CAST([XML].query('for $b in /b return xs:string($b)') AS VARCHAR(100)), ' ,', ','), 1, 1, '') 
FROM (
    SELECT DISTINCT EntityID
    FROM dbo.EntityValues
) ev
CROSS APPLY (
    SELECT [XML] = CAST((
        SELECT 
              [a] = ', ' + ev2.Value1
            , [b] = ', ' + ev2.Value2
        FROM dbo.EntityValues ev2
        WHERE ev2.EntityID = ev.EntityID
        FOR XML PATH('')
    ) AS XML)
) t

Но данный запрос также будет не оптимальным вследствие многократного вызова метода query.

Можно воспользоваться курсором:

IF OBJECT_ID('tempdb.dbo.#EntityValues') IS NOT NULL
	DROP TABLE #EntityValues
GO

SELECT DISTINCT
	  EntityID
	, Values1 = CAST(NULL AS VARCHAR(100))
	, Values2 = CAST(NULL AS VARCHAR(100))
INTO #EntityValues
FROM dbo.EntityValues

DECLARE
	  @EntityID INT
	, @Value1 CHAR(1)
	, @Value2 CHAR(1)

DECLARE cur CURSOR LOCAL READ_ONLY FAST_FORWARD FOR
    SELECT
	      EntityID
	    , Value1
	    , Value2
    FROM dbo.EntityValues

OPEN cur
FETCH NEXT FROM cur INTO
	  @EntityID
	, @Value1
	, @Value2

WHILE @@FETCH_STATUS = 0 BEGIN

    UPDATE #EntityValues
    SET 
          Values1 = ISNULL(Values1 + ', ' + @Value1, @Value1) 
        , Values2 = ISNULL(Values2 + ', ' + @Value2, @Value2)
    WHERE EntityID = @EntityID

	FETCH NEXT FROM cur INTO
          @EntityID
        , @Value1
        , @Value2

END

CLOSE cur
DEALLOCATE cur

SELECT *
FROM #EntityValues

Однако, как показала практика, при работе с большими ETL пакетами, наиболее производительным решением является возможность присваивания переменных в конструкции UPDATE:

IF OBJECT_ID('tempdb.dbo.#EntityValues') IS NOT NULL
	DROP TABLE #EntityValues
GO

DECLARE 
      @Values1 VARCHAR(100)
    , @Values2 VARCHAR(100)

SELECT 
      EntityID
    , Value1
    , Value2
    , RowNum = ROW_NUMBER() OVER (PARTITION BY EntityID ORDER BY 1/0)
    , Values1 = CAST(NULL AS VARCHAR(100))
    , Values2 = CAST(NULL AS VARCHAR(100))
INTO #EntityValues
FROM dbo.EntityValues

UPDATE #EntityValues
SET 
      @Values1 = Values1 =
        CASE WHEN RowNum = 1 
            THEN Value1
            ELSE @Values1 + ', ' + Value1 
        END
    , @Values2 = Values2 = 
        CASE WHEN RowNum = 1 
            THEN Value2
            ELSE @Values2 + ', ' + Value2 
        END

SELECT
      EntityID
    , Values1 = MAX(Values1) 
    , Values2 = MAX(Values2)
FROM #EntityValues
GROUP BY EntityID

SQL Server не имеет встроенного аналога функций GROUP_CONCAT и LISTAGG. Тем не менее, это не мешает, в зависимости от ситуации, эффективно выполнять задачи по конкатенации строк. Цель данного поста – наглядно это показать.

sql — Конкатенация строк SQL

Я работаю в sql server 2008, я хочу объединить две строки, и условие

@str1 = 'A1,B1,C1'
@str2 = 'A2,B2,C2'

Я хочу результат как

@result = 'A1,A2,B1,B2,C1,C2'

Пожалуйста помоги…

0

user2695128

9 Фев 2016 в 15:16

4 ответа

Лучший ответ

То, как вы храните свои данные, — действительно плохая практика. Однако вот решение для учебных целей:

DECLARE 
   @str1 varchar(30) = 'A1,B1,C1',
   @str2 varchar(30) = 'A2,B2,C2',
   @result varchar(60)

;WITH split as
(
  SELECT t.c.value('.', 'VARCHAR(2000)') x
  FROM (
      SELECT x = CAST('<t>' + 
          REPLACE(@str1 + ',' + @str2, ',', '</t><t>') + '</t>' AS XML)
  ) a
CROSS APPLY x.nodes('/t') t(c)
)
SELECT
  @result =
    STUFF(( 
        SELECT ',' + x
        FROM split
        ORDER BY x
        for xml path(''), type 
          ).value('.', 'varchar(max)'), 1, 1, '')

SELECT @result

Результат:

A1,A2,B1,B2,C1,C2

1

t-clausen.dk
9 Фев 2016 в 12:56

SET @result = @str1 + ',' + @str2
SELECT @result

ОБНОВЛЕНИЕ 1

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

CREATE FUNCTION SplitString
(    
      @Input NVARCHAR(MAX),
      @Character CHAR(1)
)
RETURNS @Output TABLE (
      Item NVARCHAR(1000)
)
AS
BEGIN
      DECLARE @StartIndex INT, @EndIndex INT

      SET @StartIndex = 1
      IF SUBSTRING(@Input, LEN(@Input) - 1, LEN(@Input)) <> @Character
      BEGIN
            SET @Input = @Input + @Character
      END

      WHILE CHARINDEX(@Character, @Input) > 0
      BEGIN
            SET @EndIndex = CHARINDEX(@Character, @Input)

            INSERT INTO @Output(Item)
            SELECT SUBSTRING(@Input, @StartIndex, @EndIndex - 1)

            SET @Input = SUBSTRING(@Input, @EndIndex + 1, LEN(@Input))
      END

      RETURN
END
GO


SELECT Item FROM 
dbo.SplitString(@result,',') ORDER BY Item

0

Hemal
9 Фев 2016 в 12:30

Сначала создайте функцию разделения, чтобы получать элементы отдельно:

CREATE FUNCTION [dbo].[Split]
(
    @String NVARCHAR(4000),
    @Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
    WITH Split(stpos,endpos)
    AS(
        SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos
        UNION ALL
        SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1)
            FROM Split
            WHERE endpos > 0
    )
    SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
        'Data' = SUBSTRING(@String,stpos,COALESCE(NULLIF(endpos,0),LEN(@String)+1)-stpos)
    FROM Split
)
GO

Теперь вы можете сначала разделить и упорядочить результат, а затем объединить значения

DECLARE @DelimitedString NVARCHAR(128)
SET @DelimitedString =  @str1 + ',' + @str2
SELECT @result = COALESCE(@result + ',', '') +Data
  FROM (SELECT Data 
          FROM dbo.Split(@DelimitedString, ',')
      ORDER BY Data)

1

Peter
9 Фев 2016 в 12:30

Пытаться:

SELECT stuff((SELECT ',' + T.str FROM
(SELECT 
    PARSENAME(REPLACE(@str1,',','.'),1) str UNION ALL
    PARSENAME(REPLACE(@str1,',','.'),2) str UNION ALL
    PARSENAME(REPLACE(@str1,',','.'),3) str UNION ALL
    PARSENAME(REPLACE(@str2,',','.'),1) str UNION ALL
    PARSENAME(REPLACE(@str2,',','.'),2) str UNION ALL
    PARSENAME(REPLACE(@str2,',','.'),3) str )T
    ORDER BY T.str
FOR XML PATH('')),1,1,'')

0

Haytem BrB
9 Фев 2016 в 14:35

35291850

Sql-Server-Group-Concat – вопросы и ответы по программированию

Предположим, что у меня есть эта таблица [Таблица1] Name Mark ——- —— ABC 10 DEF 10 GHI 10 JKL 20 MNO 20 PQR 30 Что должно быть моим оператором SQL для получения записи, которая выглядит так…

1 месяц, 1 неделя назад

yonan2236

Я хочу создать функцию табличной оценки в SQL Server, которую я хочу вернуть данные в значениях, разделенных запятой. Например, таблица: tbl ID | Value —+——- 1 | 100 1 | 200 1 | 300 1 | 400 Т…

Этот вопрос задавался много раз в SO, но ни один из ответов не удовлетворяет моей ситуации. Вопрос 1 вопрос 2

Я использую активную запись codeigniter, но я понял, что мне, вероятно, нужен обычный SQL-запрос для того, что я пытаюсь выполнить. Может кто-то, пожалуйста, посмотрите на этот код и дайте мне прав…

На этот вопрос уже есть ответ: Несколько строк для одного значения, разделенного запятыми [duplicate] 1 Ответ Я хочу создать табличную функцию в SQL Server, которую я хочу вернуть данные в значения…

2 месяца, 1 неделя назад

Stfvns

У меня есть таблица, содержащая ~ миллион записей, таких как: customer_id | purchased_at | product 1 | 2012-06-01 00:00 | apples 1 | 2012-09-02 00:00 | apples 1 | 2012-10-01 00:00 | pears 2 | 2012-…

11 месяцев, 2 недели назад

AGS

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX) DECLARE @ColumnName AS NVARCHAR(MAX) —Get distinct values of the PIVOT Column SELECT @ColumnName= ISNULL(@ColumnName + ‘,’,») + QUOTENAME(ACT_DESC) FRO…

11 месяцев, 3 недели назад

newb

У меня есть три таблицы следующим образом: MasterTable +———-+————-+ | MasterId | MasterName | +———-+————-+ | 1 | Master 1 | | 2 | Master 2 | | 3 | Master 3 | | 4 | Maste…

У меня есть следующий запрос, который возвращает зарплату всех сотрудников. Это работает отлично, но мне нужно собрать дополнительные данные, которые я буду агрегировать в одну ячейку (см. Result S…

11 месяцев, 3 недели назад

Martin

Я лучше объясню с помощью таблиц: размер стола —————————— id | type | size | cont_id | —————————— 1 | GP | 30 | 21 | 2 | FR | 30 | 21 | 3 | UP | 40 | 21 | 4 | …

1 год назад

Munna

Я добрался до столов. TABLE 1: [..fields..] [CATEGORIE] [..fields..] TABLE 2: [..fields..] [ID] [CATEGORIE] [..fields..] Я хочу подключиться немного специальным и пробовал его следующим образом: SE…

1 год назад

Harry

Я хочу «объединить» все «тексты» в одну строку и получить одну строку в результате. Возможно ли это? Я использую MSSQL Server 2005.

1 год назад

Fu86

Я использую Microsoft SQL Server 2005. Мне кажется, мне нужен суб-запрос. Я ищу одну (1) строку для каждого клиента, а поле AvailableAction — это объединение всех действий для каждого клиента. use …

В настоящее время я пытаюсь имитировать функцию group_concat в MySQL в MSSQL. Я придерживался кодеков, найденных в здесь и

7 лет, 2 месяца назад

JamesP

Я пытаюсь перенести приложение на основе MySQL на Microsoft SQL Server 2005 (не по своему выбору, а на то, что жизнь). В исходном приложении мы использовали почти полностью совместимые с ANSI-SQL о…

12 лет, 1 месяц назад

DanM

Мне нужно написать sql-запрос в таблице, чтобы результат имел группу по столбцу вместе с агрегированным столбцом с разделителями-запятыми. Моя таблица будет в формате ниже |««««`|««««| | ID…

9 лет, 9 месяцев назад

suryakiran

У меня есть 2 таблицы на SQL Server, в которых есть несколько мест для имени, и все, что мне нужно сделать, это расположение клубов в одну ячейку для этих имен. Table 1 Name H I J Table 2 Name Loca…

7 лет, 10 месяцев назад

IAmHomes

У меня есть таблица под названием «colamer», как показано ниже: ID Title SectionID 1 abc 231 2 abc 232 3 pqr 95 4 jkl 165 Моя сохраненная процедура: CREATE PROCEDURE CheckDuplicateBannerforSection …

У меня есть запрос, который я обычно group_concat . Мне нужно знать, имеет ли dbo.group_concat возможность dbo.group_concat результат запроса с парами 3 (в качестве примера). Например: select size,…

Как мне получить: id Name Value 1 A 4 1 B 8 2 C 9 к id Column 1 A:4, B:8 2 C:9

12 лет, 4 месяца назад

Eldila

Я просмотрел ряд решений для эмуляции функциональности Group concat в SQL Server. Я хотел сделать более понятное для человека решение, хотя и не могу понять, как это сделать. У меня есть представле…

8 лет, 3 месяца назад

Molloch

У меня есть запрос формы SELECT pub.id, topic.id, pub.title, etc… FROM pub, topic, link WHERE (matching logic) который возвращается в виде pub.id | topic.id | pub.title —————————…

mysql> select * from CT; | CID | MID | REPORT_QUERY | | 1 | 1 | select * from emp; | | 2 | 2 | select * from student; | 2 rows in set (0.00 sec) Я хочу выполнить запросы в столбце REPORT_QUERY ….

3 года, 10 месяцев назад

Jani Harsh

Я работаю над SQL Server 2008 R2 . У меня ниже двух таблиц: CREATE TABLE TRK_REQUEST( REQUEST_ID int, APPROVER_ID int CONSTRAINT app_ID_fk FOREIGN KEY REFERENCES TRK_APPROVER(APPROVER_ID), APPROVER…

5 лет, 12 месяцев назад

Touhid K.

У меня есть следующий запрос: $query = <<<SQL SELECT year, count(*) AS ‘counter’, GROUP_CONCAT(team) AS ‘team_list’ FROM team_list WHERE year IS NOT NULL SQL; if (!empty($sql)) { //$sql is…

1 год, 10 месяцев назад

JoeBe

Я соединяю несколько таблиц, в которых я хочу, чтобы одно значение столбца в строке соответствовало TechnicianName : У меня есть 4 таблицы easy_tbljobcard , easy_tbltechnician и easy_tblproblem и e…

Я пытаюсь использовать функциональность STUFF в SQL Server 2016, чтобы выбрать информацию DATE и вернуть ее в таблицу. Иногда есть несколько дат, чтобы вернуться. Я уже использовал STUFF, чтобы пол…

Я пытался понять это сейчас, и я продолжаю тупик. Может быть, кто-то здесь может мне помочь. Я работаю в компании, и мы собираемся получить файл для единиц, которые мы будем ремонтировать. В некото…

select t.Sno, t.childid, (select customername as n from customerprofile c where c.cusid = t.childid) as name,t.earnedmoney as commission, (select p.bookingamt from propertyregistration p, customerp…

Привет, я пытаюсь выполнить запрос ниже. Где выход ProjectID равен 1,2,3. Я пытаюсь извлечь данные с помощью ProjectID из другой таблицы. DECLARE @ProjectID varchar(100) DECLARE @ImpactIntakeID var…

7 лет, 2 месяца назад

sk7730

У меня есть таблица, подобная этой Hospital Insurance PatientCount h2 I1 1 h2 I1 2 h3 I1 1 h3 I2 1 Хотите группировать эту таблицу по страхованию, Hospital Insurance PatientCount h2,h3 I1 4 h3 I2 1…

У меня есть 2 таблицы: SELECT UnitId FROM dbo.tblUnits SELECT UnitId, WorkOrderNumber FROM dbo.tblWorkOrders Мне нужно отобразить все UnitId из dbo.tblUnits, затем в 1 столбце diplay все WorkOrders…

9 лет, 11 месяцев назад

user380432

Ошибка: столбец «ReviewConsultants.ConsultantID» недопустим в списке выбора, потому что он не содержится ни в агрегатной функции, ни в предложении GROUP BY. Запрос: select R.ReviewID, STUFF((select…

3 года, 3 месяца назад

sai

В таблице MSSQL («имя пользователя») у меня есть две следующие записи: name ¦ nickname John Johny Marc Marco Я хотел бы сделать запрос, который вернет «Johny, Marco», когда я буду использовать k дл…

У меня есть (temp) таблица, которая содержит записи студентов. Существует еще одна таблица, в которой содержатся учащиеся, по которым проходят занятия. Я хотел бы обновить таблицу ученика с предмет…

6 лет, 5 месяцев назад

Null Head

Предположим, что у меня есть 3 таблицы (как показано ниже). series_no table: | id | desc_seriesno | |:——|—————-:| | 7040 | AU1011 | | 7041 | AU1022 | | 7042 | AU1033 | | 7043 | AU1044…

Я пытаюсь преобразовать БД MySQL в MSSQL DB, но я экспериментирую с некоторыми проблемами при переводе запросов, в частности со следующим: MySQL SELECT GROUP_CONCAT( parent.Name ORDER BY parent.Lft…

Можно ли объединить строки с одной или несколькими другими группами по функции, например sum, avg, count и т.д. Скажем, у меня есть следующая таблица Id Name Order Value 1 a 1 100 2 b 2 200 3 c 1 3…

9 лет, 11 месяцев назад

Sarah

Моя проблема прямолинейна: я продолжаю пытаться преобразовать вывод таблицы из 1 a 1 b into 1 a b c 1 c 2 d 2 e into 2 d e f 2 f В таблице всегда будут наборы из 3 строк, которые станут таблицей с …

7 лет, 8 месяцев назад

Nathan

Эй, мне просто интересно, возможно ли следующее select id, name, (select name from secondTable where companyId = tableOne.id) as concatenatedString.. from tableOne поэтому то, что я ищу для выбора,…

9 лет, 6 месяцев назад

StevieB

2.8. Связанные таблицы — Transact-SQL В подлиннике : Персональный сайт Михаила Флёнова

На данный момент мы писали достаточно простые запросы, потому что использовали только одну таблицу. Но мы же создали в прошлой главе 4-е таблицы, и хотелось бы научиться связывать их в одно целое. Я бы не стал усложнять базу данных, создавая справочники, если бы связь не была возможной.

Давайте попробуем связать две таблицы на примере должностей. В таблице Peoples у нас есть поле «idPosition». В этом поле содержится идентификатор (первичный ключ) строки, с которой связана запись со строкой из таблицы «tbPosition». Следующий пример показывает, как можно связать эти таблицы:


SELECT * 
FROM tbPeoples, tbPosition
WHERE tbPeoples.idPosition=tbPosition.idPosition

Первая строка, как всегда говорит, что надо вывести все поля (SELECT *). Вторая строка говорит, из каких таблиц надо получать данные (FROM tbPeoples, tbPosition). На этот раз у нас здесь указано сразу две таблицы – работники и должности. Третья строка показывает связь:


tbPeoples.idPosition=tbPosition.idPosition

Для того, чтобы указать к какой таблице относиться поле «idPosition» (поле с таким именем есть в обеих таблицах, которые мы используем) мы записываем полное имя поля как ИмяБазы.ИмяПоля. Если имя поля уникально для обеих таблиц (как «vcFamil», которое есть только в таблице tbPeolpes), то можно имя таблицы опускать. Именно поэтому мы раньше опускали имя таблицы, когда использовали поля в секции SELECT и WHERE, ведь мы работали только с одной таблицей, и никаких конфликтов не могло быть. Как только мы указали две таблицы в секции FROM, сразу возникает вероятность встретиться с конфликтами имен полей.

Итак, в секции WHERE мы указываем, что поле «idPosition» из таблицы tbPeoples равно полю «idPosition» из таблицы tbPosition.

Связь необходима. Если ее не указать, то результат будет совершенно другим. Посмотрим, что произойдет, если не указывать связь, а просто выбрать данные из двух таблиц:


SELECT * 
FROM tbPeoples, tbPosition

Результат выполнения этого запроса показан на рисунке 2.4. На рисунке я немного изменил результат, чтобы поле «idPosition» из таблицы tbPeoples находилось рядом с одноименным полем (с которым происходит связь) из таблицы tbPosition. Выделенный фрагмент содержит поля, которые принадлежат таблице должностей.

Теперь посмотрим на строку Иванова. Обратите внимание, что их много. Иванов связался со всеми существующими должностями. Потом идут строки Петрова, который так же связался со всеми возможными должностями. Таким образом, количество строк в результате равно количеству строк из первой таблицы умноженное на количество строк из второй таблицы. Такое объединение называется ортогональным или декартовым.

Теперь посмотрим, что означает связь:


tbPeoples.idPosition=tbPosition.idPosition

Будем смотреть на эту команду не как на связь, а на как простое ограничение WHERE, которое говорит, что в результате поле «idPosition» в обоих, таблицах должны быть равны. Посмотрите на результат работы запроса без связи. Где значения этих полей равны? Для Иванова это та строка, где связь произошла с должностью генерального директора. Для Петрова это связь с коммерческим директором и т.д. Таким образом, все лишние записи отбрасываются, и мы получаем в результате только те строки, которые связаны по правильному ключу.

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

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


SELECT * 
FROM tbPeoples pl, tbPosition ps
WHERE pl.idPosition=ps.idPosition

В данном запросе у нас используется две таблицы и для каждой из них указывается псевдоним. Для таблицы tbPeoples это псевдоним pl, а для таблицы tbPosition это ps. В качестве псевдонима может выступать любое имя из любого количества букв. Я чаще всего использую первую букву, если она не будет конфликтовать с другими именами. В данном случае имена двух таблиц начинается с буквы p, вот и приходиться использовать две буквы.

В секции WHERE теперь не надо писать полное имя таблицы. Достаточно только указывать псевдоним:


pl.idPosition=ps.idPosition

Удобство от использования псевдонимов очень хорошо заметно, когда вы будете связывать несколько таблиц. Давайте посмотрим, как связывать три таблицы:


SELECT * 
FROM tbPeoples pl, tbPosition ps, tbPhoneNumbers pn
WHERE pl.idPosition=ps.idPosition
 AND pl.idPeoples=pn.idPeoples

В секции FROM перечислены уже три таблицы, а в секции WHERE наведены две связи. Таблица tbPeoples связана с таблицей должностей, а вторая связь связывает таблицу tbPeoples c таблицей телефонов.

У нас в таблице работников 19 записей, а в таблице телефонов 18 строк. Проанализируйте результат и вы увидите, что некоторые работники имеют по несколько номеров телефонов. Например, строка Иванова встречается 3 раза, но с разными номерами. Те работники, которые не имеют телефонов, в результат не попали. Почему? Просто нет связи, а значит условие pl.idPeoples=pn.idPeoples не срабатывает.

Использование жесткого объединение с помощью знака равенства называют внутренним объединением. Чтобы увидеть записи, которые не связаны, нужно использовать внешнее объединение, которое бывает левым или правым.

Как же тогда увидеть всех работников, и при этом наладить связь? Для этого используются левые объединения:


SELECT * 
FROM tbPeoples pl, tbPosition ps, tbPhoneNumbers pn
WHERE pl.idPosition=ps.idPosition
 AND pl.idPeoples*=pn.idPeoples

Самое интересное кроется как раз в последнем условии:


pl.idPeoples*=pn.idPeoples

Обратите внимание, что слева от знака равно стоит знак умножения или проще – звездочка. Это значит, что из таблицы работников (tbPeoples, которая находиться со стороны звездочки) нужно взять все строки, а если есть связь с таблицей, указанной справа, то отобразить ее.

Выполните этот запрос, и вы увидите всех работников. У тех, у кого нет номера телефона, поля из таблицы tbPhoneNumbers будут содержать нулевые значения NULL.

Использование знака * для не жесткого объединения описано в стандарте SQL, но я говорил, что не все базы данных поддерживают этот стандарт полностью. Например, MS Access позволяет создавать левые объединения, но здесь это делается совершенно по-другому. Мы рассмотрим этот метод в главе 2.8.

Когда мы связываем таблицы жестко с помощью знака равно, такое объединение называют внутренним. Когда мы используем не жесткое объединение со звездочкой, то оно бывает правым или левым. Чтобы вам проще было понять, где какое направление – посмотрите на звездочку. Мы ее поставили слева, значит, объединение было левым. Если бы звездочка была справа от знака равенства, то объединение стало бы правым.

Чтобы получить правое объединение, достаточно поменять поля местами:


SELECT * 
FROM tbPeoples pl, tbPosition ps, tbPhoneNumbers pn
WHERE pl.idPosition=ps.idPosition
 AND pn.idPeoples=*pl.idPeoples

Вот теперь знак звездочки находиться справа. Как видите, разница в них небольшая, но она значительна при использовании объединения таблиц по методу MS.

Псевдонимы можно использовать в любой секции, даже в секции SELECT:


SELECT pl.vcFamil, pl.vcName, pl.vcSurname, 
   ps.vcPositionName, pn.vcPhoneNumber
FROM tbPeoples pl, tbPosition ps, tbPhoneNumbers pn
WHERE pl.idPosition=ps.idPosition
 AND pl.idPeoples*=pn.idPeoples

Если быть более точным, то бывают случаи, когда использовать псевдонимы необходимо. Если есть имя поля, которое присутствует одновременно в обеих таблицах, то для его объявления в секции SELECT необходимо явно указать таблицу. Например, попробуйте добавить в список SELECT поле «idPeoples», без указания имени таблицы или псевдонима. В ответ на этот запрос, сервер выдаст ошибку: Ambiguous column name ‘idPeoples’ (двусмысленное имя колонки «idPeoples»). Сервер не знает, значение колонки «idPeoples», из какой таблицы нужно вернуть пользователю. Это вы знаете, что благодаря сравнению pl.idPeoples*=pn.idPeoples в результате все равно обе колонки будут содержать одно и то же значение, но сервер на это не надеется и даже не пытается понять, а просто выдает ошибку о двусмысленности.

При использовании связанных таблиц очень часто бывает необходимость выбрать одну таблицу полностью, а остальные могут выбираться частично. Например, давайте выберем из таблицы «tbPeoples» только ФИО, а из таблиц должностей и телефонов все поля:


SELECT vcFamil, vcName, vcSurname, ps.*, pn.*
FROM tbPeoples pl, tbPosition ps, tbPhoneNumbers pn
WHERE pl.idPosition=ps.idPosition
 AND pl.idPeoples*=pn.idPeoples

Обратите внимание, что поля, которые нам нужны из таблицы tbPeoples — перечисляются, а чтобы не перечислять все поля остальных таблиц, мы просто пишем ps.* или pn.*. То есть знак звездочки, означающий вывод всех полей относится не ко всем таблицам, а только к перечисленным.

В главе 1.2.6 мы рассматривали пример создания таблицы, в которой внешний ключ был связан с первичным ключом той же самой таблицы. В нашей тестовой базе данных такой таблицей является tbPosition, где хранятся должности работников. В этой таблице поле «idParentPosition» связано с первичным ключом «idPosition» этой же таблицы и предназначено для указания названия должности, которая является главной. Таким образом, можно построить дерево главный-подчиненный.

Давайте попробуем вывести табличку из двух полей, где первое поле будет отображать название должности, а второе – главную должность. Вот как это будет выглядеть в виде SQL запроса:


SELECT p1.vcPositionName AS 'Должность', 
    p2.vcPositionName AS 'Главная должность'
FROM tbPosition p1, tbPosition p2
WHERE p1.idParentPosition*=p2.idPosition

Прежде чем мы разберем этот запрос, давайте посмотрим на результат его работы:


ДОЛЖНОСТЬ                  ГЛАВНАЯ ДОЛЖНОСТЬ
Генеральный директор       NULL
Коммерческий директор      Генеральный директор
Директор по общим вопросам Генеральный директор
Начальник отдела снабжения Коммерческий директор
Начальник отдела сбыта     Коммерческий директор
Начальник отдела кадров    Директор по общим вопросам
ОТиЗ                       Директор по общим вопросам
Бухгалтерия                Коммерческий директор
Менеджер по снабжению      Начальник отдела снабжения
Менеджер по продажам       Начальник отдела сбыта

Первая строка соответствует должности генерального директора. Это самый главный человек в компании, поэтому для нее во второй колонке указан NULL, т.е. главной должности нет.

Следующая строка в первой колонке содержит должность коммерческого директора. Вполне логично, что она подчиняется генеральному директору, что и отображено во второй колонке результата.

Теперь посмотрим на SQL запрос, с помощью которого мы получили эти данные. Для начала посмотрим на секцию FROM, где дважды указана одна и та же таблица «tbPosition», но с разными псевдонимами p1 и p2. В секции WHERE мы наводим связь между псевдонимами одной и той же таблицы:


p1.idParentPosition*=p2.idPosition

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

Теперь посмотрите на следующий запрос:


SELECT p1.vcPositionName AS 'Должность', 
 p2.vcPositionName AS 'Главная должность',
 p3.vcPositionName AS 'Главная для главной'
FROM tbPosition p1, tbPosition p2, tbPosition p3
WHERE p1.idParentPosition=p2.idPosition
 AND p2.idParentPosition*=p3.idPosition

Здесь мы дважды использовали связь таблицы саму на себя. Результат работы этого запроса:


Должность                  Главная должность     Главная для главной
Коммерческий директор      Генеральный директор  NULL
Директор по общим вопросам Генеральный директор  NULL
Начальник отдела снабжения Коммерческий директор ГенеральныйДиректор
Начальник отдела сбыта     Коммерческий директор ГенеральныйДиректор

Давайте теперь напишем запрос, который отобразит все записи из всех связанных таблиц нашей тестовой базы данных. А таблиц у нас всего 4, но в нашей секции FROM будет пять таблиц, потому что дважды будет ссылка на таблицу должностей, чтобы отобразить должность текущего работника и должность начальника:


SELECT pl.vcFamil, pl.vcName, pl.vcSurname, dDateBirthDay,
 p1.vcPositionName AS 'Должность', p2.vcPositionName AS 'Начальник',
 pn.vcPhoneNumber, pt.vcTypeName
FROM tbPeoples pl, tbPosition p1, tbPosition p2, 
  tbPhoneNumbers pn, tbPhoneType pt
WHERE pl.idPosition=p1.idPosition
 AND p1.idParentPosition*=p2.idPosition
 AND pn.idPeoples=pl.idPeoples
 AND pt.idPhoneType=pn.idPhoneType

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

Саязанные таблицы в стиле MS

Объединение по стандарту SQL, который мы рассматривали в главе 2.7, описывает условие связи в секции WHERE. В MS зачем-то связи перенесли в секцию FROM. На мой взгляд, это как минимум не удобно для создания и для чтения связей. Стандартный вариант намного проще и удобнее. И все же, метод MS мы рассмотрим, ведь только с его помощью в MS Access можно создать левое или правое объединение, и этот же метод поддерживается в MS SQL Server.

Ортогональное объединение по методу MS, т.е. без указания связи:


SELECT * 
FROM tbPeoples CROSS JOIN tbPosition

Внутреннее объединение (эквивалентно знаку равенства) по методу MS описывается следующим образом:


SELECT * 
FROM tbPeoples pl INNER JOIN tbPosition ps 
     ON pl.idPosition=ps.idPosition

Как видите, для этого метода не нужна секция WHERE, но зато намного больше всего нужно писать. Вначале мы описываем, что нам нужно внутреннее объединение (INNER JOIN). Слева и справа от этого оператора указываются таблицы, которые нужно связать. После этого ставиться ключевое слово ON, и только теперь наводим связь между полями связанных таблиц. Таким образом, этот запрос эквивалентен следующему:


SELECT * 
FROM tbPeoples pl, tbPosition ps 
WHERE pl.idPosition=ps.idPosition

Самая большая путаница начинается, когда нужно объединить три таблицы в одно целое. Посмотрите на следующий запрос:


SELECT * 
FROM tbPeoples pl LEFT OUTER JOIN tbPhoneNumbers pn
     ON pl.idPeoples=pn.idPeoples
     INNER JOIN tbPosition ps 
     ON pl.idPosition=ps.idPosition

Сначала объединяются таблицы tbPeoples и tbPhoneNumbers через внешнее левое объединение (LEFT OUTER JOIN). Затем указывается связь между этими таблицами. А вот теперь результат объединение, связываем внутренним объединением (INNER JOIN) с таблицей tbPosition. Внимательно осмотрите запрос, чтобы понять его формат, и что в нем происходит.

Чтобы получить правое объединение, необходимо просто поменять перечисление таблиц местами:


SELECT * 
FROM tbPhoneNumbers pn RIGHT OUTER JOIN tbPeoples pl 
     ON pl.idPeoples=pn.idPeoples
     INNER JOIN tbPosition ps 
     ON pl.idPosition=ps.idPosition

Меняется местами перечисление таблиц, а вот порядок указания связанных полей не имеет особого значения и здесь ничего не меняется.

Если честно, то мне не очень нравиться объединение по методу Microsoft. Какое-то оно неудобное и громоздкое. Даже не знаю, зачем его придумали, когда в стандарте есть все то же самое, только намного проще и нагляднее.

+ (конкатенация строк) (Transact-SQL) — SQL Server

  • 5 минут на чтение

В этой статье

Применимо к: SQL Server (все поддерживаемые версии) База данных SQL AzureAzure SQL Managed InstanceAzure Synapse Analytics Хранилище параллельных данных

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

Соглашения о синтаксисе Transact-SQL

Синтаксис

  выражение + выражение
  

Аргументы

выражение
Любое допустимое выражение любого из типов данных в категории символьных и двоичных данных, за исключением типов данных image , ntext или text . Оба выражения должны иметь один и тот же тип данных, или одно выражение должно быть неявно преобразовано в тип данных другого выражения.

Явное преобразование в символьные данные должно использоваться при объединении двоичных строк и любых символов между двоичными строками. В следующем примере показано, когда CONVERT или CAST необходимо использовать с двоичной конкатенацией, а когда CONVERT или CAST использовать не обязательно.

  DECLARE @ mybin1 VARBINARY (5), @ mybin2 VARBINARY (5)
НАБОР @ mybin1 = 0xFF
НАБОР @ mybin2 = 0xA5
- Никаких функций CONVERT или CAST не требуется, потому что этот пример
- объединяет две двоичные строки.ВЫБЕРИТЕ @ mybin1 + @ mybin2
- Требуется функция CONVERT или CAST, потому что в этом примере
- объединяет две двоичные строки плюс пробел.
ВЫБРАТЬ ПРЕОБРАЗОВАТЬ (VARCHAR (5), @ mybin1) + ''
   + ПРЕОБРАЗОВАТЬ (VARCHAR (5), @ mybin2)
- Вот такое же преобразование с использованием CAST.
ВЫБРАТЬ CAST (@ mybin1 AS VARCHAR (5)) + ''
   + CAST (@ mybin2 AS VARCHAR (5))
  

Типы результатов

Возвращает тип данных аргумента с наивысшим приоритетом. Дополнительные сведения см. В разделе Приоритет типов данных (Transact-SQL).

Замечания

Оператор + (объединение строк) ведет себя иначе, когда он работает с пустой строкой нулевой длины, чем когда он работает с NULL или неизвестными значениями. Строку символов нулевой длины можно указать в виде двух одинарных кавычек без каких-либо символов внутри кавычек. Двоичная строка нулевой длины может быть указана как 0x без каких-либо значений байтов, указанных в шестнадцатеричной константе. Объединение строки нулевой длины всегда объединяет две указанные строки.Когда вы работаете со строками с нулевым значением, результат конкатенации зависит от настроек сеанса. Точно так же, как арифметические операции, которые выполняются с нулевыми значениями, когда нулевое значение добавляется к известному значению, результатом обычно является неизвестное значение, операция конкатенации строк, выполняемая с нулевым значением, также должна давать нулевой результат. Однако вы можете изменить это поведение, изменив настройку CONCAT_NULL_YIELDS_NULL для текущего сеанса. Дополнительные сведения см. В разделе SET CONCAT_NULL_YIELDS_NULL (Transact-SQL).

Если результат объединения строк превышает ограничение в 8000 байт, результат обрезается. Однако, если хотя бы одна из связанных строк является типом с большим значением, усечение не происходит.

Примеры

A. Использование конкатенации строк

В следующем примере создается один столбец под заголовком столбца Имя из многосимвольных столбцов с фамилией человека, за которой следует запятая, один пробел и затем имя человека.Набор результатов находится в возрастающем алфавитном порядке по фамилии, а затем по имени.

  - Использует AdventureWorks
  
ВЫБЕРИТЕ (Фамилия + ',' + Имя) КАК Имя
ОТ Person.Person
ORDER BY LastName ASC, FirstName ASC;
  

B. Объединение числовых типов данных и данных даты

В следующем примере функция CONVERT используется для объединения типов данных numeric и date .

  - Использует AdventureWorks
  
ВЫБЕРИТЕ 'Заказ подлежит оплате' + КОНВЕРТИРОВАТЬ (VARCHAR (12), DueDate, 101)
ОТ ПРОДАЖ.SalesOrderHeader
ГДЕ SalesOrderID = 50001;
ИДТИ
  

Вот результат.

  ------------------------------------------------
Срок подачи заказа - 23.04.2007 г.
(Затронута 1 строка (и))
  

C. Использование конкатенации нескольких строк

В следующем примере несколько строк объединяются в одну длинную строку для отображения фамилии и первого инициала вице-президентов Adventure Works Cycles. После фамилии добавляется запятая, а после первого инициала — точка.

  - Использует AdventureWorks
  
SELECT (LastName + ',' + SPACE (1) + SUBSTRING (FirstName, 1, 1) + '.') AS Name, e.JobTitle
ОТ Person.Person AS p
    ПРИСОЕДИНЯЙТЕСЬ к HumanResources.Employee AS e
    НА p.BusinessEntityID = e.BusinessEntityID
ГДЕ e.JobTitle КАК 'Vice%'
ЗАКАЗАТЬ ПО ФАМИЛИ ASC;
ИДТИ
  

Вот результат.

  Имя Заголовок
------------- --------------- `
Даффи Т. Вице-президент по инженерным вопросам
Гамильтон, Дж.Вице-президент по производству
Велкер Б. Вице-президент по продажам

(3 строки затронуты)
  

D. Использование больших строк в конкатенации

В следующем примере несколько строк объединяются в одну длинную строку, а затем предпринимается попытка вычислить длину последней строки. Конечная длина набора результатов — 16000, потому что оценка выражения начинается слева, то есть @x + @z + @y => (@x + @z) + @y. В этом случае результат (@x + @z) обрезается до 8000 байт, а затем к набору результатов добавляется @y, что делает окончательную длину строки 16000.Поскольку @y — строка типа большого значения, усечение не происходит.

  ОБЪЯВИТЬ @x VARCHAR (8000) = REPLICATE ('x', 8000)
ОБЪЯВИТЬ @y VARCHAR (max) = REPLICATE ('y', 8000)
ОБЪЯВИТЬ @z VARCHAR (8000) = REPLICATE ('z', 8000)
НАБОР @y = @x + @z + @y
- Результат следующего выбора - 16000
ВЫБЕРИТЕ LEN (@y) AS y
ИДТИ
  

Вот результат.

  г
-------
16000
 
(Затронута 1 строка (и))
  

Примеры: Azure Synapse Analytics и хранилище параллельных данных

E.Использование конкатенации нескольких строк

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

  - Использует AdventureWorks
  
ВЫБЕРИТЕ (Фамилия + ',' + ПОДСТРОКА (Имя, 1, 1) + '.') Как Имя, Заголовок
ОТ DimEmployee
ГДЕ Титул КАК "% Vice Pres%"
ЗАКАЗАТЬ ПО ФАМИЛИ ASC;
  

Вот результат.

  Имя Заголовок
------------- ---------------
Даффи Т. Вице-президент по инженерным вопросам
Гамильтон Дж. Вице-президент по производству
Велкер Б. Вице-президент по продажам
  

См. Также

+ = (Назначение конкатенации строк) (Transact-SQL)
ALTER DATABASE (Transact-SQL)
CAST и CONVERT (Transact-SQL)
Преобразование типов данных (ядро СУБД)
Типы данных (Transact-SQL)
Выражения (Transact -SQL)
Встроенные функции (Transact-SQL)
Операторы (Transact-SQL)
SELECT (Transact-SQL)
Операторы SET (Transact-SQL)

6 способов объединения строки и числа в SQL Server

Если вы когда-либо пытались объединить строку с числом при использовании SQL Server, но получали ошибку, эта статья должна прояснить ситуацию.Существует несколько способов выполнить конкатенацию с использованием T-SQL в SQL Server, и если вы объединяете разные типы данных (например, строку и число), вы можете получить ошибку, в зависимости от того, как вы выполняете конкатенацию.

При объединении разных типов данных следует помнить, что сначала их нужно преобразовать в один и тот же тип данных. Более конкретно, при конкатенации строки с числом необходимо преобразовать число в строку, прежде чем оно может быть соединено со строкой.К счастью, SQL Server / T-SQL упрощает эту задачу.

В этой статье представлены шесть способов объединения строк с числами с помощью T-SQL.

Функция CONCAT ()

Самый очевидный (и, возможно, лучший) способ объединить строку и число — использовать функцию CONCAT () . Это позволяет указать строку и число как два отдельных аргумента. Затем SQL Server объединит их, и ваше объединение будет завершено.

Пример

 SELECT CONCAT ('Комментарии:', 9) AS Result; 

Результат:

 Результат
-----------
Комментариев: 9 

Как видите, работает отлично.Строка и число представлены как одно поле.

Обратите внимание, что вы не ограничены только одной строкой и одним числом — функция CONCAT () может принимать до 254 аргументов (т. Е. Вы можете объединить до 254 строк / чисел вместе.

Также обратите внимание, что CONCAT () неявно преобразует все аргументы в строковые типы перед объединением. Кроме того, CONCAT () неявно преобразует любые нулевые значения в пустые строки.

Функция CONCAT_WS ()

Мы можем продвинуться на шаг вперед в предыдущем примере, используя функцию CONCAT_WS () .Эта функция позволяет указать разделитель.

Чтобы предоставить разделитель, просто добавьте его в качестве первого аргумента. Затем укажите строку и число в качестве второго и третьего аргументов.

 SELECT CONCAT_WS (':', 'Комментарии', 9) КАК Результат; 

Результат:

 Результат
-----------
Комментариев: 9 

Обратите внимание, что эта функция не обязательно подходит для разделения пар имя / значение, поскольку разделитель добавляется между каждым отдельным элементом, который объединен (поэтому он также будет добавлен между каждой парой, если у вас несколько пар).В нашем случае это работает нормально, потому что нам нужно объединить только одну пару имя / значение.

Однако вы всегда можете вложить несколько функций CONCAT_WS () , чтобы вернуть правильную конкатенацию для ваших нужд (чтобы у вас был другой разделитель между каждой парой).

Функция CONVERT ()

Если по какой-то причине вы не можете (или не хотите) использовать функции CONCAT () или CONCAT_WS () , вы можете выполнить конкатенацию с помощью оператора конкатенации строк ( + ).При использовании этого метода вам нужно будет выполнять преобразование любых типов данных вручную.

Одним из способов преобразования между типами данных является использование функции CONVERT () .

Вот как это сделать, используя те же данные из предыдущих примеров:

 SELECT 'Комментарии:' + CONVERT (varchar (12), 9) AS Result; 

Результат:

 Результат
-----------
Комментариев: 9 

В этом случае я конвертирую целое число в varchar (12), но это могут быть данные любого типа и длины, которые вам нужны.

Функция CAST ()

Функция CAST () очень похожа на функцию CONVERT () . Основное отличие состоит в том, что CAST () является стандартным ANSI, а CONVERT () относится только к T-SQL. Сказав это, CONVERT () действительно имеет некоторые дополнительные функции, но для целей этих примеров вы можете использовать любой из них.

Вот версия CAST () , использующая те же данные из предыдущих примеров:

 SELECT 'Комментарии:' + CAST (9 AS varchar (12)) AS Result; 

Результат:

 Результат
-----------
Комментариев: 9 

Функция TRY_CONVERT ()

Одна потенциальная проблема при использовании функции CONVERT () заключается в том, что, если преобразование не завершится успешно, вы получите сообщение об ошибке.Хотя во многих случаях это нормально, в некоторых случаях это может быть нежелательно. В таких случаях вам может оказаться более подходящим TRY_CONVERT () .

Функция TRY_CONVERT () преобразует тип данных так же, как функция CONVERT () . Однако, если данные не могут быть преобразованы, будет возвращено null .

Например, если мы попытаемся сделать следующее, мы получим ошибку:

 SELECT 'Комментарии:' + CONVERT (varchar (1), 10.00) AS Result; 

Результат:

 Ошибка: ошибка арифметического переполнения при преобразовании числового типа в тип данных varchar.

Однако, если мы используем TRY_CONVERT () , мы получим null :

 SELECT 'Комментарии:' + TRY_CONVERT (varchar (1), 10.00) AS Result; 

Результат:

 Результат
------
null 

В этом случае можно использовать условное программирование для выполнения другой задачи в зависимости от результата.

Функция TRY_CAST ()

Аналогичным образом работает функция TRY_CAST () . Он преобразует тип данных так же, как функция CAST () , и, если данные не могут быть преобразованы, возвращает null .

Например, это вызывает ошибку:

 SELECT 'Комментарии:' + CAST (10.00 AS varchar (1)) AS Result; 

Результат:

 Ошибка: ошибка арифметического переполнения при преобразовании числового типа в тип данных varchar. 

Но если вместо этого использовать TRY_CAST () , мы получим null :

 SELECT 'Комментарии:' + TRY_CAST (10.00 AS varchar (1)) AS Result; 

Результат:

 Результат
------
null 

SQL Server: + Оператор


В этом руководстве по SQL Server объясняется, как использовать оператор конкатенации (оператор + ) в SQL Server (Transact-SQL) с синтаксисом и примерами.

Описание

В SQL Server (Transact-SQL) оператор + позволяет объединить 2 или более строк вместе.

Синтаксис

Синтаксис оператора + в SQL Server (Transact-SQL):

 строка1 + строка2 + строка_n 

Параметры или аргументы

строка1
Первая строка для объединения.
строка2
Вторая строка для объединения.
строка_n
N-я строка для объединения.

Относится к

Оператор + может использоваться в следующих версиях SQL Server (Transact-SQL):

  • SQL Server 2017, SQL Server 2016, SQL Server 2014, SQL Server 2012, SQL Server 2008 R2, SQL Server 2008, SQL Server 2005

Пример

Давайте рассмотрим некоторые примеры операторов SQL Server + и узнаем, как использовать оператор + в SQL Server (Transact-SQL).

Например:

 ВЫБЕРИТЕ «TechOnTheNet» + «.com»;
  Результат:  'TechOnTheNet.com'

ВЫБЕРИТЕ 'Tech' + 'On' + 'The' + 'Net' + '.com';
  Результат:  'TechOnTheNet.com'

ВЫБЕРИТЕ «Tech» + «On» + «The» + «Net»;
  Результат:  «Интернет-технологии» 

Объединенные символы пространства

Когда вы объединяете значения вместе, вы можете добавить символы пробела, чтобы разделить ваши объединенные значения. В противном случае вы можете получить длинную строку с объединенными значениями, работающими вместе.Это очень затрудняет чтение результатов.

Давайте рассмотрим простой пример.

Мы можем объединить пробел с помощью оператора + .

Например:

 ВЫБЕРИТЕ «Джейн» + «» + «Смит»;
  Результат:  'Джейн Смит' 

В этом примере мы использовали оператор + , чтобы добавить пробел между значениями Jane и Smith . Это предотвратит сплющивание наших ценностей.

Вместо этого наш результат будет выглядеть следующим образом:

 'Джейн Смит' 

Вы бы чаще использовали оператор + для объединения символа пробела, когда вы объединяете несколько полей вместе.

Например:

 ВЫБЕРИТЕ first_name + '' + last_name AS contact_name
ОТ контактов; 

В этом примере будет возвращен набор результатов с одним столбцом, состоящим из полей first_name и last_name (разделенных пробелом) из таблицы contacts .Столбец в наборе результатов будет иметь псевдоним contact_name .

Объединенные одиночные цитаты

Поскольку оператор + объединяет строковые значения, заключенные в одинарные кавычки, непросто добавить символ одинарной кавычки в результат конкатенированной строки.

Давайте рассмотрим довольно простой пример, который показывает, как добавить одинарную кавычку к результирующей строке с помощью оператора + .

Например:

 SELECT «Давайте» + «изучим SQL Server»;
  Результат:  «Давайте изучим SQL Server» 

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

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

 SELECT 'Let' + '' '' + 's' + 'изучать SQL Server';
  Результат:  «Давайте изучим SQL Server» 

Обзор функции CONCAT в SQL с примерами

В этой статье мы исследуем синтаксис, рабочий механизм и другие детали функции CONCAT в SQL, а также составим различные примеры на ее основе.

Введение

Строка — это набор символов, который помогает объявлять тексты на языках программирования. Что касается SQL Server, мы можем разделить строковые типы данных SQL на две разные группы. Это:

Мы должны принять во внимание один момент, касающийся типов данных text и ntext . Эти типы данных устарели, и по этой причине мы должны стараться не использовать эти типы данных. Вместо этого мы можем использовать nvarchar (max) или varchar (max) .

Строковые функции SQL используются для управления символьными выражениями или для получения различной информации о них. Функция CONCAT в SQL — один из наиболее полезных членов этих функций. Функция CONCAT — это строковая функция SQL, которая обеспечивает объединение двух или более чем двух символьных выражений в одну строку. Теперь мы перейдем к сути на простом примере.

Синтаксис функции CONCAT

Синтаксис функции выглядит следующим образом:

CONCAT (строковое_значение1, строковое_значение2 [, строковое_значениеN])

Функция CONCAT требует как минимум двух параметров, и эта функция может принимать не более 254 параметров.

Примеры функции CONCAT

В этом примере мы объединим строки Think и green с помощью функции CONCAT:

SELECT CONCAT (‘Think’, ‘green’) AS ‘FullString’

Как мы ясно видим в этом первом примере, функция CONCAT объединила эти две строки, и мы получили строку Thinkgreen .

Во втором примере мы объединим 7 строк:

SELECT CONCAT (‘If’, ‘you’, ‘save’, ‘a’, ‘tree’, ‘you’, ‘save’, ‘a’, ‘life’) AS ‘FullString’

В этом втором примере функция CONCAT объединила более двух строк, и результат был . Если вы сохраните дерево, вы спасете жизнь .

Кроме того, мы можем объединить переменные с помощью этой функции:

DECLARE @ Str1 AS VARCHAR (100) = ‘Think’

DECLARE @ Str2 AS VARCHAR (100) = ‘-‘

DECLARE @ Str3 AS VARCHAR (100) = ‘green’

SELECT CONCAT (@ Str1, @ Str2, @ Str3) AS ResultString

Объединение числовых выражений с функцией CONCAT в SQL

Функция CONCAT также может объединять числовые значения.В следующем примере мы объединим три разных целочисленных значения:

SELECT CONCAT (11,33,99) AS Результат

Как мы видим, мы не использовали какие-либо функции CAST или CONVERT для соединения этих числовых выражений с функцией. С другой стороны, если мы хотим объединить эти выражения со знаком плюс ( + ), нам нужно преобразовать их в строковые типы данных.В противном случае результат операции конкатенации будет неверным:

SELECT CAST (11 AS VARCHAR (10)) + CAST (33 AS VARCHAR (10)) + CAST (99 AS VARCHAR (10)) AS TrueResult

В следующем примере демонстрируется объединение числовых выражений с ( + ) плюс без какого-либо преобразования данных, поэтому результат будет математическим сложением:

ВЫБРАТЬ 11 + 33 + 99 AS WrongResult

Теперь давайте исследуем и попытаемся понять, что происходит за кулисами в процессе объединения числовых выражений с помощью функции CONCAT.

Во-первых, мы создадим тестовую таблицу, чтобы вставить несколько числовых выражений. Следующий сценарий создаст таблицу Test_NumericValue :

УДАЛИТЬ ТАБЛИЦУ, ЕСЛИ СУЩЕСТВУЕТ Test_NumericValue

СОЗДАТЬ ТАБЛИЦУ Test_NumericValue (Number_1 INT, Number_2 INT, Number_3 INT)

На втором этапе мы вставим тестовые данные в эту таблицу:

ВСТАВИТЬ ЗНАЧЕНИЯ Test_NumericValue (11,33,99)

Теперь мы выполним приведенный ниже оператор SELECT в плане ApexSQL:

ВЫБРАТЬ СЦЕПИТЬ (Число_1, Число_2, Число_3) ИЗ Test_NumericValue

На этом этапе мы проанализируем фактические детали плана выполнения запроса.Причина, по которой мы анализируем план выполнения, заключается в том, что в нем скрыты все подробности операции обработки запроса:

Кратко поясним упомянутый выше план запроса. Оператор сканирования таблицы указывает, что оптимизатору запросов требуется прочитать все данные Test_NumericValue , поскольку они не содержат индекса. Однако для данной таблицы это не проблема, поскольку она содержит только одну строку. С другой стороны, если мы обнаружим этот оператор для любой таблицы с огромным количеством строк, эта ситуация может указывать на проблему с производительностью.Оператор Compute Scalar выполняет скалярное вычисление и берет на себя задачу завершения операции функции CONCAT для выполнения этого запроса. На последнем этапе плана выполнения оператор SELECT представляет результат запроса. Предупреждающий знак отображается на операторе SELECT. Мы упомянем детали этого предупреждающего знака в следующем совете. Теперь мы перейдем на вкладку Operations , чтобы узнать больше об операторе Compute Scalar.

Как мы ясно видим, преобразование данных произошло во время выполнения запроса.В частности, для этого запроса выражения типа данных целое число (INT) преобразуются в строки (VARCHAR). На этом примере мы продемонстрировали, что операция преобразования данных выполняется функцией CONCAT. В следующем совете мы выделим еще одну проблему, связанную с планом выполнения, — операцию CONVERT_IMPLICIT .

Совет: Функция CONCAT в SQL выполняет неявное преобразование, если передается какой-либо параметр нестрокового типа данных.

Как мы упоминали выше, на операторе SELECT в плане выполнения отображается предупреждающий знак.Причина этого знака заключается в том, что если мы используем какие-либо несимвольные параметры в функции CONCAT, эти параметры будут автоматически преобразованы в строковый тип данных SQL Server. Затем будет выполнена операция объединения строк. Теперь мы подкрепим эту теоретическую информацию примером:

Сначала мы выполним следующий запрос, чтобы подготовить тестовую среду:

DROP TABLE IF EXISTS PhoneNumbers

CREATE TABLE PhoneNumbers (ClientName VARCHAR (100), AreaCode INT, PhoneNumber BIGINT, Dt DATETIME)

INSERT INTO PhoneNumbers VALUES (‘Name-1’, 301,29DATE) ())

ВСТАВИТЬ ЗНАЧЕНИЯ телефонных номеров (‘Name-1’, 925,5781725, GETDATE ())

ВСТАВИТЬ ЗНАЧЕНИЯ телефонных номеров (‘Name-3’, 207,3188796, GETDATE ())

Следующий запрос попытается объединить 4 различных выражения с типизированными данными.Это VARCHAR , INT , BIGINT, и DATETIME .

Теперь мы выполним следующий запрос:

SELECT CONCAT (ClientName, AreaCode, PhoneNumber, Dt) как результат FROM PhoneNumbers

Как мы видим, все выражения с разными типами данных объединяются без ошибок.Теперь проанализируем план выполнения запроса:

Когда мы наводим курсор на значок оператора SELECT , появляется всплывающее окно и явно проявляется проблема неявного преобразования. Неявное преобразование — это операция преобразования данных, которая выполняется SQL Server автоматически, когда это необходимо. Кроме того, вы можете посмотреть статью «Неявное преобразование в SQL Server», чтобы узнать больше о понятии неявного преобразования.

значение NULL и функция CONCAT в SQL

NULL — это специальный указатель, который определяет значение, которое неизвестно или не существует в SQL Server.С точки зрения функции CONCAT, если мы используем значение NULL в качестве параметра функции CONCAT, оно преобразует значения NULL в пустую строку. Теперь мы сделаем это на примере:

SELECT CONCAT (‘Think’, NULL, ‘green’) AS ‘FullString’

Как мы видим, выражение NULL, используемое в функции CONCAT, не повлияло на результат функции и вело себя как пустая строка.Кроме того, если мы передадим все параметры как NULL , , результатом функции будет пустая строка. Теперь мы рассмотрим это на примере:

ВЫБРАТЬ CONCAT (NULL, NULL, NULL) AS ‘FullString’

В результате мы можем сказать, что значения NULL не влияют на вывод функции.

Как использовать перевод строки (\ n) и возврат каретки (\ r) с функцией CONCAT

Функция CHAR позволяет преобразовывать числа ASCII в символьные значения.Следующие коды ASCII могут использоваться для получения новой строки с функцией CHAR в SQL:

Значение

Char

Описание

10

LF

Подача строки

13

CR

Возврат каретки

Мы можем получить новую строку, если объединим строки с помощью следующих функций CHAR:

  • СИМВОЛ (10): Новая строка / перевод строки
  • СИМВОЛ (13): Возврат каретки

Например, следующий запрос дает построчную конкатенированную строку с функцией CHAR (13):

SELECT CONCAT (‘Make’, CHAR (13), ‘every’, CHAR (13), ‘drop’, CHAR (13), ‘of’, CHAR (13), ‘вода’, CHAR (13),

‘count’) AS Результат

Теперь мы заменим выражение CHAR (13) на выражение CHAR (10) и повторно выполним тот же запрос:

SELECT CONCAT (‘Make’, CHAR (10), ‘every’, CHAR (10), ‘drop’, CHAR (10), ‘of’, CHAR (10), ‘вода’, CHAR (10),

‘count’) AS Результат

В то же время мы можем использовать CHAR (13) и CHAR (10) вместе.Этот тип использования может быть хорошим вариантом, когда мы хотим создать разрыв строки. Теперь мы продемонстрируем это:

SELECT CONCAT (‘Make’, CHAR (10), CHAR (13), ‘every’, CHAR (10), CHAR (13), ‘drop’, CHAR (10), CHAR (13)

, ‘). of ‘, CHAR (10), CHAR (13),’ water ‘, CHAR (10), CHAR (13),

‘ count ‘) AS Результат

Заключение

В этой статье мы изучили функцию CONCAT в SQL на различных примерах.Функция CONCAT — очень полезный вариант для объединения выражений в SQL.

Эсат Эркеч — специалист по SQL Server, который начал свою карьеру более 8 лет назад в качестве разработчика программного обеспечения. Он является сертифицированным экспертом по решениям Microsoft SQL Server.

Большая часть его карьеры была сосредоточена на администрировании и разработке баз данных SQL Server. В настоящее время он интересуется администрированием баз данных и бизнес-аналитикой. Вы можете найти его в LinkedIn.

Посмотреть все сообщения от Esat Erkec

Последние сообщения от Esat Erkec (посмотреть все)

|| Оператор конкатенации строк — миграция с Oracle на SQL Server

|| Оператор объединяет одну или несколько строк в одну строку в Oracle.

Быстрый пример :

 - Объединение строк New и York
   ВЫБЕРИТЕ «Новый» || 'Йорк' ОТ двойного;
   - Результат: Нью-Йорк 

Сводная информация:

Синтаксис string_expression1 || string_expression2 || …
Значения NULL Значение NULL в любом выражении обрабатывается как » (пустая строка)
Но || возвращает NULL, если все выражения равны NULL
Преобразование выражений Числовые и datetime-выражения неявно преобразуются в строку перед конкатенацией
Альтернативы Функция CONCAT Только 2 параметра NULL is » (пустая строка)

Последнее обновление: Oracle 11g Release 2

|| Оператор объединяет одно или несколько строковых выражений в одну строку.

Оракул :

 ВЫБРАТЬ «Город» || "есть" || «Париж» ОТ двойного;
   - Результат: Город Париж 

NULL — пустая строка

Значение NULL в любом строковом выражении рассматривается как » (пустая строка).

Оракул :

 ВЫБРАТЬ «Город» || "есть" || NULL FROM dual;
   - Результат: Город 

Но если все выражений оцениваются как NULL, || Оператор возвращает NULL, а не пустую строку.

Оракул :

 ВЫБРАТЬ NVL (NULL || NULL || NULL, 'Нулевое значение') FROM dual;
   - Результат: нулевое значение 

Неявное преобразование нестроковых параметров

|| Оператор неявно преобразует числа и значения даты и времени в строку перед конкатенацией.

Оракул :

 ВЫБРАТЬ 1 || 'st' ОТ двойного;
  - Результат: 1-й

  ВЫБЕРИТЕ «Сегодня» || SYSDATE FROM dual;
  - Результат: Сегодня 28-МАЯ-12 

Вы можете конвертировать Oracle || оператор конкатенации строк с оператором + или функцией CONCAT в SQL Server и SQL Azure:

+ Оператор
Если какое-либо значение равно NULL, результат будет NULL, если только CONCAT_NULL_YIELDS_NULL не выключен
Требуется явное литье
CONCAT Функция
NULL — это » (пустая строка), не зависит от CONCAT_NULL_YIELDS_NULL
Можно указать более двух выражений
Доступно с SQL Server 2012

Последнее обновление: Microsoft SQL Server 2012

В SQL Server оператор + и функция CONCAT позволяют объединить более двух строк.

SQL Server :

 SELECT "Город" + "равен" + "Париж";
   - Результат: город - Париж.

   ВЫБРАТЬ СЦЕПИТЬ ('Город', 'есть', 'Париж');
   - Результат: Город Париж 

Значения NULL

В SQL Server, если какое-либо выражение имеет значение NULL, оператор + возвращает NULL для всего выражения (по умолчанию), а CONCAT обрабатывает NULL.
значение в любом выражении как » (пустая строка).

SQL Server :

 SELECT 'Город' + 'равен' + NULL;
   - Результат: NULL

   SELECT CONCAT ('Город', 'равно', NULL);
   - Результат: Город 

Но установив для CONCAT_NULL_YIELDS_NULL значение OFF, вы также можете указать, чтобы NULL обрабатывался как » (пустая строка) с помощью оператора +.

SQL Server :

 УСТАНОВИТЬ CONCAT_NULL_YIELDS_NULL ВЫКЛ.

   ВЫБЕРИТЕ 'Город' + 'равен' + NULL;
   - Результат: Город 

Обратите внимание, что CONCAT_NULL_YIELDS_NULL не применяется к функции CONCAT, он всегда обрабатывает NULL как » (пустая строка).

К сожалению (с точки зрения миграции) Microsoft не рекомендует использовать SET CONCAT_NULL_YIELDS_NULL OFF,
и планирует всегда устанавливать для этой опции значение ON, поэтому вы должны использовать функцию CONCAT или функцию ISNULL для отдельных выражений, чтобы заменить NULL
с » (пустая строка), чтобы получить то же поведение, что и в Oracle.

SQL Server :

 SELECT 'Город' + 'равен' + ISNULL (NULL, '');
   - Результат: Город 

Неявное преобразование нестроковых параметров

В отличие от || в Oracle оператор + в SQL Server требует явного преобразования чисел и значений даты и времени в строку перед объединением.

SQL Server :

 ВЫБРАТЬ 1 + 'st';
  -- Ошибка:
  - Сообщение 245, уровень 16, состояние 1, строка 1
  - Ошибка преобразования при преобразовании значения varchar 'st' в тип данных int.
  ВЫБЕРИТЕ «Сегодня» + GETDATE ();
  -- Ошибка:
  - Сообщение 241, уровень 16, состояние 1, строка 1
  - Ошибка преобразования при преобразовании даты и / или времени из символьной строки. 

В то же время в SQL Server функция CONCAT неявно преобразует числа и значения даты и времени в
строка перед конкатенацией (так же, как Oracle ||).

SQL Server :

 ВЫБРАТЬ СЦЕПИТЬ (1, 'st');
  - Результат: 1-й

  SELECT CONCAT ('Сегодня', GETDATE ());
  - Результат: сегодня 28 мая 2012 г., 18:13 

Oracle 11g R2 Справочник по языку SQL

Microsoft SQL Server 2012 — Электронная документация

SQLines предлагает услуги и инструменты, которые помогут вам перенести базы данных и приложения.Для получения дополнительной информации свяжитесь с нами по адресу [email protected]

Автор Дмитрий Толпеко — май 2012 г.

Объединение значений строк в Transact-SQL

Содержание

Введение

Часто программисты SQL сталкиваются с необходимостью генерировать наборы результатов, подобные отчету, непосредственно из запроса Transact SQL. В большинстве случаев требование возникает из-за того, что нет ни достаточных инструментов, ни собственного опыта для разработки инструментов, которые могут извлекать данные в виде набора результатов, а затем обрабатывать данные в желаемом формате отображения.Довольно часто люди сбиты с толку относительно возможности нарушения основ отношений, таких как первая нормальная форма или скалярная природа типизированных значений. (Говорить о нарушениях 1NF на таком языке, как SQL, который не имеет достаточной поддержки домена, допускает NULL s и поддерживает дубликаты, для начала несколько иронично, но это тема, которая требует подробных объяснений.)

Под «объединением значений строк» ​​мы подразумеваем следующее:
У вас есть таблица, представление или результат, которые выглядят так…
… и вы хотите получить набор результатов, подобный приведенному ниже:

В этом примере мы получаем доступ к образцу базы данных NorthWind и используем следующий SQL

ВЫБЕРИТЕ CategoryId, ProductName

FROM Northwind..Товары

Цель состоит в том, чтобы вернуть набор результатов с двумя столбцами, один с идентификатором категории, а другой с объединенным списком всех имен продуктов, разделенных символом-разделителем: например, запятой.

Объединение значений столбцов или выражений из нескольких строк обычно лучше всего выполнять на языке клиентских приложений, поскольку возможности манипулирования строками в СУБД на основе Transact SQL и SQL несколько ограничены.Однако вы можете сделать это, используя разные подходы в Transact SQL, но лучше избегать таких методов в долгосрочных решениях

Основная проблема

Несмотря на то, что SQL в целом значительно отличается от реляционной модели, его зависимость от определенных основных аспектов реляционных основ делает SQL функциональным и мощным. Одним из таких основных аспектов является природа SQL-выражений, основанная на множествах (точнее, множественные множества, но для данного контекста давайте проигнорируем проблему дублирования).Основная идея заключается в том, что таблицы неупорядочены, и поэтому наборы результатов любого запроса, в котором нет явного предложения ORDER BY , также неупорядочены. Другими словами, строки в наборе результатов запроса не имеют заданной позиции, если она явно не указана в выражении запроса.

С другой стороны, составной список — это упорядоченная структура. Каждый элемент в списке занимает определенную позицию. Фактически, конкатенация сама по себе является операцией по использованию порядка в том смысле, что значения могут иметь префиксы или постфиксации к существующему списку.Таким образом, подходы, которые в общих чертах называются «конкатенацией значений строк», «агрегатной конкатенацией» и т. Д., Должны будут гарантировать, что какой-либо порядок, явный или неявный, должен быть указан до конкатенации значений строк. Если такие критерии упорядочения не указаны, объединенная строка будет произвольной по своему характеру.

Соображения

Как правило, запросы на конкатенацию значений строк часто бывают двух основных видов: когда количество строк известно и мало (обычно меньше 10), и когда количество строк неизвестно и потенциально велико.Возможно, лучше будет рассмотреть каждый из них отдельно.

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

В данной статье таблица Products из базы данных Northwind используется для иллюстрации объединения значений столбца с группирующим столбцом.Northwind — это образец базы данных в установках SQL Server 2000 по умолчанию. Вы можете загрузить копию с сайта Microsoft Downloads

.

Объединение значений, когда количество элементов мало и известно заранее

Когда количество строк невелико и почти известно заранее, легче сгенерировать код. Один из распространенных подходов, когда есть небольшой набор конечных строк, — это метод поворота. Вот пример, в котором извлекаются только первые четыре отсортированных в алфавитном порядке наименования продуктов по categoryid :

SELECT CategoryId,

MAX (CASE seq WHEN 1 THEN ProductName ELSE » END) + ‘,’ +

MAX (CASE seq WHEN 2 THEN ProductName ELSE » END) + ‘,’ +

MAX (CASE seq WHEN 3 THEN ProductName ELSE » END) + ‘,’ +

MAX (CASE seq WHEN 4 THEN ProductName ELSE » END)

FROM (SELECT p1.CategoryId, p1.ProductName,

(ВЫБРАТЬ COUNT (*)

FROM Northwind.dbo.Products p2

ГДЕ p2.CategoryId = p1.CategoryId

И p2.ProductName <= p1.ProductName)

FROM Northwind. dbo.Products p1) D (CategoryId, ProductName, seq)

GROUP BY CategoryId;

Идея здесь состоит в том, чтобы создать выражение внутри коррелированного подзапроса, которое выдает рейтинг ( seq ) на основе названий продуктов, а затем использовать его во внешнем запросе.Используя общие табличные выражения и функцию ROW_NUMBER () , вы можете переписать это как:

; С CTE (CategoryId, ProductName, seq)

AS (SELECT p1.CategoryId, p1.ProductName,

ROW_NUMBER () НАД (РАЗДЕЛЕНИЕ ПО ИДЕНТИФИКАТОРУ КАТЕГИ, ЗАКАЗАТЬ ПО ИМЯ продукта)

ИЗ Northwind.dbo.Products p1)

SELECTId ,

MAX (CASE seq WHEN 1 THEN ProductName ELSE ‘END) +’, ‘+

MAX (CASE seq WHEN 2 THEN ProductName ELSE’ ‘END) +’, ‘+

MAX (CASE seq WHEN 3 THEN ProductName ELSE » END) + ‘,’ +

MAX (CASE seq WHEN 4 THEN ProductName ELSE » END)

FROM CTE

GROUP BY CategoryId;

Обратите внимание, что ROW_NUMBER () — это новая функция, представленная в SQL 2005.Если вы используете любую предыдущую версию, вам придется использовать подход с подзапросом (вы также можете использовать самосоединение, чтобы написать его немного по-другому). Используя недавно представленный оператор PIVOT , вы можете записать это следующим образом:

SELECT CategoryId,

«1» + ‘,’ + «2» + ‘,’ + «3» + ‘,’ + «4» AS Product_List

FROM (SELECT CategoryId, ProductName,

ROW_NUMBER () НАД (РАЗДЕЛЕНИЕ ПО CategoryId

ЗАКАЗАТЬ ПО ProductName)

ОТ Northwind.dbo.Products) P ​​(CategoryId, ProductName, seq)

PIVOT (MAX (ProductName) FOR seq IN («1», «2», «3», «4»)) AS P_;

Синтаксис не только выглядит немного запутанным, но и не предлагает больше функциональных возможностей, чем предыдущий подход CASE . Однако в редких случаях может пригодиться.

Объединение значений, когда количество элементов неизвестно

Если вы заранее не знаете количество элементов, которые должны быть объединены, код может стать более требовательным.Новые возможности SQL 2005 упрощают некоторые подходы. Например, рекурсивные общие табличные выражения (CTE) и синтаксис FOR XML PATH (”) заставляют сервер выполнять тяжелую работу по объединению, оставляя программисту заниматься проблемами представления. Приведенные ниже примеры делают это очевидным.

Рекурсивные методы CTE

Идея этого метода взята из сообщения группы новостей Вадима Тропашко. Это похоже на идеи создания материализованного пути для иерархий.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

WITH CTE (CategoryId, product_list, product_name, length)

AS (SELECT CategoryId, CAST (» AS VARCHAR (8000)), CAST (» AS VARCHAR (8000)), 0

FROM Northwind..Products

GROUP BY CategoryId

UNION ALL

SELECT p.CategoryId, CAST (product_list +

CASE WHEN length = 0 THEN » ELSE ‘,’ END + ProductName AS VARCHAR (8000)),

CAST ( ProductName AS VARCHAR (8000)), длина + 1

ОТ CTE c

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Northwind..Products p

ON c.CategoryId = p.CategoryId

ГДЕ p.ProductName> c.product_name)

SELECT CategoryId, product_list

FROM (SELECT CategoryId, product_list,

RANK () OVER (РАЗДЕЛЕНИЕ ПО ИДЕНТИФИКАТОРУ КАТЕГОРИИ ПОКАЗАТЬ ПО длине DESC)

FROM ) D (CategoryId, product_list, rank)

ГДЕ rank = 1;

CASE в рекурсивной части CTE используется для удаления начальной запятой, но вместо этого вы можете использовать функции RIGHT или SUBSTRING .Возможно, это не самый эффективный вариант, но можно выполнить определенную дополнительную настройку, чтобы сделать их подходящими для наборов данных среднего размера.

Другой подход, использующий рекурсивные общие табличные выражения, был предложен Анубом Филипом, инженером из Sathyam Computers, который использует отдельные общие табличные выражения для якорной и рекурсивной частей.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

WITH Ranked (CategoryId, rnk, ProductName)

AS (SELECT CategoryId,

ROW_NUMBER () OVER (РАЗДЕЛ ПО ИДЕНТИФИКАТОРУ КАТЕГИ, ЗАКАЗАТЬ ПО идентификатору категории),

CAST (ProductName AS VARCHAR (8000))

FROM Northwind..Products),

AnchorRanked (CategoryId, rnk, ProductName)

AS (SELECT CategoryId, rnk, ProductName

FROM Ranked

WHERE rnk = 1),

RecurRanked (CategoryId, rnk, ProductName)

AS (CategoryId, rnk, ProductName) ВЫБЕРИТЕ CategoryId, rnk, ProductName

FROM AnchorRanked

UNION ALL

SELECT Ranked.CategoryId, Ranked.rnk,

RecurRanked.ProductName + ‘,’ + Ranked.ProductName

FROM Ranked

INNER JOIN RecurRanked

ON Ranked.CategoryId = RecurRanked.CategoryId

AND Rankedur.r )

ВЫБРАТЬ CategoryId, MAX (ProductName)

FROM RecurRanked

GROUP BY CategoryId;

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

XML-методы черного ящика

Вот метод конкатенации строк, который использует предложение FOR XML с режимом PATH . Первоначально он был размещен Евгением Коганом, а затем стал обычным явлением в публичных группах новостей.

SELECT p1.CategoryId,

(SELECT ProductName + ‘,’

FROM Northwind.dbo.Products p2

WHERE p2.CategoryId = p1.CategoryId

ORDER BY ProductName

FOR XML PATH (»)) AS Products

FROM Northwind.dbo.Products p1

ГРУППА ПО CategoryId;

Существует аналогичный подход, который изначально был обнаружен в группах новостей бета-тестирования, с использованием оператора CROSS APPLY .

ВЫБРАТЬ ОТЛИЧИТЕЛЬНЫЙ CategoryId, ProductNames

ОТ Northwind.dbo.Products p1

CROSS APPLY (SELECT ProductName + ‘,’

FROM Northwind.dbo.Products p2

WHERE p2.CategoryId = p1.CategoryId

ORDER BY ProductName

FOR XML PATH (»)) D (ProductNames)

Вы можете заметить запятую в конце объединенной строки, которую можно удалить с помощью функции STUFF, SUBSTRING или LEFT .Хотя вышеупомянутые методы многие считают надежными на момент написания, нет никакой гарантии, что так и будет, учитывая, что внутренняя работа и правила оценки выражения FOR XML PATH () в коррелированных подзапросах плохо документированы. .

Проблема с этим подходом заключается в том, что содержимое столбца ProductName интерпретируется как XML, а не как текст, что приведет к тому, что определенные символы будут «уполномочены» или, в некоторых случаях, приведет к ошибке SQL.(см. примечание ниже и решение Адама Мачаника в комментариях ниже), и чтобы избежать этого, лучше использовать слегка измененный синтаксис, подобный этому ..

SELECT p1.CategoryId,

stuff ((SELECT ‘,’ + ProductName

FROM Northwind.dbo.Products p2

WHERE p2.CategoryId = p1.CategoryId

ORDER BY ProductName

FOR XML PATH (» ), ТИП).value (‘.’, ‘varchar (max)’)

, 1,1, »)

AS Products

FROM Northwind.dbo.Products p1

GROUP BY CategoryId;

… а это…

ВЫБРАТЬ DISTINCT CategoryId, ProductNames

FROM Northwind.dbo.Products p1

CROSS APPLY (SELECT

stuff ((SELECT ‘,’ + ProductName

FROM Northwind.dbo.Products p2

ГДЕ p2.CategoryId = p1.CategoryId

ЗАКАЗАТЬ ПО ProductName

ДЛЯ ПУТИ XML (»), TYPE) .value (‘.’, ‘varchar (max)’)

, 1, 1, »)

) D (ProductNames)

Использование общеязыковой среды выполнения

Хотя эта статья посвящена подходам с использованием Transact SQL, этот раздел включен из-за популярности агрегатов CLR в SQL 2005.Это не только дает программисту CLR новые возможности для разработки баз данных, но также, в некоторых случаях, они работают не хуже, чем собственные подходы Transact SQL.

Если вы знакомы с языками .NET, SQL 2005 предлагает удобный способ создания определяемых пользователем агрегатных функций с использованием C #, VB.NET или подобных языков, которые поддерживаются Common Language Runtime (CLR). Вот пример агрегатной функции конкатенации строк, написанной с использованием C #.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

using System;

с использованием System.Коллекции.

с использованием System.Data.SqlTypes;

с использованием System.IO;

с использованием Microsoft.SqlServer.Server;

[Сериализуемый]

[SqlUserDefinedAggregate (Format.UserDefined, MaxByteSize = 8000)]

общедоступная структура strconcat: IBinarySerialize {

значения частного списка;

public void Init () {

this.values ​​= new List ();

}

public void Accumulate (значение SqlString) {

this.values.Add (value.Value);

}

public void Merge (значение strconcat) {

this.values.AddRange (value.values.ToArray ());

}

public SqlString Terminate () {

return new SqlString (string.Join («,», this.values.ToArray ()));

}

public void Read (BinaryReader r) {

int itemCount = r.ReadInt32 ();

this.values ​​= новый список (itemCount);

для (int i = 0; i <= itemCount - 1; i ++) {

this.values.Add (r.ReadString ());

}

}

public void Write (BinaryWriter w) {

w.Write (this.values.Count);

foreach (строка s в this.values) {

w.Write (s);

}

}

}

После сборки и развертывания этой сборки на сервере вы сможете выполнить свой запрос на конкатенацию как:

SELECT CategoryId,

dbo.strconcat (ProductName)

ИЗ продуктов

GROUP BY CategoryId;

Если вы новичок в языках CLR и хотите узнать больше о разработке решений для баз данных с использованием языков CLR, подумайте о том, чтобы начать с Введение в интеграцию Common Language Runtime (CLR).

Скалярная UDF с рекурсией

Рекурсивные функции в t-SQL имеют недостаток, заключающийся в том, что максимальный уровень вложенности равен 32. Таким образом, этот подход применим только для небольших наборов данных, особенно когда количество элементов в группе, которые необходимо объединить, меньше 32.

СОЗДАТЬ ФУНКЦИЮ udf_recursive (@cid INT, @i INT)

ВОЗВРАЩАЕТ VARCHAR (8000) КАК НАЧАЛО

DECLARE @r VARCHAR (8000), @l VARCHAR (8000)

SELECT @i = @i — 1, @r = ProductName + ‘,’

FROM Northwind..Products p1

WHERE CategoryId = @cid

AND @i = (SELECT COUNT (*) FROM Northwind..Products p2

WHERE p2.CategoryId = p1.CategoryId

AND p2.ProductName <= p1.ProductName);

IF @i> 0 НАЧАТЬ

EXEC @l = dbo.udf_recursive @cid, @i;

НАБОР @r = @l + @r;

КОНЕЦ

ВОЗВРАТ @r;

КОНЕЦ

Эту функцию можно вызвать следующим образом:

SELECT CategoryId,

dbo.udf_recursive (CategoryId, COUNT (ProductName))

FROM Northwind..Products

GROUP BY CategoryId;

Таблица значений UDF с циклом WHILE

Этот подход основан на идее Линды Вежбекки, где табличная переменная с тремя столбцами используется в UDF, возвращающем табличное значение. Первый столбец представляет группу, второй представляет текущее обрабатываемое значение в группе, а третий представляет объединенный список значений.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

CREATE FUNCTION udf_tbl_Concat () RETURNS @t TABLE (

CategoryId INT,

Product VARCHAR (40),

list VARCHAR (8000))

BEGIN

INSERT @t (CategoryId, Product, list)

SELECT CategoryId, MIN (ProductName), MIN (ProductName)

FROM Products

GROUP BY CategoryId

WHILE (SELECT COUNT (Product) FROM @t)> 0 BEGIN

UPDATE t

SET list = list + COALESCE (

(SELECT ‘,’ + MIN (ProductName)

FROM Northwind..Products

ГДЕ Products.CategoryId = t.CategoryId

AND Products.ProductName> t.Product), »),

Product = (SELECT MIN (ProductName)

FROM Northwind..Products

WHERE Products. CategoryId = t.CategoryId

AND Products.ProductName> t.Product)

FROM @tt END

RETURN

END

Использование вышеуказанной функции может быть таким:

ВЫБРАТЬ CategoryId, перечислить как продукты

FROM udf_tbl_Concat ();

Динамический SQL

Этот подход представляет собой разновидность кладжа, часто известного под названием «динамическое кросс-табулирование».Существует достаточно литературы, демонстрирующей недостатки и последствия использования динамического SQL. Популярным, по крайней мере, с точки зрения программиста Transact SQL, является книга Эрланда «Проклятие и благословение динамического SQL». Подходы динамического SQL могут быть разработаны на основе создания строки запроса Transact SQL на основе количества групп и последующего использования серии выражений CASE или функции ROW_NUMBER () для поворота данных для конкатенации.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

DECLARE @r VARCHAR (MAX), @n INT, @i INT

SELECT @i = 1,

@r = ‘SELECT CategoryId,’ + CHAR (13),

@n = (SELECT TOP 1 COUNT (ProductName)

FROM Northwind..Продукты

GROUP BY CategoryId

ORDER BY COUNT (ProductName) DESC);

WHILE @i <= @n BEGIN

SET @r = @r +

CASE WHEN @i = 1

THEN ‘MAX (CASE Seq WHEN’ + CAST (@i AS VARCHAR) + ‘

THEN ProductName

ELSE SPACE (0) END) + ‘+ CHAR (13)

WHEN @i = @n

THEN’ MAX (CASE Seq WHEN ‘+ CAST (@i AS VARCHAR) +’

THEN ‘) , » + ProductName

ELSE SPACE (0) END) ‘+ CHAR (13)

ELSE’ MAX (CASE Seq WHEN ‘+ CAST (@i AS VARCHAR) +’

THEN ‘,’ ‘+ ProductName

ЕЩЕ ПРОБЕЛ (0) КОНЕЦ) + ‘+ СИМВОЛ (13)

КОНЕЦ;

НАБОР @i = @i + 1;

КОНЕЦ

SET @r = @r + ‘

FROM (SELECT CategoryId, ProductName,

ROW_NUMBER () OVER (РАЗДЕЛЕНИЕ ПО CategoryId ORDER BY ProductName)

FROM Northwind..Продукты p) D (CategoryId, ProductName, Seq)

GROUP BY CategoryId; ‘

EXEC (@r);

Подход курсора

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

DECLARE @tbl TABLE (id INT PRIMARY KEY, list VARCHAR (8000))

SET NOCOUNT ON

DECLARE @c INT, @p VARCHAR (8000), @cNext INT, @pNext VARCHAR (40)

DECLARE c КУРСОР ДЛЯ

SELECT CategoryId, ProductName

FROM Northwind..Products

ЗАКАЗАТЬ ПО CategoryId, ProductName;

ОТКРЫТЬ c;

ПОИСК СЛЕДУЮЩЕГО ИЗ c В @cNext, @pNext;

НАБОР @c = @cNext;

WHILE @@ FETCH_STATUS = 0 BEGIN

IF @cNext> @c BEGIN

INSERT @tbl SELECT @c, @p;

ВЫБРАТЬ @p = @PNext, @c = @cNext;

END ELSE

SET @p = COALESCE (@p + ‘,’, ПРОБЕЛ (0)) + @pNext;

ПОИСК СЛЕДУЮЩЕГО ИЗ c В @cNext, @pNext

КОНЕЦ

ВСТАВИТЬ @tbl SELECT @c, @p;

ЗАКРЫТЬ c;

DEALLOCATE c;

ВЫБРАТЬ * ИЗ @tbl;

В этом разделе подробно описаны несколько печально известных методов, которые часто публикуются на публичных форумах.Проблема с этими методами в том, что они полагаются на физическую модель реализации; изменения в индексах, статистике и т. д. или даже изменение простого выражения в списке SELECT или предложении ORDER BY могут изменить вывод. Кроме того, они недокументированы, не поддерживаются и ненадежны до такой степени, что можно постоянно демонстрировать сбои. Поэтому эти методы вообще не рекомендуются для систем производственного режима.

Скалярная UDF с расширением обновления t-SQL

Использование выражения, которое включает столбец, переменную и выражение в предложении SET в операторе UPDATE, редко бывает интуитивно понятным.Однако в целом кажется, что оптимизатор обрабатывает эти значения в порядке материализации либо во внутренних рабочих таблицах, либо в любых других структурах хранения.

СОЗДАТЬ ФУНКЦИЮ udf_update_concat (@CategoryId INT)

ВОЗВРАЩАЕТ VARCHAR (МАКС.) КАК

НАЧАТЬ

DECLARE @t TABLE (p VARCHAR (40));

DECLARE @r VARCHAR (MAX);

НАБОР @r = ПРОБЕЛ (0);

INSERT @t (p) SELECT ProductName FROM Northwind..Products

ГДЕ CategoryId = @CategoryId;

ЕСЛИ @@ ROWCOUNT> 0

ОБНОВЛЕНИЕ @t

НАБОР @r = @r + p + ‘,’;

ВОЗВРАТ (@r)

КОНЕЦ

Вот как использовать эту функцию:

ВЫБЕРИТЕ CategoryId, dbo.udf_update_concat (CategoryId)

ОТ Northwind..Продукты

ГРУППА ПО CategoryId;

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

Скалярная UDF с конкатенацией переменных в SELECT

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

СОЗДАТЬ ФУНКЦИЮ dbo.udf_select_concat (@c INT)

ВОЗВРАЩАЕТ VARCHAR (МАКС.) В НАЧАЛЕ

DECLARE @p VARCHAR (MAX);

НАБОР @p = »;

ВЫБРАТЬ @p = @p + ProductName + ‘,’

FROM Northwind..Products

WHERE CategoryId = @c;

ВОЗВРАТ @p

КОНЕЦ

А, что касается его использования:

ВЫБРАТЬ CategoryId, dbo.udf_select_concat (CategoryId)

FROM Northwind..Products

GROUP BY CategoryId;

Заключение

Независимо от того, как оно используется, «агрегированная конкатенация» значений строк в Transact SQL, особенно при группировке, не является простой процедурой. Вам необходимо тщательно обдумать обстоятельства, прежде чем выбирать один метод вместо другого. Наиболее логичным вариантом было бы наличие встроенного оператора с необязательными настраиваемыми параметрами, который может объединять значения в зависимости от типа.До тех пор, требования к отчетности и процедуры экспорта внешних данных должны будут полагаться на такие приемы программирования Transact SQL.

Список литературы

Благодарности

Умачандар Джаячандран, Линда Вежбекки, Брюс Марголин, Рой Харви, Юджин Коган, Вадим Тропашко, Ануб Филип.

Дополнительная информация о подходе XML Blackbox добавлена ​​22 марта 2012 г.

Конкатенация строк SQL Server | Рам Кедем

В этом руководстве по SQL основное внимание уделяется объединению строк в SQL Server , а также приведены объяснения, примеры и упражнения.Для упражнений этого урока используйте эту ссылку.

Это руководство является частью нескольких сообщений, в которых объясняется, как писать базовые запросы в SQL Server. Чтобы прочитать дополнительные сообщения по этой теме, воспользуйтесь следующими ссылками:


Базовая конкатенация строк в SQL Server

Объединение строк в SQL Server позволяет добавлять одну строку в конец другой строки. Чтобы отобразить содержимое двух или более столбцов под именем одного столбца, вы можете использовать оператор конкатенации (+).
Например, чтобы отобразить имя сотрудника вместе с его или ее фамилией, используйте следующий оператор SQL Server:

ВЫБЕРИТЕ first_name + last_name
ОТ сотрудников
 

Результат:

(Без названия столбца)
------------------------
Джон Смит
 

SQL Server — объединение двух полей с пробелом

Хотя в предыдущем примере запрошенный результат — слияние двух значений из двух разных столбцов — был достигнут, конечный результат по-прежнему нечитаем, поскольку у нас нет разделителя пробелов между именем и фамилией.Поэтому рекомендуется также объединить пробел (‘‘):

ВЫБЕРИТЕ first_name + '' + last_name
ОТ сотрудников
 

Результат:

(Без названия столбца)
-----------------------------
Джон Смит
 

Использование псевдонима столбца SQL Server

Чтобы сделать результат более читабельным, используйте псевдоним столбца SQL Server:

ВЫБЕРИТЕ first_name + '' + last_name как 'FullName'
ОТ сотрудников
 

Результат:

Полное имя
--------------
Джон Смит
 

SQL Server — получение дополнительных столбцов

В SQL Server, если после или до этой конкатенации вы хотите отобразить дополнительный отдельный столбец, просто используйте запятую (,):

ВЫБЕРИТЕ город, first_name + '' + last_name AS 'FullName', зарплата
ОТ сотрудников
 

Результат:

город FullName зарплата
------ ---------- -------------
Лондон Джон Смит 5800
 

SQL Server — объединить более двух значений

В SQL Server при необходимости можно создавать более сложные конкатенации:

ВЫБЕРИТЕ 'Имя сотрудника:' + first_name + '-'
+ last_name AS 'E_DETAILS',
ОТ сотрудников
 

Результат:

E_Details
-----------------------------
Имя сотрудника: Джон-Смит
 

.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *