Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 DISTINCT по полю (данные с разделителем)  [new]
astranexus
Member

Откуда:
Сообщений: 22
AUS|
AUS|EUR|GEN|CIS|
CAN|
CAN|USA|
CIS|
EUR|
EUR|CIS|
EUR|GEN|
EUR|GEN|CIS|
GEN|
GEN|MES|
GEN|MES|CIS|
MES|
MES|GEN|
PUT|USA|
USA|


В строках в столбце region содержатся вот такие записи.
Как сделать правильно DISTINCT запрос чтобы отобрать не повторяющиеся записи , например чтобы получить
AUS
EUR
GEN
CAN ну и тд
15 янв 14, 16:48    [15420040]     Ответить | Цитировать Сообщить модератору
 Re: DISTINCT по полю (данные с разделителем)  [new]
prog882
Guest
astranexus,

declare @t table (region varchar(max))
insert into @t
select 'AUS|' union all
select 'AUS|EUR|GEN|CIS|' union all
select 'CAN|' union all
select 'CAN|USA|' union all
select 'CIS|' union all
select 'EUR|' union all
select 'EUR|CIS|' union all
select 'EUR|GEN|' union all
select 'EUR|GEN|CIS|' union all
select 'GEN|' union all
select 'GEN|MES|' union all
select 'GEN|MES|CIS|' union all
select 'MES|' union all
select 'MES|GEN|' union all
select 'PUT|USA|' union all
select 'USA|'
select distinct substring(region,1, charindex('|',region)-1)
from @t
15 янв 14, 16:58    [15420142]     Ответить | Цитировать Сообщить модератору
 Re: DISTINCT по полю (данные с разделителем)  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31948
prog882,

Не, ну ему нужно собрать все перечисленные регионы из строк :-)

astranexus,

Поищите по форуме "строку в записи", вам нужно преобразовать данные из строк в нормальный вид (в таблицу), и оттуда уже сделать SELECT DISTINCT
15 янв 14, 17:00    [15420160]     Ответить | Цитировать Сообщить модератору
 Re: DISTINCT по полю (данные с разделителем)  [new]
Alexander Us
Member

Откуда:
Сообщений: 1161
astranexus,

CREATE FUNCTION [dbo].[fn_Split] 
(
	@String varchar(8000), 
        @Spliter varchar(300)  
)
RETURNS @T table(PosNr int identity(1,1), SubStr varchar(8000))
AS
BEGIN 

if @String is null return
if @Spliter is null
  set @Spliter=''

declare @SubStr varchar(8000)
declare @StrLen int, @FPos int, @LPos int, @SplPos int, @SplLen int 

if substring(@String,len(@String),1)<>@Spliter
begin
  select @String=@String+@Spliter
end

select  @FPos=0, @LPos=0, @SplLen=len(@Spliter), @LPos=0, @StrLen=Len(@String)

select @FPos=1
select @LPos= case when @SplLen>0 then charindex(@Spliter,@String,1) else @FPos+1 end

while @FPos<=@StrLen
begin
  insert @T
  select substring(@String,@FPos,@LPos-@FPos)

  select @FPos=@LPos+@SplLen
  select @LPos=case when @SplLen>0 then  charindex(@Spliter,@String,@FPos) else @FPos+1 end
end

return
END


declare @t table (region varchar(max))
insert into @t
select 'AUS|' union all
select 'AUS|EUR|GEN|CIS|' union all
select 'CAN|' union all
select 'CAN|USA|' union all
select 'CIS|' union all
select 'EUR|' union all
select 'EUR|CIS|' union all
select 'EUR|GEN|' union all
select 'EUR|GEN|CIS|' union all
select 'GEN|' union all
select 'GEN|MES|' union all
select 'GEN|MES|CIS|' union all
select 'MES|' union all
select 'MES|GEN|' union all
select 'PUT|USA|' union all
select 'USA|'


select distinct F.SubStr from @T cross apply tools..fn_split__OLD(region,'|')F
15 янв 14, 17:16    [15420289]     Ответить | Цитировать Сообщить модератору
 Re: DISTINCT по полю (данные с разделителем)  [new]
Alexander Us
Member

Откуда:
Сообщений: 1161
поравка:
select distinct F.SubStr from @T cross apply fn_split(region,'|')F
15 янв 14, 17:17    [15420295]     Ответить | Цитировать Сообщить модератору
 Re: DISTINCT по полю (данные с разделителем)  [new]
astranexus
Member

Откуда:
Сообщений: 22
Alexander Us, спасибо большое!!
15 янв 14, 18:01    [15420555]     Ответить | Цитировать Сообщить модератору
 Re: DISTINCT по полю (данные с разделителем)  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
Alexander Us
astranexus,

CREATE FUNCTION [dbo].[fn_Split] 
(
	@String varchar(8000), 
        @Spliter varchar(300)  
)
RETURNS @T table(PosNr int identity(1,1), SubStr varchar(8000))
AS
BEGIN 

if @String is null return
if @Spliter is null
  set @Spliter=''

declare @SubStr varchar(8000)
declare @StrLen int, @FPos int, @LPos int, @SplPos int, @SplLen int 

if substring(@String,len(@String),1)<>@Spliter
begin
  select @String=@String+@Spliter
end

select  @FPos=0, @LPos=0, @SplLen=len(@Spliter), @LPos=0, @StrLen=Len(@String)

select @FPos=1
select @LPos= case when @SplLen>0 then charindex(@Spliter,@String,1) else @FPos+1 end

while @FPos<=@StrLen
begin
  insert @T
  select substring(@String,@FPos,@LPos-@FPos)

  select @FPos=@LPos+@SplLen
  select @LPos=case when @SplLen>0 then  charindex(@Spliter,@String,@FPos) else @FPos+1 end
end

return
END
Лучше так не делать
15 янв 14, 20:44    [15421416]     Ответить | Цитировать Сообщить модератору
 Re: DISTINCT по полю (данные с разделителем)  [new]
Alexander Us
Member

Откуда:
Сообщений: 1161
iap,

Не быстро конечно но для небольших данных работает.
Себе я переделал эту функцию на CLR.

Каковы Ваши рекомендации?
15 янв 14, 22:51    [15421905]     Ответить | Цитировать Сообщить модератору
 Re: DISTINCT по полю (данные с разделителем)  [new]
invm
Member

Откуда: Москва
Сообщений: 9824
Alexander Us
Себе я переделал эту функцию на CLR.
Если уж CLR, то лучше сделать обертку над Regex.Split. И гибче и быстрее - 15097121
15 янв 14, 23:51    [15422125]     Ответить | Цитировать Сообщить модератору
 Re: DISTINCT по полю (данные с разделителем)  [new]
prog882
Guest
astranexus, извините, не правильно понял. Вот:

declare @t table (region varchar(max))
insert into @t
select 'AUS|' union all
select 'AUS|EUR|GEN|CIS|' union all
select 'CAN|' union all
select 'CAN|USA|' union all
select 'CIS|' union all
select 'EUR|' union all
select 'EUR|CIS|' union all
select 'EUR|GEN|' union all
select 'EUR|GEN|CIS|' union all
select 'GEN|' union all
select 'GEN|MES|' union all
select 'GEN|MES|CIS|' union all
select 'MES|' union all
select 'MES|GEN|' union all
select 'PUT|USA|' union all
select 'USA|'
;with t_cte as (
select region, lvl=1, RecCur = region, RecNew = region from @t
union all
select region, lvl=lvl+1, RecCur = right (RecCur, len(RecCur) - charindex('|', RecCur)),
RecNew = left (RecCur, charindex('|', RecCur)) from t_Cte where charindex('|', RecCur) > 0
)
select distinct region = replace(RecNew,'|','') from t_cte where lvl != 1
16 янв 14, 08:24    [15422678]     Ответить | Цитировать Сообщить модератору
 Re: DISTINCT по полю (данные с разделителем)  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
Alexander Us
iap,

Не быстро конечно но для небольших данных работает.
Себе я переделал эту функцию на CLR.

Каковы Ваши рекомендации?
Как минимум, не использовать для этого скалярную UDF, да ещё и с циклами внутри.
Я не истина в последней инстанции, могу только дать ссылки на обсуждения этого вопроса.
https://www.sql.ru/forum/847500/funkciya-kotoraya-delit-stroku-na-slova
Я там функцию выкладывал с инлайн табличной функцией:
https://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=847500&msg=10589208
И aleks2 тоже: https://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=847500&msg=10586095
16 янв 14, 09:29    [15422873]     Ответить | Цитировать Сообщить модератору
 Re: DISTINCT по полю (данные с разделителем)  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
Оптимально вообще не использовать функции
16 янв 14, 09:29    [15422877]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить