BGInfo(Microsoft Sysinternals)能够将数据写入SQL服务器。网卡信息是一个字段,由CRLF CHAR(13)+ CHAR(10)分隔。有些计算机可能只有一个网卡。其他人可能有7张或更多的网卡。每个字段(Network_Card,IP_Address和Subnet_Mask)包含匹配网卡信息的CRLF分隔列表。
我想将CRLF分隔字段转换为与Network_Card的第一个条目匹配的多行,以及IP_Address和Subnet_Mask的第一个条目。然后,选择Default_Gateway与IP_address匹配的记录(指示哪个网卡处于活动状态)。
BGInfo将许多字段填充到表中,对于此示例,我将使用所需字段创建子集。
首先我们可以创建一个临时的BGInfo表:
IF OBJECT_ID('tempdb..#BGInfo') IS NOT NULL DROP TABLE #BGInfo
CREATE TABLE #BGInfo (
[User_Name] nvarchar(25),
[Host_Name] nvarchar(25),
[Network_Card] nvarchar(MAX),
[IP_Address] nvarchar(255),
[Subnet_Mask] nvarchar(255),
[Default_Gateway] nvarchar(25)
)
然后用一些示例数据填充它:
INSERT INTO #BGInfo
SELECT
'User1',
'PC-A',
'nic1'+CHAR(13)+CHAR(10)+'nic2'+CHAR(13)+CHAR(10)+'nic3'+CHAR(13)+CHAR(10)+'nic4'+CHAR(13)+CHAR(10)+'nic5'+CHAR(13)+CHAR(10)+'nic6'+CHAR(13)+CHAR(10)+'nic7',
'(none)'+CHAR(13)+CHAR(10)+'(none)'+CHAR(13)+CHAR(10)+'10.91.2.155'+CHAR(13)+CHAR(10)+'(none)'+CHAR(13)+CHAR(10)+'192.168.80.1'+CHAR(13)+CHAR(10)+'192.168.126.1'+CHAR(13)+CHAR(10)+'(none)',
'(none)'+CHAR(13)+CHAR(10)+'(none)'+CHAR(13)+CHAR(10)+'255.255.255.128'+CHAR(13)+CHAR(10)+'(none)'+CHAR(13)+CHAR(10)+'255.255.255.0'+CHAR(13)+CHAR(10)+'255.255.255.0'+CHAR(13)+CHAR(10)+'(none)',
'10.91.2.129'
UNION ALL
SELECT
'User2',
'PC-B',
'nic1'+CHAR(13)+CHAR(10)+'nic2'+CHAR(13)+CHAR(10)+'nic3'+CHAR(13)+CHAR(10)+'nic4'+CHAR(13)+CHAR(10)+'nic5'+CHAR(13)+CHAR(10)+'nic6'+CHAR(13)+CHAR(10)+'nic7',
'10.17.17.23'+CHAR(13)+CHAR(10)+'(none)'+CHAR(13)+CHAR(10)+'(none)'+CHAR(13)+CHAR(10)+'(none)'+CHAR(13)+CHAR(10)+'192.168.80.1'+CHAR(13)+CHAR(10)+'192.168.126.1'+CHAR(13)+CHAR(10)+'(none)',
'255.255.240.0'+CHAR(13)+CHAR(10)+'(none)'+CHAR(13)+CHAR(10)+'(none)'+CHAR(13)+CHAR(10)+'(none)'+CHAR(13)+CHAR(10)+'255.255.255.0'+CHAR(13)+CHAR(10)+'255.255.255.0'+CHAR(13)+CHAR(10)+'(none)',
'10.17.16.5'
我想如果我将CRLF转换为逗号分隔值:
REPLACE([IP_Address],CHAR(13)+CHAR(10),',')
然后我可以将其转换为XML并选择行。 (很多在线信息)但是......如何使用多列?我试过这个,但它只是创建了很多重复的数据:
IF OBJECT_ID('tempdb..#XMLtable') IS NOT NULL DROP TABLE #XMLtable
CREATE TABLE #XMLtable (
[User_Name] nvarchar(25),
Computer nvarchar(25),
Network_Card nvarchar(255),
IPAddr xml,
Subnet xml,
Default_Gateway nvarchar(25)
)
INSERT INTO #XMLtable
SELECT
[User_Name],
[Host_Name] as Computer,
[Network_Card],
CAST('<i>'+REPLACE(REPLACE([IP_Address],CHAR(13)+CHAR(10),','),',','</i><i>')+'</i>' as xml) AS IPAddr,
CAST('<i>'+REPLACE(REPLACE([Subnet_Mask],CHAR(13)+CHAR(10),','),',','</i><i>')+'</i>' as xml) AS Subnet,
Default_Gateway
FROM #BGInfo bg
SELECT
[User_Name],
[Computer],
[Network_Card],
IP_Address = i.value('.', 'varchar(MAX)'),
IP_Address = s.value('.', 'varchar(MAX)'),
Default_Gateway
FROM #XMLtable
CROSS APPLY IPaddr.nodes ('/i') AS IPAddr(i)
CROSS APPLY Subnet.nodes ('/i') AS Subnet(s);
我想有一个这样的列表:(数据可能不匹配,但你明白了)
User_Name Computer Network_Card IP_Address Subnet_Mask Default_Gateway
User1 PC-A nic1 (none) (none) 10.91.2.129
User1 PC-A nic2 (none) (none) 10.91.2.129
User1 PC-A nic3 10.91.2.155 255.255.255.128 10.91.2.129
User1 PC-A nic4 192.168.80.1 255.255.255.0 10.91.2.129
User1 PC-A nic5 192.168.126.1 255.255.255.0 10.91.2.129
User2 PC-B nic1 10.17.17.23 255.255.240.0 10.17.16.5
User2 PC-B nic2 (none) (none) 10.17.16.5
User2 PC-B nic3 (none) (none) 10.17.16.5
User2 PC-B nic4 192.168.80.1 255.255.255.0 10.17.16.5
User2 PC-B nic5 192.168.126.1 255.255.255.0 10.17.16.5
然后可以选择默认网关与IP_address匹配的ACTIVE网卡:
User_Name Computer Network_CardIP_Address Subnet_Mask Default_Gateway
User1 PC-A nic3 10.91.2.155 255.255.255.128 10.91.2.129
User2 PC-B nic1 10.17.17.23 255.255.240.0 10.17.16.5
答案 0 :(得分:1)
我认为问题来自于尝试从单个#XMLtable表中分解卡片,ips和子网。使用您所做的相同逻辑,我做了三个单独的查询(网卡,ips和子网各一个),为每个查询生成row_numbers,并根据row_number将它们连接在一起。然后我用PARSENAME
来比较ip地址和网关。
select nics.User_Name,
nics.Host_Name Computer,
nics.nic Network_Card,
ips.ip IP_Address,
subnets.subnet Subnet_Mask,
b.Default_Gateway
from
(
select User_Name, Host_Name,
nic.a.value('.', 'varchar(max)') as nic,
ROW_NUMBER() over (partition by User_name, Host_name order by User_name, Host_name) Row_number
from
(
select b.User_name, b.Host_name,
CAST('<i>' + REPLACE(b.Network_Card, CHAR(13)+CHAR(10), '</i><i>') + '</i>' as xml) as nics
from #BGInfo b
) a
cross apply nics.nodes('/i') as nic(a)
) nics
join
(
select User_Name, Host_Name,
ip.a.value('.', 'varchar(max)') as ip,
ROW_NUMBER() over (partition by User_name, Host_name order by User_name, Host_name) Row_number
from
(
select b.User_name, b.Host_name,
CAST('<i>' + REPLACE(b.IP_Address, CHAR(13)+CHAR(10), '</i><i>') + '</i>' as xml) as ips
from #BGInfo b
) a
cross apply ips.nodes('/i') as ip(a)
) ips on ips.User_Name = nics.User_Name and ips.Host_Name = nics.Host_Name and ips.Row_number = nics.Row_number
join
(
select User_Name, Host_Name,
subnet.a.value('.', 'varchar(max)') as subnet,
ROW_NUMBER() over (partition by User_name, Host_name order by User_name, Host_name) Row_number
from
(
select b.User_name, b.Host_name,
CAST('<i>' + REPLACE(b.Subnet_Mask, CHAR(13)+CHAR(10), '</i><i>') + '</i>' as xml) as subnets
from #BGInfo b
) a
cross apply subnets.nodes('/i') as subnet(a)
) subnets on subnets.User_Name = nics.User_Name and subnets.Host_Name = nics.Host_Name and subnets.Row_number = nics.Row_number
join #BGInfo b on b.User_Name = nics.User_Name and b.Host_Name = nics.Host_Name
where PARSENAME(ips.ip, 4) = PARSENAME(b.Default_Gateway, 4) and
PARSENAME(ips.ip, 3) = PARSENAME(b.Default_Gateway, 3)
我不知道它将如何针对大量行执行,但它适用于测试数据。
答案 1 :(得分:1)
一种选择是转储BGInfo,并使用PowerShell脚本。 Powershell可以获得Nic信息,它可以执行SQL。如果您的桌面安装了PowerShell,那么这可能更容易构建和维护,并且可能更快。 我找到了两篇可以帮助你的文章:
如果你必须使用BGInfo,那么就个人而言,我会采取不同的方法,并将问题分开。
如果BGInfoTable上的唯一键是Time_stamp + User_name + Host_name,那么您可以拥有这样的相关nic表:
CREATE TABLE BGInfo_Nics (
BGTime_Stamp DATETIME NOT NULL,
User_Name NVARCHAR(250) NOT NULL, -- these cols should match BGInfoTable datatypes
Host_Name NVARCHAR(250) NOT NULL,
NicName NVARCHAR(250) NOT NULL,
IPAddress NVARCHAR(50) NULL,
SubNet NVARCHAR(50) NULL,
GatewayIP NVARCHAR(50) NULL
)
GO
CREATE UNIQUE INDEX IX_BGInfo_Nics ON BGInfo_Nics ( BGTime_Stamp,
User_Name,
Host_Name,
NicName
)
GO
该程序将不断运行,并且每隔一段时间,它就可以查询BGInfoTable以查看是否需要处理的行。处理将包括从BGInfoTable读取尚待处理的行,解析包括IP地址,子网和网关在内的nic信息,并将nic信息行写入新的(相关)表BGInfo_Nics。
例如: - 使用它来获取需要处理的行:
SELECT bg.*
FROM BGInfoTable bg (NOLOCK) LEFT OUTER JOIN BGInfo_Nics nics (NOLOCK) ON
bg.Time_Stamp = nics.BGTime_Stamp AND
bg.[User_Name] = nics.[User_name] AND
bg.[Host_Name] = nics.[Host_name]
WHERE nics.BGTime_Stamp IS NULL
或者,您可以向BGInfoTable添加几列以标记已经处理的行,并创建索引以快速获取未处理的行。
有一个单独的程序进行处理(读取新的,解析和保存),我怀疑这种解决方案将提供更多的灵活性来解析并将数据保存为您真正想要报告的格式,并且表现非常好
HTH
麦克