Как создать функцию SQL Server для “присоединений” к нескольким строкам от подзапроса в единственное разграниченное поле? [дубликат]

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

См. также: A хороший список лучших практик

Я бы добавил, очень важно, хорошо использовать модификатор final. Использование "окончательной" модификатор, когда это применимо в Java

Сводка:

  1. Используйте модификатор final для обеспечения хорошей инициализации.
  2. Избегайте возврата null в методы, например, при возврате пустых коллекций.
  3. Использовать аннотации @NotNull и @Nullable
  4. Быстрое завершение работы и использование утверждений, чтобы избежать распространения нулевых объектов через все приложение, когда они не должен быть пустым.
  5. Сначала используйте значения с известным объектом: if("knownObject".equals(unknownObject)
  6. Предпочитают valueOf() поверх toString ().
  7. Используйте null safe StringUtils StringUtils.isEmpty(null).

193
задан DineshDB 2 April 2018 в 01:34
поделиться

7 ответов

При использовании SQL Server 2005 Вы могли бы использовать команду FOR XML PATH.

SELECT [VehicleID]
     , [Name]
     , (STUFF((SELECT CAST(', ' + [City] AS VARCHAR(MAX)) 
         FROM [Location] 
         WHERE (VehicleID = Vehicle.VehicleID) 
         FOR XML PATH ('')), 1, 2, '')) AS Locations
FROM [Vehicle]

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

253
ответ дан Art 23 November 2019 в 05:26
поделиться

Обратите внимание, что код Matt приведет к дополнительной запятой в конце строки; использование ОБЪЕДИНЯЕТ (или ISNULL в этом отношении) как показано в ссылке в сообщении Lance использует похожий метод, но не оставляет Вас с дополнительной запятой для удаления. Ради полноты вот соответствующие нормы из ссылки Lance на sqlteam.com:

DECLARE @EmployeeList varchar(100)
SELECT @EmployeeList = COALESCE(@EmployeeList + ', ', '') + 
    CAST(EmpUniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1
86
ответ дан Community 23 November 2019 в 05:26
поделиться

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

declare @s varchar(max)
set @s = ''
select @s = @s + City + ',' from Locations

select @s

Это - определенно меньше кода, чем обход по курсору, и вероятно более эффективный.

45
ответ дан Matt Hamilton 23 November 2019 в 05:26
поделиться

При выполнении SQL Server 2005 можно записать пользовательская агрегатная функция CLR для обработки этого.

версия C#:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Text;
using Microsoft.SqlServer.Server;
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.UserDefined,MaxByteSize=8000)]
public class CSV:IBinarySerialize
{
    private StringBuilder Result;
    public void Init() {
        this.Result = new StringBuilder();
    }

    public void Accumulate(SqlString Value) {
        if (Value.IsNull) return;
        this.Result.Append(Value.Value).Append(",");
    }
    public void Merge(CSV Group) {
        this.Result.Append(Group.Result);
    }
    public SqlString Terminate() {
        return new SqlString(this.Result.ToString());
    }
    public void Read(System.IO.BinaryReader r) {
        this.Result = new StringBuilder(r.ReadString());
    }
    public void Write(System.IO.BinaryWriter w) {
        w.Write(this.Result.ToString());
    }
}
1
ответ дан Ian Kemp 23 November 2019 в 05:26
поделиться

Приведенный ниже код будет работать для Sql Server 2000/2005/2008

CREATE FUNCTION fnConcatVehicleCities(@VehicleId SMALLINT)
RETURNS VARCHAR(1000) AS
BEGIN
  DECLARE @csvCities VARCHAR(1000)
  SELECT @csvCities = COALESCE(@csvCities + ', ', '') + COALESCE(City,'')
  FROM Vehicles 
  WHERE VehicleId = @VehicleId 
  return @csvCities
END

-- //Once the User defined function is created then run the below sql

SELECT VehicleID
     , dbo.fnConcatVehicleCities(VehicleId) AS Locations
FROM Vehicles
GROUP BY VehicleID
13
ответ дан 23 November 2019 в 05:26
поделиться

ПРИМЕЧАНИЕ ВЕРСИИ. Для этого решения необходимо использовать SQL Server 2005 или выше с уровнем совместимости 90 или выше.

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

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

Ссылаясь на версию C # примера 1:

change:  this.intermediateResult.Append(value.Value).Append(',');
    to:  this.intermediateResult.Append(value.Value);

и

change:  output = this.intermediateResult.ToString(0, this.intermediateResult.Length - 1);
    to:  output = this.intermediateResult.ToString();

Таким образом, когда вы используете свой собственный агрегат, вы можете выбрать использование собственного разделителя или его отсутствие вообще, например:

SELECT dbo.CONCATENATE(column1 + '|') from table1

ПРИМЕЧАНИЕ: Будьте осторожны с объемом данных, которые вы пытаетесь обработать в своей совокупности. Если вы попытаетесь объединить тысячи строк или множество очень больших типов данных, вы можете получить ошибку .NET Framework, в которой говорится: «[t] буфер недостаточен».

3
ответ дан 23 November 2019 в 05:26
поделиться

Из того, что я вижу, FOR XML (как было сказано ранее) - единственный способ сделать это, если вы хотите также выбрать другие столбцы (что, я полагаю, делает большинство), как это делает ОП. Using COALESCE(@var... не позволяет включить другие столбцы.

Обновление: Благодаря programmingsolutions.net появился способ убрать "прицепную" запятую to. Превратив ее в ведущую запятую и используя функцию STUFF в MSSQL, вы можете заменить первый символ (ведущую запятую) пустой строкой, как показано ниже:

stuff(
    (select ',' + Column 
     from Table
         inner where inner.Id = outer.Id 
     for xml path('')
), 1,1,'') as Values
23
ответ дан 23 November 2019 в 05:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: