powered by simpleCommunicator - 2.0.56     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / CLR Concatenate
19 сообщений из 19, страница 1 из 1
CLR Concatenate
    #38373583
Двоичник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
здравствуйте алл
помогите, пожалуйста. я совершенно не знаю язык C#
но есть задачка из одной функции сделать более расширенную.
помогите, пожалуйста.

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

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

соответственно код существующей функции прилагается
using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.IO;
using Microsoft.SqlServer.Server;

[Serializable]
[SqlUserDefinedAggregate(Format.UserDefined, MaxByteSize = 8000)]
public struct fn_Concatenate : IBinarySerialize
{
private List<string> values;

public void Init()
{
this.values = new List<string>();
}

public void Accumulate(SqlString value)
{
this.values.Add(value.Value);
}

public void Merge(fn_Concatenate value)
{
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 = new List<string>(itemCount);
for (int i = 0; i <= itemCount - 1; i++)
{
this.values.Add(r.ReadString());
}
}

public void Write(BinaryWriter w)
{
w.Write(this.values.Count);
foreach (string s in this.values)
{
w.Write(s);
}
}
}


спасибо!!!
...
Рейтинг: 0 / 0
CLR Concatenate
    #38373595
Фотография skyANA
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
CLR Concatenate
    #38373599
Двоичник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
skyANA String.Join Method
я дико извиняюсь. но мне бы код, чтобы я мог его скомпилировать.
на этом мои знания и заканчиваются.
еще раз извините
...
Рейтинг: 0 / 0
CLR Concatenate
    #38374112
Двоичник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
please, up!
...
Рейтинг: 0 / 0
CLR Concatenate
    #38374146
Двоичник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
в идеале бы еще и управление сортировкой и группировкой данных на выходе. чтобы в перечисляемой строке одинаковые данные не попадались. но это уже верх моей наглости.
...
Рейтинг: 0 / 0
CLR Concatenate
    #38374157
Pallaris
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Двоичникв идеале бы еще и управление сортировкой и группировкой данных на выходе. чтобы в перечисляемой строке одинаковые данные не попадались. но это уже верх моей наглости.

Думаю, все-таки тебе придется открыть книжку по c#
...
Рейтинг: 0 / 0
CLR Concatenate
    #38376858
SHKoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
либо никто не умеет, либо жлобы собрались на форуме.
жалко помочь человеку?

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

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text;

[Serializable]
[SqlUserDefinedAggregate(
Format.UserDefined,
IsInvariantToOrder = false,
IsInvariantToNulls = true,
IsInvariantToDuplicates = false,
MaxByteSize = -1
)]
public struct Concatenate : IBinarySerialize
{
private StringBuilder _accumulator;
private string _delimiter;

public Boolean IsNull;

public void Init()
{
_accumulator = new StringBuilder();
_delimiter = string.Empty;
}

public void Accumulate(SqlChars item, SqlString delimiter)
{
// if we have an actual delimiter
if ((!delimiter.IsNull) && (delimiter.Value.Length > 0))
{
_delimiter = delimiter.Value;
// accumulate delimiter if we have something already
if (_accumulator.Length > 0)
_accumulator.Append(delimiter.Value);
}

// if value is null, just add delimiter (above) and return
if (item.IsNull)
return;
else
{
_accumulator.Append(item.Value);
this.IsNull = false;
}

}

public void Merge(Concatenate Group)
{

if (_accumulator.Length > 0 && Group._accumulator.Length > 0)
_accumulator.Append(_delimiter);

_accumulator.Append(Group._accumulator.ToString());

}

public SqlChars Terminate()
{

return new SqlChars(_accumulator.ToString());

}

void IBinarySerialize.Read(System.IO.BinaryReader r)
{

_delimiter = r.ReadString();
_accumulator = new StringBuilder(r.ReadString());

if (_accumulator.Length != 0)
this.IsNull = false;

}

void IBinarySerialize.Write(System.IO.BinaryWriter w)
{

w.Write(_delimiter);
w.Write(_accumulator.ToString());

}

}
...
Рейтинг: 0 / 0
CLR Concatenate
    #38376900
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В MSSQL конкатенация строк обычно делается запросом:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
use AdventureWorks2012
go
select (
  select distinct ', '+FirstName
  from Person.Person
  order by 1
  for xml path(''), type
).value('.', 'varchar(255)')
...
Рейтинг: 0 / 0
CLR Concatenate
    #38377467
Двоичник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны,

это конечно спасибо, но вопрос был именно в CLR
...
Рейтинг: 0 / 0
CLR Concatenate
    #38377510
Фотография МСУ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры ПавловныВ MSSQL конкатенация строк обычно делается запросом:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
use AdventureWorks2012
go
select (
  select distinct ', '+FirstName
  from Person.Person
  order by 1
  for xml path(''), type
).value('.', 'varchar(255)')



Я извиняюсь, но чем эта жесть через xml лучше классики?

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
declare @text nvarchar(max)
set @text = ''

select @text = @text + FirstName from (
  select distinct ', ' + FirstName as FirstName
  from Person.Person
) as t
order by FirstName

select @text
...
Рейтинг: 0 / 0
CLR Concatenate
    #38377661
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
МСУЯ извиняюсь, но чем эта жесть через xml лучше классики?
Тем, что эта классика, по сути - скалярка, и если надо будет сделать конкатенацию попутно с извлечением/агрегацией/etc. прочих данных, то ввиду того, что скалярка не будет заинлайнена в запрос, производительность заметно просядет. Если нужно просто сджойнить энную выборку в ХП - да, так нагляднее, во всех прочих случаях она проиграет в производительности - даже если эту скалярку объявить как schema-bound.
...
Рейтинг: 0 / 0
CLR Concatenate
    #38377682
Фотография МСУ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны, не понял по поводу производительности... Что мешает сразу сформировать нужный рекордсет (фильтры и группировка) на SQL, а потом тупо собрать через накопительную переменную?
...
Рейтинг: 0 / 0
CLR Concatenate
    #38377726
Двоичник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
модераторы, перенесите ветку в MS SQL, пожалуйста. спасибо

я создал на основе предложенного варианта функцию
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
create function dbo.fn_GetAgent (@c_id numeric(10), @p_id numeric(10))
returns varchar(4000)
as
BEGIN
declare @result varchar(4000)

set @result = (select (
                      select distinct dbo.fn_GetPerson(p.agent_id) + '; '
                      from table p
                    where p.c_id = @c_id	
                    and p.p_id = @p_id  
                    group by p.agent_id
                      order by 1
                      for xml path(''), type
                    ).value('.', 'varchar(4000)'))
      

return @result 
END
go


и теперь при
Код: sql
1.
select dbo.fn_GetAgent (4444, 5555)


я получаю
SELECT failed because the following SET options have incorrect settings: 'ANSI_NULLS, QUOTED_IDENTIFIER'. Verify that SET options are correct for use with indexed views and/or indexes on computed columns and/or filtered indexes and/or query notifications and/or XML data type methods and/or spatial index operations.

соответственно
SET ANSI_WARNINGS OFF
go
SET ANSI_PADDING OFF
go
SET ANSI_NULLS OFF
go
SET QUOTED_IDENTIFIER OFF
go
даже ON ключ не помогает.
что теперь нужно? чтобы заработало...
...
Рейтинг: 0 / 0
CLR Concatenate
    #38377755
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
МСУСон Веры Павловны, не понял по поводу производительности... Что мешает сразу сформировать нужный рекордсет (фильтры и группировка) на SQL, а потом тупо собрать через накопительную переменную?
Ну вот простейший пример - вывести все таблицы базы с именами колонок в строчку для каждой таблицы:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
use AdventureWorks2012
go
select
  o.name, stuff(f.x.value('.','varchar(max)'),1,2,'') columns
from sys.objects o
cross apply (
  select ', '+c.name
  from sys.columns c
  where c.object_id=o.object_id
  order by c.column_id
  for xml path(''), type
) f(x)
where o.type='U'


Каким боком тут приткнуть накопительную переменную, кроме как использовать её внутри скалярной функции?
...
Рейтинг: 0 / 0
CLR Concatenate
    #38377928
Фотография МСУ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны, подожди, ты писал про извлечение, агрегацию. Ну так извлекай и агрегируй. А потом конкатенируй и через разделитель накапливай в переменную, автору же нужно управлять этим разделителем.
...
Рейтинг: 0 / 0
CLR Concatenate
    #38378237
Фотография МСУ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны, третий способ : http://codearticles.ru/articles/1861
...
Рейтинг: 0 / 0
CLR Concatenate
    #38378877
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
МСУ,

Это самый неприемлемый способ - оверхед в виде объема перелопачиваемых данных (и, соответственно, нагрузка на сервер) растет по арифметической прогрессии в зависимости от числа записей в конкатенируемой выборке.

Ради интереса провел тест. У нас в рабочей базе в sys.all_objects ~390 тыс. записей. Время отработки с накоплением в локальную переменную - 183 с. Время отработки через for xml path - 4 c. Отработки варианта с CTE я не дождался - прождал 5 минут, и решил не насиловать сервер. Почему первый способ (через переменную) настолько медленнее второго способа (через for xml) - не знаю, надо спросить в соответствующем разделе. Вроде план запроса с накоплением в переменную в разы проще плана с for xml, но факт проигрыша налицо.

P.S. Проверялось на
Код: sql
1.
select @@VERSION


Код: plaintext
1.
2.
3.
4.
5.
-----------------------------------------------------------------------------------
Microsoft SQL Server 2008 (SP3) - 10.0.5500.0 (X64) 
	Sep 21 2011 22:45:45 
	Copyright (c) 1988-2008 Microsoft Corporation
	Enterprise Edition (64-bit) on Windows NT 6.0 <X64> (Build 6002: Service Pack 2)
...
Рейтинг: 0 / 0
CLR Concatenate
    #38378916
Фотография МСУ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны, для больших объемов for xml всех рвёт, не спорю. Я ратую за то, что для разных ситуаций могут применяться различные подходы. Накапливание в переменную много раз использовал, полет отличный.
Надеюсь, согласишься, что задачи, в которых нужно на миллионных выборках в строчку через разделитель накрутить значения детализации - это дырка в башке архитектора подобного решения, а не в CTE.
...
Рейтинг: 0 / 0
CLR Concatenate
    #38666078
Фотография MaratSH
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры ПавловныВ MSSQL конкатенация строк обычно делается запросом:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
use AdventureWorks2012
go
select (
  select distinct ', '+FirstName
  from Person.Person
  order by 1
  for xml path(''), type
).value('.', 'varchar(255)')



Шикарный вариант! Не знал, что так можно!
Простестировал на больших объемах в сравнении с хорошо оптимизированной CLR агрегатом.
Стояла задача конкатенации, поддерживающей сортировку, допускающей дупликаты ключей и значений, и превращающей null'ьные значения в пустые строки.
Вариант с for xml бьет все рекорды. Причем, на лету коде можно использовать тонны вариаций, а вот чтобы вводить какие-то вариации в CLR реализацию, приходится пыхтеть, потеть и пузыриться.

Огромное спасибо за пример!
...
Рейтинг: 0 / 0
19 сообщений из 19, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / CLR Concatenate
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]