我有一个名为ExcelLinks的列的表,其中包含如下记录:
= INDEX(\\ SAN1 \ engData [BT_500.0_Structural_Position.xls]混凝土'$ B $ 4:!$ IK 83 $,MATCH($ $ķ9'\\ SAN1 \ engData [BT_500.0_Structural_Position.xls]混凝土'$ A $ 4:!$ A $ 83,0),MATCH(C212,\\ SAN1 \ engData [BT_500.0_Structural_Position.xls]混凝土'$ B $ 3:!$ $ IK 3,0))/ 1000000
= INDEX(\\ SAN1 \ engData [GK_600.0_Pumps.xls]泵'$ B $ 4:!$ $ BD 39 MATCH($ $ķ9'\\ SAN1 \ engData [TT_640.0_Generator.xls]发生器'$ A $ 4:!$ A $ 39,0),MATCH(C214,\\ SAN1 \ engData [GK_600.0_Pumps.xls]泵$ B $ 3:!$ $ BD 3,0))/ 1000000
= INDEX(\\ SAN1 \ engData [TT_640.0_Generator.xls]发生器'$ B $ 4:!$ HU 83 $,MATCH($ $ķ9'\\ SAN1 \ engData [GK_600.0_Pumps.xls]泵'$ A $ 4:!$ A $ 83,0),MATCH(C218,\\ SAN1 \ engData [TT_640.0_Generator.xls]发生器'$ B $ 3:!$ $ HU 3,0))/ 1000000
理想的输出是:
_______________________________________
| Row | LinkCount | UniqueLinkCount |
| 1 | 3 | 1 |
| 2 | 3 | 2 |
| 3 | 3 | 2 |
我想查询此数据并查看每条记录使用的文件数和唯一文件数。
我在网上搜索过,找不到任何可以做到这一点的内容。
我想我会制作一个光标,对于每个记录,我会检测以\\
开头并以'!$
结尾的字符并计算文件数。
硬件位是ExcelLinks,=INDEX
和MATCH
函数使用多个互连链接(可能是不同的文件)。
此表中有超过1200万条记录,因此我担心使用游标的性能。
使用Oracle using RegEx's有一些更好的方法可以做到这一点。我知道SQL Server没有RegEx,如果这是最简单的选择,我愿意编写/使用CLR存储过程。
答案 0 :(得分:3)
首先,grab this string splitting CLR function from Adam Machanic。将代码编译成DLL(using csc,如果您没有Visual Studio),将DLL复制到您的服务器,然后按如下方式注册DLL(您必须在此处替换一些可变部分,例如文件路径,您想要调用程序集的内容等):
CREATE ASSEMBLY CLRStuff
FROM 'C:\DLLs\CLRStuff.dll'
WITH PERMISSION_SET = SAFE;
GO
CREATE FUNCTION dbo.SplitStrings
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE ( Item NVARCHAR(4000) )
EXTERNAL NAME CLRStuff.UserDefinedFunctions.SplitString_Multi;
GO
有了这个,查询本身就很容易了。让我们创建一个包含几行的简单表变量(为简洁起见,我缩短了路径):
DECLARE @x TABLE(i INT, ExcelLink VARCHAR(MAX));
INSERT @x
-- 3 files, 1 unique:
SELECT 1,'=INDEX(''\\san1\a.xls''!$B$4:$IK$83,MATCH($K$9,''\\san1\a.xls'
+ '''!$A$4:$A$83,0),MATCH(C212,''\\san1\a.xls''!$B$3:$IK$3,0))/1000000'
UNION ALL
-- 3 files, 3 unique:
SELECT 2,'=INDEX(''\\san1\a.xls''!$B$4:$BD$39,MATCH($K$9,''\\san1\b.xls'
+ '''!$A$4:$A$39,0),MATCH(C214,''\\san1\c.xls''!$B$3:$BD$3,0))/1000000'
UNION ALL
-- 3 files, 2 unique:
SELECT 3,'=INDEX(''\\san1\b.xls''!$B$4:$HU$83,MATCH($K$9,''\\san1\c.xls'
+ '''!$A$4:$A$83,0),MATCH(C218,''\\san1\c.xls''!$B$3:$HU$3,0))/1000000'
UNION ALL
-- 1 file, 1 unique:
SELECT 4,'=INDEX(''\\san1\foo.xls''!$B$4:$HU$83,0)';
-- the above was just inserts; the remainder is all of the query:
;WITH x(i,part) AS
(
SELECT x.i, SUBSTRING(t.Item, CHARINDEX('''\\', t.Item), 2048)
FROM @x AS x CROSS APPLY dbo.SplitStrings(x.ExcelLink, '!$') AS t
)
SELECT i, [file_count] = COUNT(part), [unique_files] = COUNT(DISTINCT part)
FROM x WHERE part LIKE '''\\%'
GROUP BY i ORDER BY i;
结果:
i file_count unique_files
-- ---------- ------------
1 3 1
2 3 3
3 3 2
4 1 1
这依赖于\\
除了作为文件路径的开头之外不会自然地出现在数据中,并且所有文件路径都驻留在网络共享上。
这可能不是你能获得的最有效率 - 我确信一些RegEx向导可以使用这种方法改进这个而不是分裂(here is a good article to get you started),但这不是我的强项。大部分成本将是扫描整个表所需的I / O,而不是计数或替换。
如果您不能使用CLR,则可以将该函数替换为任意数量的非CLR版本(here is an example that would be a functionally suitable replacement),但请记住,其他方法可能会受到性能不佳的影响。