2015-07-20 190 views
2

我有列电话和范围表称为PHONENUMBERS如下SQL拿到电话号码的序列

enter image description here

在这里的电话专栏中,我有一个电话号码,并在一系列专栏中,我有一个范围的值我需要的电话号码是included.For所述第一电话号码9125678463我需要包括的电话号码,直到9125678465即(9125678463,9125678464,9125678465)。类似地用于其它电话号码too.here的范围内的样品目的地表应看起来像

enter image description here

我怎么能写SQL来得到这个?

在此先感谢

+2

您好!你可以请张贴你到目前为止尝试过的吗? – scubaFun

+1

2份刚刚拆分原来的号码,让你有前缀和休息,然后创建一个数字表或动态理货表和加盟者一起 –

+0

@JamesZ这几乎是我的答案做什么 - 很高兴我不是唯一的一个谁是这样想的;-) – CeOnSql

回答

1

我有一个解决方案,它采用了经典的方法但它不需要递归,也不需要任何循环!和它的作品,即使你的范围具有一个3或5,或任何长度...

首先我创建一个表以数字(在这个例子中,从1到100万 - 你可以在TOP()子句采用这个) :

SELECT TOP (1000000) n = CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id])) 
INTO dbo.Numbers 
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2 
OPTION (MAXDOP 1); 

CREATE UNIQUE CLUSTERED INDEX idx_numbers ON dbo.Numbers(n) 
; 

如果你有一个表这是很简单的:

;WITH phonenumbers 
AS 
(
SELECT phone, 
     [range], 
     CAST(RIGHT(phone,LEN([range])) AS INT) AS number_to_increase, 
     CAST(LEFT(phone,LEN(phone)-LEN([range])) + REPLICATE('0',LEN([range])) AS BIGINT) AS base_number 
FROM PhoneNumbers 
) 

SELECT p.base_number + num.n 
FROM phonenumbers p 
     INNER JOIN dbo.Numbers num ON num.n BETWEEN p.number_to_increase AND p.[range] 

您没有使用CTE喜欢这里 - 它只是去看了一下清晰的这种做法背后的想法是什么。这也许适合你

1

您可以使用CTE这样的:

;WITH CTE (PhoneNumbers, [Range], i) AS (
    SELECT CAST(Phone AS bigint), [Range], CAST(1 AS bigint) 
    FROM yourTable 
    UNION ALL 
    SELECT CAST(PhoneNumbers + 1 AS bigint), [Range], i + 1 
    FROM CTE 
    WHERE (PhoneNumbers + 1) % 10000 <= [Range] 
) 
SELECT PhoneNumbers 
FROM CTE 
ORDER BY PhoneNumbers 
+0

这工作,但使用递归CTE这样是非常低效的处理是由行做一行。 http://www.sqlservercentral.com/articles/T-SQL/74118/ –

1

下面是一个使用了提示表的一个例子。在我的系统中,我有一组视图作为视图,所以我再也不需要再写它了。

if OBJECT_ID('tempdb..#PhoneNumbers') is not null 
    drop table #PhoneNumbers; 

create table #PhoneNumbers 
(
    Phone char(10) 
    , Range smallint 
) 

insert #PhoneNumbers 
    select 9135678463, 8465 union all 
    select 3279275678, 5679 union all 
    select 6372938103, 8105; 

WITH 
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)), 
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows 
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max 
cteTally(N) AS 
(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4 
) 

select * 
from #PhoneNumbers p 
join cteTally t on t.N >= RIGHT(Phone, 4) and t.N <= Range 
order by p.Phone 
0

还有一个办法:

--Creating dummy table 
select '9999991234' phone, '1237' rang into #tbl 
union 
select '9999995689', '5692' 

SELECT [phone] low 
     ,(CAST(9999995689/10000 AS bigINT) * 10000 + [Rang]) high 
into #tbl1 
FROM #tbl 

--Creating 'numbrs' to have numbers between 0 & 9999 i.e. max range 

select (rn-1)rn 
into #numbrs 
from 
(select row_number() over (partition by null order by A.object_id) rn from sys.objects A 
cross join sys.objects B)A 
where rn between 0 and 9999 

select (low + rn)phn from #numbrs cross join #tbl1 
where (low + rn) between low and high