Как извлечь строки, завернутые в HTML, из столбца таблицы SQL в новую таблицу? - PullRequest
0 голосов
/ 14 июля 2011

У меня есть столбец в таблице SQL Server 2005, который называется BIO - данные в столбце BIO отформатированы следующим образом:

<HTML><HEAD><TITLE></TITLE></HEAD><BODY><STRONG><A name=SN>AARTS</A>, <A name=GN>Michelle Marie</A>, </STRONG><A name=HO>B.Sc.</A>, <A name=HO>M.Sc.</A>, <A name=HO>Ph.D.</A>; <A name=OC>scientist, professor</A>; b. <A name=BC>St. Marys</A>, Ont. <A name=BY>1970</A>; <A name=PA>d. Wm. and H. Aarts</A>; <A name=ED>e. Univ. of Western Ont. B.Sc.(Hons.) 1994, M.Sc. 1997</A>; <A name=ED>McGill Univ. Ph.D. 2002</A>; <A name=MA>m. L. MacManus</A>; two children; <A name=PO>CANADA RESEARCH CHAIR IN SIGNAL TRANSDUCTION IN ISCHEMIA</A> and <A name=PO>ASST. PROF., DEPT. OF BIOL. SCI., UNIV. OF TORONTO SCARBOROUGH 2006&ndash;&nbsp;&nbsp;</A>; Postdoctoral Fellow, Toronto Western Hosp. 2000&ndash;06; Expert Cons., Auris Med. SAS, Montpellier, France; mem., Centre for the Neurobiol. of Stress; named INMHA Brainstar of the Year 2003; Bd. of Dirs. &amp; Fundraising Chair, N'Sheemaehn Childcare; mem., Soc. for Neurosci.; Cdn. Physiol. Soc.; Cdn. Assn. for Neurosci.; <A name=WK>co-author: 'Therapeutic Tools in Brain Damage' in <EM>Proteomics and Protein Interactions: Biology, Chemistry, Bioinformatics and Drug Design </EM>2005; 18 pub. journal articles</A>; Office: <A name=OF1_L1>1265 Military Trail</A>, <A name=OF1_CT>Scarborough</A>, <A name=OF1_PR>Ont.</A> <A name=OF1_PC>M1C 1A4</A>. </BODY></HTML>

Мне нужно извлечь значения из каждого тега привязки, т. Е.:

<A name=SN>AARTS</A> 

Мне нужно иметь AARTS в столбце с именем SN в наборе результатов

Это то, что у меня есть ...

SELECT  CONTACT_ID
    ,dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=SN>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=SN>', [BIO])) - CHARINDEX('<A name=SN>', [BIO])-11))) AS 'SN'
    ,dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=GN>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=GN>', [BIO])) - CHARINDEX('<A name=GN>', [BIO])-11))) AS 'GN'
    ,dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=HO>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=HO>', [BIO])) - CHARINDEX('<A name=HO>', [BIO])-11))) AS 'HO'
    ,dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=OC>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=OC>', [BIO])) - CHARINDEX('<A name=OC>', [BIO])-11))) AS 'OC'
    ,dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=PO>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=PO>', [BIO])) - CHARINDEX('<A name=PO>', [BIO])-11))) AS 'PO'
    ,dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=BD>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=BD>', [BIO])) - CHARINDEX('<A name=BD>', [BIO])-11))) AS 'BD'
    ,dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=PA>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=PA>', [BIO])) - CHARINDEX('<A name=PA>', [BIO])-11))) AS 'PA'
    ,dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=BY>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=BY>', [BIO])) - CHARINDEX('<A name=BY>', [BIO])-11))) AS 'BY'
    ,dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=ED>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=ED>', [BIO])) - CHARINDEX('<A name=ED>', [BIO])-11))) AS 'ED'
FROM [cww].[dbo].[Contacts]
ORDER BY CONTACT_ID

Результаты, которые я получаю, выглядят так:

CONTACT_ID  SN  GN  HO  OC  PO  DB  PA  BY  ED
3   AARON   Raymond Leonard B.Sc.   business coach, professional speaker, real estate entrepreneur  D>AARON
5   AATAMI  Pita    C.Q.    business executive; Kuujjuaq
7   ABBOTT  Anthony C.  P.C.    lawyer  Montreal
8   ABBOTT  Elizabeth   M.A.    historian   Ottawa
9   ABBOTT  (Caroline) Louise   D>ABBOTT    writer, photographer, filmmaker Montreal

Я могу продолжать и вручную добавлять все подстроки для каждого якоря с разными именами, но проблема в том, что я не знаю всех «имен», которые используются в якорях, и в этой таблице содержится более 22 000 записей что я должен был бы просмотреть, чтобы убедиться, что я поймаю их всех. Кроме того, не все BIO имеют все привязки, поэтому, если вы посмотрите на результат для 'ABBOTT (Caroline) Louise', у нее нет привязки 'HO', поэтому она возвращает неверные данные 'D> ABBOTT', а у меня нет Я видел это еще с ограниченными результатами, которые я привожу, но у некоторых записей есть несколько якорей, таких как 2 'HO, которые, я думаю, вызовут проблемы ..

Еще одна проблема заключается в том, что не все имена якорей состоят из 2 букв, поэтому 11, которые я использую в charindex, будет неправильным для этих ..

Есть ли лучший способ сделать это? Любая помощь будет оценена.

ОБНОВЛЕНИЕ - я добавил операторы CASE для удаления неверных данных, когда имя привязки не существует для текущей записи.

SELECT  CONTACT_ID
    ,'SN' = 
        CASE
            WHEN CHARINDEX('<A name=SN>', [BIO]) = 0 THEN NULL
            ELSE dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=SN>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=SN>', [BIO])) - CHARINDEX('<A name=SN>', [BIO])-11)))
        END     
    ,'GN' = 
        CASE
            WHEN CHARINDEX('<A name=GN>', [BIO]) = 0 THEN NULL
            ELSE dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=GN>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=GN>', [BIO])) - CHARINDEX('<A name=GN>', [BIO])-11)))
        END
    ,'HO' = 
        CASE
            WHEN CHARINDEX('<A name=HO>', [BIO]) = 0 THEN NULL
            ELSE dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=HO>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=HO>', [BIO])) - CHARINDEX('<A name=HO>', [BIO])-11)))
        END
    ,'OC' = 
        CASE
            WHEN CHARINDEX('<A name=OC>', [BIO]) = 0 THEN NULL
            ELSE dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=OC>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=OC>', [BIO])) - CHARINDEX('<A name=OC>', [BIO])-11)))
        END
    ,'PO' = 
        CASE
            WHEN CHARINDEX('<A name=PO>', [BIO]) = 0 THEN NULL
            ELSE dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=PO>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=PO>', [BIO])) - CHARINDEX('<A name=PO>', [BIO])-11)))
        END
    ,'BD' = 
        CASE
            WHEN CHARINDEX('<A name=BD>', [BIO]) = 0 THEN NULL
            ELSE dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=BD>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=BD>', [BIO])) - CHARINDEX('<A name=BD>', [BIO])-11)))
        END
    ,'PA' = 
        CASE
            WHEN CHARINDEX('<A name=PA>', [BIO]) = 0 THEN NULL
            ELSE dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=PA>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=PA>', [BIO])) - CHARINDEX('<A name=PA>', [BIO])-11)))
        END
    ,'BY' = 
        CASE
            WHEN CHARINDEX('<A name=BY>', [BIO]) = 0 THEN NULL
            ELSE dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=BY>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=BY>', [BIO])) - CHARINDEX('<A name=BY>', [BIO])-11)))
        END
    ,'ED' = 
        CASE
            WHEN CHARINDEX('<A name=ED>', [BIO]) = 0 THEN NULL
            ELSE dbo.udf_StripHTML(SUBSTRING([BIO], (CHARINDEX('<A name=ED>', [BIO]) + 11), (CHARINDEX('</A>', [BIO], CHARINDEX('<A name=ED>', [BIO])) - CHARINDEX('<A name=ED>', [BIO])-11)))
        END
--INTO [cww].[dbo].[BioDetails]
FROM [cww].[dbo].[Contacts]
ORDER BY CONTACT_ID

Ответы [ 2 ]

0 голосов
/ 14 июля 2011

Я не знаю, как вы можете сделать это чисто в T-SQL

Если вы можете извлечь столбцы CONTACT_ID и BIO в приложение, вы можете выполнить итерацию по результирующему набору, проанализировать данные BIO как XML, а затем использовать XPath для получения значения атрибута name и тела привязки, создаваякарта данных для вставки в вашу новую таблицу.Поскольку вы не знаете всех различных имен, которые могли бы существовать, вам, вероятно, нужно будет воссоздавать таблицу каждый раз, когда она запускается, поэтому сохраняйте имена, найденные в множестве, и после итерации по всем строкам используйте набор для генерации create table Statement.

Код БД - это просто фантазия, но вот фрагмент, показывающий, как это можно сделать с помощью библиотеки XOM XML для Java.Я не уверен, что это сработает, поскольку значения ваших атрибутов не заключены в кавычки, но вы можете найти синтаксический анализатор, который не слишком требователен, и я уверен, что вы могли бы сделать нечто подобное в .NET.

ResultSet results = db.query("select CONTACT_ID, BIO from [cww].[dbo].[Contacts]");

Set<String> newTableColumns = new Set<String>();
newTableColumns.put("CONTACT_ID");

List<Map<String,String> > dataToInsert = new ArrayList<Map<String,String> >();
Builder parser = new Builder();

for (ResultRow resultRow : results) { // iterate over the result set

    Map<String,String> rowDataToInsert = new HashMap<String,String>();
    rowData.put("CONTACT_ID", resultRow.get("CONTACT_ID"));

    // parse the BIO data as an XML document
    Document doc = parser.build(resultRow.get("BIO"), "");

    // query the document using XPath
    Nodes namedAnchors = doc.query("//a[@name]");

    for (int nItr = 0; nItr < namedAnchors.size(); nItr++) {

        Element anchor = (Element) namedAnchors.get(nItr);
        String name = anchor.getAttributeValue("name");
        String anchorBody = anchor.getValue();

        newTableColumns.put(name);
        rowDataToInsert.put(name, anchorBody);

    }

    // we've stored all the anchor data from this row, so put it away
    dataToInsert.add(rowDataToInsert);
}

// create your table
db.createTable("NEW_TABLE_NAME", newTableColumns);

// insert into your new table
db.batchInsert("NEW_TABLE_NAME", dataToInsert);
0 голосов
/ 14 июля 2011

Я бы создал таблицу с contact_id, типом и значением привязки, проанализировал бы данные и добавил к ним записи, а затем выплюнул их с помощью кросс-таблицы.Это позволит вам легко найти все типы якорей, использовать несколько типов якорей / нет и т. Д.

Вам также может потребоваться несколько проходов данных или рассмотреть возможность использования инструментов, которые не установлены в основном.на основе (как SQL), например, c #.

...