SQL Выбрать FOR XML в документ Solr - PullRequest
       10

SQL Выбрать FOR XML в документ Solr

4 голосов
/ 13 сентября 2011

Я пытаюсь получить оператор выбора SQL для генерации XML, соответствующего стандарту Solr.

Имеется таблица типа:

id | name
---------
 1 | one
 2 | two
 3 | three

Мне нужен результат, подобный (с корневым узлом или без него):

<add>
  <doc>
    <field name="id">1</field>
    <field name="name">one</field>
  </doc>
  <doc>
    <field name="id">2</field>
    <field name="name">two</field>
  </doc>
  <doc>
    <field name="id">3</field>
    <field name="name">three</field>
  </doc>
</add>

Можно ли сгенерировать эту структуру, используя запрос FOR XML, или мне понадобится XSLT или какой-то другой механизм для соответствия этой схеме?

Ответы [ 3 ]

5 голосов
/ 13 сентября 2011

Вот немного другой способ использования конструкторов.

DECLARE @sample TABLE
(
    [id]    int         NOT NULL,
    [name]  varchar(50) NOT NULL
);
INSERT INTO @sample ([id], [name])
SELECT 1, 'one' UNION ALL
SELECT 2, 'two' UNION ALL
SELECT 3, 'three';

SELECT
    CONVERT(xml, N'').query
    (N'
        <doc>
        {
            element field
            {
                attribute name {"id"},
                text{sql:column("id")}
            },
            element field
            {
                attribute name {"name"},
                text{sql:column("name")}
            }
        }
        </doc>
    ')
FROM
    @sample
FOR XML PATH(N''), ROOT(N'add');

* РЕДАКТИРОВАТЬ: Просто подумал о другом способе сделать это (но все еще требует знания столбцов заранее) * Опять же, я не уверен в последствиях для производительности любого из этих подходов.

SELECT
    (
        SELECT
            'id' AS [@name],
            [id] AS [data()]
        FOR XML PATH('field'), TYPE
    ) AS [*],
    (
        SELECT
            'name' AS [@name],
            [name] AS [data()]
        FOR XML PATH('field'), TYPE
    ) AS [*]
FROM
    @sample
FOR XML PATH(N'doc'), ROOT(N'add');

* ОБНОВЛЕНИЕ 2: Динамичный, но неэффективный метод, вдохновленный комментариями Аарона Бертрана *

Это было доказательством концепции метода, описанного в посте, на который Аарон ссылался в своих комментариях. (Это ужасно работает на больших наборах данных)

-- Inspired by Aaron Bertrand's comment
WITH [cte_KVP]
AS
(
    -- Generating Key/Value pairs for columns in a table
    -- Courtesey of Mikael Eriksson (http://stackoverflow.com/questions/7341143/flattening-of-a-1-row-table-into-a-key-value-pair-table/)
    SELECT
        [T2].[N].value(N'local-name(.)', N'sysname')    AS [Key],
        [T2].[N].value(N'.', N'nvarchar(max)')          AS [Value],
        [T2].[N].value(N'../GROUP[1]', N'int')          AS [GROUP] -- 3. Used for to group the key/value pairs per row
    FROM
        (
            SELECT
                *,
                ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [GROUP] -- 1. Generating a simple "identity" value.
            FROM
                @sample
            FOR XML PATH(N'Row'), TYPE -- 2. Adding the 'Row' to the path separates each row, and allows us to backtrack via xpath to get the "GROUP" id
        ) AS [T1]([x])
    CROSS APPLY
        [T1].[x].nodes(N'Row/*') AS [T2]([N])
    WHERE
        [T2].[N].value(N'local-name(.)', N'sysname') <> N'GROUP'
)
SELECT
    [InnerNodes].[xml] AS [*]
FROM
    (
        -- Probably preferable to use a table of numbers here
        SELECT DISTINCT
            [GROUP]
        FROM
            [cte_KVP]
    ) AS [Numbers]([Number])
CROSS APPLY
    (
        -- Generating the xml fragment specified by OP
        SELECT
            [cte_KVP].[Key]     AS [@name],
            [cte_KVP].[Value]   AS [data()]
        FROM
            [cte_KVP]
        WHERE
            [cte_KVP].[GROUP] = [Numbers].[Number]
        FOR XML PATH(N'field'), ROOT(N'doc'), TYPE
    ) AS [InnerNodes]([xml])
FOR XML PATH(N''), ROOT(N'add');
4 голосов
/ 13 сентября 2011

Это, вероятно, не так "естественно", как вы хотите, и если вы не знаете заранее названия столбцов, вам придется строить их динамически, но, похоже, вы получите документ, который вам нужен:*

SELECT 
    CONVERT(XML, '<field name="id">' + RTRIM(id) + '</field>'
    + '<field name="name">' + name + '</field>')
FROM dbo.[table]
FOR XML PATH(N'doc'), ROOT(N'add');

А вот и динамический подход:

DECLARE
    @table NVARCHAR(512) = N'dbo.[table]',
    @sql   NVARCHAR(MAX) = N'';

SELECT @sql += '
    + ''<field name="' + name 
    + '">'' + CONVERT(NVARCHAR(MAX), ' 
    + QUOTENAME(name) + ') + ''</field>'''
    FROM sys.columns 
    WHERE object_id = OBJECT_ID(@table);

SET @sql = 'SELECT CONVERT(XML, ' + STUFF(@sql, 1, 4, '')
    + ') FROM ' + @table 
    + ' FOR XML PATH(N''doc''), ROOT(N''add'');';

PRINT @sql;
-- EXEC sp_executesql @sql;
1 голос
/ 13 сентября 2011

Я предполагаю, что вы программируете на .NET, поскольку вы используете SQL Server. Если вы рассматривали возможность использования клиента SolrNet для загрузки документов на сервер Solr?

...