Гость
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сложная, но интересная задача / 24 сообщений из 24, страница 1 из 1
18.12.2013, 23:33
    #38505934
=Сергей=
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
Есть таблица с диапазонами телефонных номеров, а в АТС используются префиксы телефонных номеров. Как преобразовать?
Код: sql
1.
2.
3.
4.
5.
6.
create table Ranges(
    [id] int identity(1,1) not null
   ,[beg] varchar(32) //начало диапазона
   ,[end] varchar(32) //конец диапазона
   ,[name] nvarchar(100) //имя диапазона
)


Например, диапазон 391500-392080 должен быть преобразован в список из 14 префиксов:
3915
3916
3917
3918
3919
39290
39291
39292
39293
39294
39295
39296
39297
39298
...
Рейтинг: 0 / 0
18.12.2013, 23:57
    #38505941
o-o
o-o
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
кто-то что-то понял?
почему есть 3915 и нет 391500?
почему 14?
чем не угодил 3920?
...
Рейтинг: 0 / 0
19.12.2013, 00:09
    #38505944
=Сергей=
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
o-o,
Мы ведь рассуждаем о ПРЕФИКСАХ, а для номера 391500 из указанного диапазона будет достаточным префикс 3915
...
Рейтинг: 0 / 0
19.12.2013, 00:19
    #38505947
Gwa
Gwa
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
=Сергей=,

NB! 3929 в указанный диапазон не попадают !
...
Рейтинг: 0 / 0
19.12.2013, 00:20
    #38505948
sdet
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
=Сергей=o-o,
Мы ведь рассуждаем о ПРЕФИКСАХ, а для номера 391500 из указанного диапазона будет достаточным префикс 3915
То есть вы предлагаете нам самим разбираться в правилах образования ваших префиксов?
...
Рейтинг: 0 / 0
19.12.2013, 00:38
    #38505956
=Сергей=
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
Простите за неудачный и неверный пример.
Следующий будет лучше: 123456000-123789999 соответствует списку таких префиксов:
123456
123457
123458
123459
12346
12347
12348
12349
1235
1236
12370
12371
12372
12373
12374
12375
12376
12377
12378
...
Рейтинг: 0 / 0
19.12.2013, 01:18
    #38505981
qwerty112
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
=Сергей=Следующий будет лучше:

даа, такое же г. как и первый раз
к концу 4-го года на форуме, уже мог бы и ознакомиться ... - Рекомендации по оформлению сообщений в форуме
=Сергей= 123456000-123789999 соответствует списку таких префиксов:
123456
123457
123458
123459
12346
12347
12348
12349
1235
1236
12370
12371
12372
12373
12374
12375
12376
12377
12378

эти префиксы - где-то храняться ?
по какому правилу, нужно "родить", что 1235 - 4х значный префикс,
а 1234х - пятизначный ??
...
Рейтинг: 0 / 0
19.12.2013, 01:37
    #38505989
=Сергей=
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
qwerty112даа, такое же г. как и первый раз
к концу 4-го года на форуме, уже мог бы и ознакомиться ... - Рекомендации по оформлению сообщений в форуме
Ткните пальцем в нарушенный мною пункт указанных Правил.
qwerty112эти префиксы - где-то храняться ?
нет, напротив, задача - составить их список.
qwerty112по какому правилу, нужно "родить", что 1235 - 4х значный префикс,
а 1234х - пятизначный ??
по тому правилу, что какие бы цифры вы не набрали (при соблюдении длины номера, разумеется) после любого из указанных префиксов 1235, набранный номер будет лежать внутри указанного диапазона.
Может так список префиксов для диапазона 123456000-123789999 станет понятнее:
12345[6-9]
1234[6-9]
123[5-6]
1237[0-8]
?
...
Рейтинг: 0 / 0
19.12.2013, 02:12
    #38505994
sdet
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
=Сергей=,

Ознакомьтесь с п. 6 правил и обратите внимание на описание желаемого результата на примере тестовых данных.
Представьте описание и тестовые данные для разных диапазонов.
...
Рейтинг: 0 / 0
19.12.2013, 04:32
    #38506029
Ruuu
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
=Сергей=Ткните пальцем в нарушенный мною пункт указанных Правил.Пункты 3,4, и самое главное 6.
=Сергей=в АТС используются префиксы телефонных номеровС АТС и возьмите. Или придумайте логику "получения префиксов" и опишите её на русском языке, потом перечитайте и, если поймете сами, тогда может быть поймут и другие.
...
Рейтинг: 0 / 0
19.12.2013, 05:45
    #38506046
Сложная, но интересная задача
=Сергей=o-o,
Мы ведь рассуждаем о ПРЕФИКСАХ, а для номера 391500 из указанного диапазона будет достаточным префикс 3915
если так рассуждать, то и префикса 391 будет достаточно. как, в прочем, и префикса 39, или даже 3.

Не можешь формализовать, то хотя бы на словах расскажи алгоритм однозначного определения префикса.
...
Рейтинг: 0 / 0
19.12.2013, 06:17
    #38506053
Сложная, но интересная задача
Добрый Э - Эх=Сергей=o-o,
Мы ведь рассуждаем о ПРЕФИКСАХ, а для номера 391500 из указанного диапазона будет достаточным префикс 3915
если так рассуждать, то и префикса 391 будет достаточно. как, в прочем, и префикса 39, или даже 3.

Не можешь формализовать, то хотя бы на словах расскажи алгоритм однозначного определения префикса.О-о-о, прочитал ещё раз постановку задачи. Смысл желаемого стал ясен. :)
В общих чертах решение сводится к тому, что нужно выделить полные [десятки | сотни | тысячи] номеров в заданном диапазоне. Причем, выделять префиксы нужно от крупного к мелкому: сначала пытаться выделить полные тысячи, если не вышло - сотни, если опять не вышло - десятки. Таким образом получить полное покрытие диапазона нумерации минимально достаточными префиксами.
...
Рейтинг: 0 / 0
19.12.2013, 09:11
    #38506102
o-o
o-o
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
=Сергей= 123456000-123789999
123456
123457
123458
123459
12346
12347
12348
12349
1235
1236
12370
12371
12372
12373
12374
12375
12376
12377
12378

я все равно не понимаю.
вот в этом примере: 123456000-123789999
можно "переваливать" за 123456, но нельзя за 123789999, так?
1235 ок, тк меньше, чем 123789999
1236 тоже ок, но куда делись 12351, 12352,...,12359?
и почему нету 12361, 12362,...,12369,
почему сразу 12370?
да и 12370 чем лучше 12360? почему первое подходит, а второе -- нет?
в смысле, почему это "можно наращивать" после "7",
но нельзя было после "5", "6"?
...
Рейтинг: 0 / 0
19.12.2013, 09:41
    #38506134
Dis07
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
Добрый Э - Эходнозначного определения :)
В банке на 13 литров: 4 (знака в строке) - 6 - 3
...
Рейтинг: 0 / 0
19.12.2013, 10:17
    #38506180
Cygapb-007
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
=Сергей=Простите за неудачный и неверный пример.
Следующий будет лучше: 123456000-123789999 соответствует списку таких префиксов:Попробую переформулировать постановку задачи.

очевидно, что любой номер с минимальным общим префиксом 123 может выйти за границы диапазона как снизу (123000110, например), так и сверху (123810971).
аналогично рассуждая, получим минимальный префикс нижней границы 123456 (далее любые цифры номера попадают в диапазон)
значит, первый префикс 123456 определяет номера с 123456000 по 123456999, соответственно, остаток первоначального диапазона примет вид 123457000-123789999 , его так же нужно раздробить на поддиапазоны.

минимальный диапазон остатка, путем аналогичных рассуждений, будет 123457, затем 123458, затем 123459
последний диапазон оставляет от первоначального поддиапазон 123460000-123789999

далее, рассуждая так же, получаем цепочку диапазонов 12346, 12347, 12348, 12349, 1235, 1236 (остаток 1237000000-12378999 )

теперь нужно уже учитывать верхнюю границу диапазона, потому что для префикса 1237 существуют номера, выходящие за верхнюю границу (например, 12379001), поэтому диапазон становится более узким: 12370, 12371, 12372, ..., 12377, 12378

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

Как-то так...
...
Рейтинг: 0 / 0
19.12.2013, 12:46
    #38506392
aleks2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
Не может быть сложной задача для АТС.

Поганая императивщина и допиливать надо...
Код: sql
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.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
create function dbo.Prefixes(@beg varchar(32), @end varchar(32))
returns @p table (prefix varchar(32) primary key clustered
                  , beg bigint, [end] bigint, unique(beg, [end])
                  , i int identity
                 )
as
begin
  declare @len int 
        , @prefix0 varchar(32)
        , @prefix varchar(32)
        , @20_0 char(32) 
        , @20_9 char(32) 
        , @i int;

  set @20_0 = '00000000000000000000';
  set  @20_9 = '99999999999999999999';
  set @len = len(@end)

  --1 уравниваем длины
  if len(@beg) < @len set @beg = right( @20_0 + @beg, @len);

  --2 префикс абсолютного совпадения
  set @i = 1;
  while @i<=@len and left(@beg, @i) = left(@end, @i)
    set @i = @i+1;

  -- 3 следующая за @prefix цифра
  set @prefix = left(@beg, @i) + 1;

  -- 4 все возможные КОРОТКИЕ префиксы
  while @prefix < @end
  begin
    insert @p values (@prefix, left( @prefix + @20_0, @len), left( @prefix + @20_9, @len));
    set @prefix = @prefix + 1;
  end;

  -- 5 для последнего префикса генерируем +1 цифирь
  set @prefix = @prefix - 1;
  update @p set prefix = prefix + '0' where prefix = @prefix;
  set @prefix = @prefix + '1';

  while @prefix < @end
  begin
    insert @p values (@prefix, left( @prefix + @20_0, @len), left( @prefix + @20_9, @len));
    set @prefix = @prefix + 1;
  end;

  -- 6  генерируем начальные префиксы
	while substring(@beg, @i+1, 1) <> '0'
	begin

  	  set @i = @i + 1;

	  -- 3 следующая за @prefix цифра
	  set @prefix = left(@beg, @i) + 1;
	  set @end = (select min(beg) from @p) - 1;

	  -- 4 все возможные КОРОТКИЕ префиксы
	  while @prefix < @end
	  begin
                   insert @p values (@prefix, left( @prefix + @20_0, @len), left( @prefix + @20_9, @len));
                   set @prefix = @prefix + 1;
	  end;
	end;

    set @prefix = left(@beg, @i);
    insert @p values (@prefix, left( @prefix + @20_0, @len), left( @prefix + @20_9, @len));

  return;
end;
go

select * from dbo.Prefixes('123456000', '123789999')
order by i
...
Рейтинг: 0 / 0
19.12.2013, 15:17
    #38506617
o-o
o-o
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
как объяснил Cygapb-007, мне нравится, но в таком случае в первом примере откуда взялись префиксы,
начиная с 39290?
ведь все, что начинается с 39290, вылетает за 392080?
=Сергей=Например, диапазон 391500-392080 должен быть преобразован в список из 14 префиксов:
3915
3916
3917
3918
3919
39290
39291
39292
39293
39294
39295
39296
39297
39298
...
Рейтинг: 0 / 0
19.12.2013, 15:23
    #38506628
o-o
o-o
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
ну вот, функция от aleks2 со мной почти согласна,
хотя она для диапазона 391500-392080 еще выдает 3920,
а фига-ли, вылетят номера с таким префиксом за 3920 80
(392099...)
...
Рейтинг: 0 / 0
19.12.2013, 18:12
    #38507005
Cygapb-007
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
-- if object_id('Ranges') is not null drop table Ranges
if object_id('Ranges') is null begin
   create table Ranges(
       [id] int identity(1,1) not null
      ,[rBeg] varchar(32)   -- начало диапазона
      ,[rEnd] varchar(32)   -- конец диапазона
      ,[rName] nvarchar(100)-- имя диапазона
      );
   insert Ranges(rBeg,rEnd,rName) values 
      ('391500','392080','Range1'),
      ('123456000','123789999','Range2'),
      ('123000','123259','Range3'),
      ('120000','120057','Range4');
end


Код: sql
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.
;with dRanges as(
   select 
      r.id, r.rName, r.rBeg sBeg, r.rEnd [sEnd], fLen,
      fPfx, fMin, fMax, lPfx, g.*
   from Ranges r
   cross apply (select LEN(r.rEnd))f1(fLen)
   cross apply (select convert(varchar,LEFT(r.rBeg,f1.fLen - PATINDEX('%[1-9]%',REVERSE(r.rBeg))+1)))f2(fPfx)
   cross apply (select LEFT(f2.fPfx+REPLICATE('0',f1.fLen),f1.fLen))f3(fMin)
   cross apply (select LEFT(f2.fPfx+REPLICATE('9',f1.fLen),f1.fLen))f4(fMax)
   outer apply (select convert(varchar,fPfx) where fMax<=rEnd) l(lPfx)
   outer apply (select fPfx where fMax>rEnd) g(gPfx)
   union all
   select 
      r.id, rName, sBeg, sEnd, fLen, 
      ufPfx, ufMin, ufMax, ulPfx, ugPfx
   from dRanges r
   cross apply (select 
      convert(varchar,case 
         when lPfx IS NULL then gPfx+'0' 
         when right(lPfx,1)<'9' then r.lPfx+1 
         else left(lPfx+1, LEN(lPfx)-1) end)
      ) f1(ufPfx)
   cross apply (select LEFT(f1.ufPfx+REPLICATE('0',fLen),fLen))f3(ufMin)
   cross apply (select LEFT(f1.ufPfx+REPLICATE('9',fLen),fLen))f4(ufMax)
   outer apply (select convert(varchar,ufPfx) where ufMax<=sEnd) l(ulPfx)
   outer apply (select ufPfx where ufMax>sEnd) g(ugPfx)
   where gPfx is null or gPfx<sEnd
)
select id, rName, sBeg, sEnd, lPfx, fMin, fMax
from dRanges d
where lPfx is not null
order by d.id, d.lPfx

Результат выполненияidrNamesBegsEndlPfxfMinfMax1Range139150039208039153915003915991Range139150039208039163916003916991Range139150039208039173917003917991Range139150039208039183918003918991Range139150039208039193919003919991Range1391500392080392003920003920091Range1391500392080392013920103920191Range1391500392080392023920203920291Range1391500392080392033920303920391Range1391500392080392043920403920491Range1391500392080392053920503920591Range1391500392080392063920603920691Range1391500392080392073920703920791Range13915003920803920803920803920802Range21234560001237899991234561234560001234569992Range21234560001237899991234571234570001234579992Range21234560001237899991234581234580001234589992Range21234560001237899991234591234590001234599992Range2123456000123789999123461234600001234699992Range2123456000123789999123471234700001234799992Range2123456000123789999123481234800001234899992Range2123456000123789999123491234900001234999992Range212345600012378999912351235000001235999992Range212345600012378999912361236000001236999992Range2123456000123789999123701237000001237099992Range2123456000123789999123711237100001237199992Range2123456000123789999123721237200001237299992Range2123456000123789999123731237300001237399992Range2123456000123789999123741237400001237499992Range2123456000123789999123751237500001237599992Range2123456000123789999123761237600001237699992Range2123456000123789999123771237700001237799992Range2123456000123789999123781237800001237899993Range312300012325912301230001230993Range312300012325912311231001231993Range3123000123259123201232001232093Range3123000123259123211232101232193Range3123000123259123221232201232293Range3123000123259123231232301232393Range3123000123259123241232401232493Range3123000123259123251232501232594Range4120000120057120001200001200094Range4120000120057120011200101200194Range4120000120057120021200201200294Range4120000120057120031200301200394Range4120000120057120041200401200494Range41200001200571200501200501200504Range41200001200571200511200511200514Range41200001200571200521200521200524Range41200001200571200531200531200534Range41200001200571200541200541200544Range41200001200571200551200551200554Range41200001200571200561200561200564Range4120000120057120057120057120057
...
Рейтинг: 0 / 0
19.12.2013, 19:52
    #38507111
Cygapb-007
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
Есть неточность, проявляется, например, на диапазоне 398577-513132
Но допиливать особого смысла не вижу.
...
Рейтинг: 0 / 0
20.12.2013, 18:08
    #38508324
Speshuric
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
=Сергей=,

Всё же просто. Рекурсивные CTE рулят :)
Код: sql
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.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
declare @start bigint = 1220438;
declare @finish bigint = 1421953;

with cte
	(start,  -- начало диапазона
	divider, -- точка внутри диапазона для основания рекурсии start<=divider<=finish
	finish,  -- конец диапазона
	base)    -- текущая длина диапазона (степень десяти)
as (

-- 1. Начало: 
-- а) находим такую длину диапазона (base), чтобы она не превышала хвост префикса минимальной длины
-- б) "откусываем" начало диапазона до смены цифр при самом коротком префиксе
select 
	t.start, 
	(t.start+t.base)/t.base*t.base-1 divider, -- "x/n*n" для выравнивания по n
	t.finish, 
	t.base
from 
	(select 
		@start start, 
		@finish finish, 
		POWER(10,FLOOR(LOG10(@finish-@start+1))) base -- FLOOR(LOG10(x)) - число цифр
	) t

-- 2. Для текущей длины префикса разбиваем основной диапазон на диапазоны, соответствующие префиксам
union all 
select
	cte.divider+1 start, 
	case when cte.divider + cte.base>cte.finish then cte.finish else cte.divider + cte.base end, 
	cte.finish finish, 
	cte.base
from cte
where cte.finish>=cte.divider+1

-- 3. Проверяем, если диапазон не является префиксом по base, то уменьшаем base и отправляем снова в мясорубку п. 2
union all
select 
	t.start, 
	case when t.finish<(t.start+t.base)/t.base*t.base-1 then t.finish else (t.start+t.base)/t.base*t.base-1 end divider, 
	t.finish, 
	t.base
from 
	(select
		cte.start start,
		cte.divider finish,
		cte.base/10 base
	from cte
	where 
		cte.divider<>cte.start+cte.base-1
	) t

)
-- Выводим результаты, отсекая "недиапазонные" строчки, которые появились как переходы от п.2 к п.3
select 
	cte.start/cte.base prefix, -- префикс
	cte.start,                 -- начало диапазона
	cte.divider finish,        -- конец диапазона
	cte.base,                  -- множитель префикса
	LOG10(cte.base) suffix_len -- допустимая длина номера
from cte          
where divider = start + base - 1
order by cte.start



Запрос не в три строчки, конечно, но в основном чтобы было понятно как оно работает.
...
Рейтинг: 0 / 0
20.12.2013, 19:41
    #38508424
o-o
o-o
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
Speshuric , спасибо за решение: доходчиво, алгоритм как на ладони.
...
Рейтинг: 0 / 0
22.12.2013, 15:59
    #38509273
andrey odegov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
Извиняюсь, если опоздал и что на PowerShell (SQL Server остался на работе)
Код: powershell
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
cls
[int]$beg,[int]$end,[int]$mag=1220438,1421953,1
while($beg -lt $end){
  while($beg -lt [math]::truncate($end/$mag)){
   while($beg%10 -eq 0){
    $mag*=10
    $beg=[math]::truncate($beg/10)
    if(($beg+1)*$mag-1 -gt $end){
     $mag/=10
     $beg*=10
     break
    }
   }
   $beg++|write
  }
 $beg*=$mag
 $mag=1
}
if($beg -eq $end){$beg}
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
24.04.2020, 13:57
    #39950987
VictorKosenkov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сложная, но интересная задача
andrey odegov, здравствуйте.

Вот уже несколько лет пользуюсь Вашим решением задачи преобразования диапазонов в префиксы.
Допилил код PowerShell для обработки CSV файла с сайта Россвязи, но поскольку почти весь процесс работы по тарификации телефонных разговоров у меня организован в MS Excel (MS Office 365), хочется решить эту задачу в Power Query.
Собственные попытки ни к чему не привели, знаний маловато.
Подскажите, это вообще возможно - решить данную задачу в редакторе Power Query, или я зря надеюсь и не стоит тратить время?
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сложная, но интересная задача / 24 сообщений из 24, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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