我在SQL数据库中有两列:SubnetID
,SubnetName
示例:
SubnetID SubnetName
1 1.2.3.0/24
2 1.2.4.0/14
3 1.2.5.4/30
...
...
使用SQL代码,我需要为每个现有行(subnetID,SubnetName)添加另一列“ IP地址”。
输出:
SubnetID SubnetName IP Address
1 1.2.3.0/24 1.2.3.0
1 1.2.3.0/24 1.2.3.1
1 1.2.3.0/24 1.2.3.2
... ... ... and so on (till .24)
1 1.2.3.0/24 1.2.3.24
2 1.2.4.0/14 1.2.4.0
2 1.2.4.0/14 1.2.4.1
2 1.2.4.0/14 1.2.4.2
... ... ... and so on (till .14)
2 1.2.4.0/14 1.2.4.14
3 1.2.5.4/30 1.2.5.4
3 1.2.5.4/30 1.2.5.5
3 1.2.5.4/30 1.2.5.6
... ... ... and so on (till .30)
3 1.2.5.4/30 1.2.5.30
... etc.
因此,基本上前两列需要保持原样,但其他列将具有覆盖(.x / x)范围的单独地址。
非常感谢您的任何建议。
答案 0 :(得分:0)
如果我正确理解了您的问题,最好在表中添加另一个列,而不是在表中添加新列:
SubnetID IPAddress
-------------------
1 1.2.3.0
1 1.2.3.1
1 1.2.3.2
... ...
2 1.2.4.0
... ...
3 1.2.5.4
您的原始表格保持不变:
SubnetID SubnetName
---------------------
1 1.2.3.0/24
2 1.2.4.0/14
3 1.2.5.4/30
... ...
在我看来,这比您想做的要好,因为现在我们不复制所有的SubnetName
值,并且现在可以避免冗余和所谓的update anomaly。
例如在您提出的示例中,如果要将ID SubnetName
的{{1}}从2
更改为1.2.4.0/14
会发生什么?您将不得不更改每一行-但是使用这种方式,只需更改一次即可。
答案 1 :(得分:0)
尝试此解决方案,
with cte1 as (
select *, RNUM =
row_number() over (partition by SubnetID order by SubnetID,SubnetName)-1
from demo_25_7_2018
)
select *,IPADDRESS=SUBSTRING(subnetname,1,charindex('/',subnetname,1)-1)+'.'+convert(varchar,rnum)
from cte1
Sqlfiddle演示: http://sqlfiddle.com/#!18/0057d/1
让我知道这是否可以正常工作。
答案 2 :(得分:0)
在您的问题中,我建议您在业务逻辑层上这样做。
这是 SQL服务器版本解决方案。
您可以使用 CTE递归。
有一些主要步骤
STRING_SPLIT
函数编写第一个子查询,以拆分/
得到IP
和Number
。STRING_SPLIT
函数编写第二个子查询,以拆分.
得到IP
和MaxNumber
并使用 CTE递归。REPLACE
替换IP地址。查询
;WITH CTE AS (
SELECT t1.SubnetID,
t1.SubnetName,
MAX(CASE WHEN rn = 1 THEN v.value END) startIP,
MAX(CASE WHEN rn = 2 THEN v.value END) MaxLevel
FROM T t1
CROSS APPLY (SELECT value,row_number() over (order by (select null)) rn FROM STRING_SPLIT(t1.SubnetName,'/')) v
GROUP BY t1.SubnetName,
t1.SubnetID
),CTE1 AS(
SELECT
t1.SubnetID,
t1.SubnetName,
t1.startIP,
CAST(t1.MaxLevel AS INT) MaxLevel,
CAST(MAX(CASE WHEN rn = 4 THEN v.value END) AS INT) StartLevel,
CAST(MAX(CASE WHEN rn = 4 THEN v.value END) AS INT) IPSub
FROM CTE t1
CROSS APPLY (SELECT value,row_number() over (order by (select null)) rn FROM STRING_SPLIT(t1.startIP,'.')) v
GROUP BY
t1.SubnetName,
t1.startIP,
t1.MaxLevel,
t1.SubnetID
UNION ALL
SELECT
SubnetID,
SubnetName,
startIP,
MaxLevel,
(StartLevel + 1) StartLevel,
IPSub
FROM CTE1
WHERE StartLevel < MaxLevel
)
SELECT
SubnetID,
SubnetName,
REPLACE(startIP,CONCAT('.',IPSub),CONCAT('.',StartLevel))
FROM CTE1
order by SubnetID
编辑
如果您的SQL Server版本不支持STRING_SPLIT
函数。您可以编写自己的splitstring
函数。
这是T-SQL split string中的自定义splitstring
函数
CREATE FUNCTION dbo.splitstring (@inputStr VARCHAR(MAX),@spitChar varchar(1))
RETURNS
@returnList TABLE ([Value] [nvarchar] (500))
AS
BEGIN
DECLARE @name NVARCHAR(255)
DECLARE @pos INT
WHILE CHARINDEX(@spitChar, @inputStr) > 0
BEGIN
SELECT @pos = CHARINDEX(@spitChar, @inputStr)
SELECT @name = SUBSTRING(@inputStr, 1, @pos-1)
INSERT INTO @returnList
SELECT @name
SELECT @inputStr = SUBSTRING(@inputStr, @pos+1, LEN(@inputStr)-@pos)
END
INSERT INTO @returnList
SELECT @inputStr
RETURN
END
然后您可以像sqlfiddle
一样使用