SQL Проблема с обработкой узла XQuery SERVER - PullRequest
1 голос
/ 12 июля 2020

Мне нужно обработать данные из xml по дате операции, моделируя день за днем, в течение 4 месяцев обрабатывать в базе данных файл XML, который выглядит так:

<Operaciones_por_Dia>
  <OperacionDia fecha="2020-01-30">
    <PagoRecibo TipoRecibo="5" NumFinca="9782331"/>
    <PagoRecibo TipoRecibo="5" NumFinca="6696849"/>
    <TransConsumo id="1" LecturaM3="325" descripcion="Cobro Mensual" NumFinca="3336538"/>
    <TransConsumo id="3" LecturaM3="40" descripcion="Lectura errónea" NumFinca="2425954"/>
  </OperacionDia>
  <OperacionDia fecha="2020-04-08">
   <PagoRecibo TipoRecibo="7" NumFinca="1423800"/>
   <PagoRecibo TipoRecibo="7" NumFinca="1393022"/>
   <TransConsumo id="2" LecturaM3="22" descripcion="Reclamo de cliente" NumFinca="2101885"/>
  </OperacionDia>
</Operaciones_por_Dia>

Когда я подготавливаю данные, я сохраняю все даты из XML в таблицу переменных, а затем выполняю итерацию от минимальной даты до максимальной даты (@FechaOperacion сохранила эту дату), затем мне нужно обработать данные узла, где дата совпадает с датой узла xml.

Я пытаюсь это сделать, но @ Documento XML .value ('(/ Operaciones_por_Dia / OperacionDia / @ fecha) [1]', 'DATE' ) не совпадают, правильные данные, которые мне нужно сравнить, - это Fecha с @FechaOperacion, но я не знаю, как мне получить это значение с помощью Xquery.

INSERT @PagosHoy (NumFinca, TipoRecibo, Fecha)
        select ph.value('@NumFinca', 'INT')
            , ph.value('@TipoRecibo', 'INT')
            , ph.value('../@fecha', 'DATE')
        from @DocumentoXML.nodes('/Operaciones_por_Dia/OperacionDia/PagoRecibo') AS t(ph)
        where @DocumentoXML.value('(/Operaciones_por_Dia/OperacionDia/@fecha)[1]', 'DATE') = @FechaOperacion

С помощью следующего кода это работают хорошо, но я хочу знать, как это сделать, как и по-другому.

INSERT INTO @PagosHoy(NumFinca,TipoRecibo,Fecha)  
SELECT [NumFinca],[TipoRecibo],[fechaDeIngreso]
FROM OPENXML (@hdoc, 'Operaciones_por_Dia/OperacionDia/PagoRecibo',1)  
WITH (  [NumFinca]      VARCHAR(30) '@NumFinca',  
        [TipoRecibo]    INT         '@TipoRecibo',
        [fechaDeIngreso]    VARCHAR(100)    '../@fecha')
WHERE [fechaDeIngreso] = @FechaOperacion
EXEC spProcesaPagos @PagosHoy

Ответы [ 2 ]

2 голосов
/ 12 июля 2020

Проприетарный OPENXML Microsoft и сопутствующие ему sp_xml_preparedocument и sp_xml_removedocument сохранены только для обратной совместимости с устаревшим SQL Server 2000. Настоятельно рекомендуется переписать SQL и переключить его на XQuery. .

Вот еще один метод, аналогичный тому, что предлагает @AlwaysLearning, но более простой.

Он использует предикат XPath вместо предложения WHERE.

SQL

-- DDL and sample data population, start
DECLARE @PagosHoy TABLE (ID INT IDENTITY PRIMARY KEY, NumFinca INT, TipoRecibo INT, Fecha DATE);
DECLARE @xml XML = 
N'<Operaciones_por_Dia>
    <OperacionDia fecha="2020-01-30">
        <PagoRecibo TipoRecibo="5" NumFinca="9782331"/>
        <PagoRecibo TipoRecibo="5" NumFinca="6696849"/>
        <TransConsumo id="1" LecturaM3="325" descripcion="Cobro Mensual"
                      NumFinca="3336538"/>
        <TransConsumo id="3" LecturaM3="40" descripcion="Lectura errónea"
                      NumFinca="2425954"/>
    </OperacionDia>
    <OperacionDia fecha="2020-04-08">
        <PagoRecibo TipoRecibo="7" NumFinca="1423800"/>
        <PagoRecibo TipoRecibo="7" NumFinca="1393022"/>
        <TransConsumo id="2" LecturaM3="22" descripcion="Reclamo de cliente"
                      NumFinca="2101885"/>
    </OperacionDia>
</Operaciones_por_Dia>';
-- DDL and sample data population, end


DECLARE @FechaOperacion DATE = '2020-01-30';

INSERT @PagosHoy (NumFinca, TipoRecibo, Fecha)
SELECT c.value('@NumFinca', 'INT')
    , c.value('@TipoRecibo', 'INT')
    , @FechaOperacion AS FechaOperacion
FROM @xml.nodes('/Operaciones_por_Dia/OperacionDia[@fecha eq sql:variable("@FechaOperacion")]/PagoRecibo') AS t(c)

-- test
SELECT * FROM @PagosHoy;

Выход

+----+----------+------------+------------+
| ID | NumFinca | TipoRecibo |   Fecha    |
+----+----------+------------+------------+
|  1 |  9782331 |          5 | 2020-01-30 |
|  2 |  6696849 |          5 | 2020-01-30 |
+----+----------+------------+------------+
1 голос
/ 12 июля 2020

Предложение where в вашем первом примере запроса /Operaciones_por_Dia/OperacionDia/@fecha[1] независимо от запроса nodes('/Operaciones_por_Dia/OperacionDia/PagoRecibo'), поэтому всегда будет сравниваться @FechaOperacion с первым атрибутом даты, который в этом документе равен 2020-01-30.

declare @FechaOperacion date = convert(date, '2020-01-30', 120);
select
    ph.value('@NumFinca', 'INT'),
    ph.value('@TipoRecibo', 'INT'),
    ph.value('../@fecha', 'DATE')
from @DocumentoXML.nodes('/Operaciones_por_Dia/OperacionDia/PagoRecibo') AS t(ph)
where @DocumentoXML.value('(/Operaciones_por_Dia/OperacionDia/@fecha)[1]', 'DATE') = @FechaOperacion

В зависимости от значения @FechaOperacion он либо вернет все строки в документе (когда он совпадает), либо теперь строки вообще (когда это не так) ...

(No column name) (No column name) (No column name)
---------------- ---------------- ----------------
9782331          5                2020-01-30
6696849          5                2020-01-30
1423800          7                2020-04-08
1393022          7                2020-04-08

Решение состоит в том, чтобы запросить nodes('/Operaciones_por_Dia/OperacionDia'), а затем использовать перекрестный запрос для запроса дочерних узлов PagoRecibo.

declare @FechaOperacion date = convert(date, '2020-01-30', 120);
select
    ph.value('@NumFinca', 'INT'),
    ph.value('@TipoRecibo', 'INT'),
    od.value('@fecha', 'DATE')
from @DocumentoXML.nodes('/Operaciones_por_Dia/OperacionDia') AS s(od)
cross apply s.od.nodes('PagoRecibo') AS t(ph)
where s.od.value('@fecha', 'DATE') = @FechaOperacion

Что возвращает ...

(No column name) (No column name) (No column name)
---------------- ---------------- ----------------
9782331          5                2020-01-30
6696849          5                2020-01-30
...