powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сложная, но интересная задача
24 сообщений из 24, страница 1 из 1
Сложная, но интересная задача
    #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
Сложная, но интересная задача
    #38505941
o-o
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
o-o
Гость
кто-то что-то понял?
почему есть 3915 и нет 391500?
почему 14?
чем не угодил 3920?
...
Рейтинг: 0 / 0
Сложная, но интересная задача
    #38505944
=Сергей=
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
o-o,
Мы ведь рассуждаем о ПРЕФИКСАХ, а для номера 391500 из указанного диапазона будет достаточным префикс 3915
...
Рейтинг: 0 / 0
Сложная, но интересная задача
    #38505947
Gwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
=Сергей=,

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

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

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

Не можешь формализовать, то хотя бы на словах расскажи алгоритм однозначного определения префикса.О-о-о, прочитал ещё раз постановку задачи. Смысл желаемого стал ясен. :)
В общих чертах решение сводится к тому, что нужно выделить полные [десятки | сотни | тысячи] номеров в заданном диапазоне. Причем, выделять префиксы нужно от крупного к мелкому: сначала пытаться выделить полные тысячи, если не вышло - сотни, если опять не вышло - десятки. Таким образом получить полное покрытие диапазона нумерации минимально достаточными префиксами.
...
Рейтинг: 0 / 0
Сложная, но интересная задача
    #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
Сложная, но интересная задача
    #38506134
Dis07
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый Э - Эходнозначного определения :)
В банке на 13 литров: 4 (знака в строке) - 6 - 3
...
Рейтинг: 0 / 0
Сложная, но интересная задача
    #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
Сложная, но интересная задача
    #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
Сложная, но интересная задача
    #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
Сложная, но интересная задача
    #38506628
o-o
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
o-o
Гость
ну вот, функция от aleks2 со мной почти согласна,
хотя она для диапазона 391500-392080 еще выдает 3920,
а фига-ли, вылетят номера с таким префиксом за 3920 80
(392099...)
...
Рейтинг: 0 / 0
Сложная, но интересная задача
    #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
Сложная, но интересная задача
    #38507111
Cygapb-007
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть неточность, проявляется, например, на диапазоне 398577-513132
Но допиливать особого смысла не вижу.
...
Рейтинг: 0 / 0
Сложная, но интересная задача
    #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
Сложная, но интересная задача
    #38508424
o-o
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
o-o
Гость
Speshuric , спасибо за решение: доходчиво, алгоритм как на ладони.
...
Рейтинг: 0 / 0
Сложная, но интересная задача
    #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
Период между сообщениями больше года.
Сложная, но интересная задача
    #39950987
VictorKosenkov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andrey odegov, здравствуйте.

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


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