2012-07-04 1 views
2

У меня есть таблица с колонкой под названием ExcelLinks а, содержащую запись, как это:граф общие и уникальные имена файлы, встроенные в строке

= ИНДЕКС («\\ san1 \ engData [BT_500.0_Structural_Position.xls] Бетон» ! $ B $ 4: $ IK $ 83, MATCH ($ K $ 9, '\\ san1 \ engData [BT_500.0_Structural_Position.xls] Бетон' $ A $ 4: $ A $ 83,0), MATCH (C212, '\\ san1 \ engData [BT_500.0_Structural_Position.xls] Concrete '$ B $ 3: $ IK $ 3,0))/1000000

= ИНДЕКС (' \\ san1 \ engData [GK_600.0_Pumps.xls] Насосы $! B $ 4: $ BD $ 39, MATCH ($ K $ 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))/1 000000

= ИНДЕКС ('\\ san1 \ engData [TT_640.0_Generator.xls] Генератор' $ B $ 4: $ HU $ 83, MATCH ($ K $ 9, '\\ san1 \ engData [GK_600.0_Pumps. xls] Pumps '! $ 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, которые используют несколько взаимосвязей (это могут быть разные файлы).

В этой таблице содержится более 12 миллионов записей, поэтому меня беспокоит производительность с помощью курсора.

Есть несколько лучших способов сделать это с помощью Oracle using RegEx's. Я знаю, что у SQL Server нет RegEx и я готов написать/использовать хранимую процедуру CLR, если это самый простой вариант.

+0

По существу, каждый раз, когда вы видите \\, который считается файлом? SQL Server не поддерживает RegEx изначально, но вы можете реализовать его с помощью CLR (и вам, конечно, не нужен курсор для этого в любом случае). –

+0

Спасибо @Aaron, я попытался прояснить то, что хочу, и я не думаю, что смог бы его подсчитать количество '\\'. –

ответ

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), но это не моя сильная сторона. Большая часть затрат - это ввод-вывод, необходимый для сканирования всей таблицы, а не подсчета или замены.

Если вы не можете использовать CLR, вы можете заменить эту функцию на любое количество версий, отличных от CLR (here is an example that would be a functionally suitable replacement), но имейте в виду, что другие подходы, вероятно, будут иметь менее оптимальную производительность.

+0

Это так здорово, что я скопировал функцию CLR для разделения строк из Адама Мачанича (http://sqlblog.com/blogs/adam_machanic/archive/2009/04/28/sqlclr-string-splitting-part-2-even -faster-even-more-scalable.aspx), поместите его в проект библиотеки классов> Скомпилированный> поместите DLL на сервер и получите его работу. Единственный трюк был нацелен на pre .Net 4.0, а затем он зарегистрировал удовольствие. Огромное спасибо. –