Search code examples
sql-serverxmlfilternodesxquery

XML XQuery Find sub nodes


I have a 20k line XML file in a SQL table with XML data type.

Below is subsection of the file.

I need to find all System nodes for a particular DF ID

Here is my query, the query returns all system nodes not the system nodes for DF Id=1.

select station, 
  x.y.value('@id[1]','int') AS DFR_Id,
  z.y.value('local-name(.)', 'nvarchar(128)') AS elem_name,
  z.y.value('text()[1]', 'nvarchar(max)') AS elem_text
from DME_Settings_Baseline e 
OUTER APPLY e.configxml.nodes('SubStation/DFs/DF') as X(Y)
OUTER APPLY e.configxml.nodes('SubStation/ DFs/DF/System/*') as Z(Y)
WHERE X.Y.value('@id[1]','int')=1'

<SubStation id="10" name="West">
<DFs>
<DF id="1">
  <IPAddress>155.100.1.1</IPAddress>
  <System>
    <DfrId>1</DfrId>
    <RecordingDeviceId>M9000</RecordingDeviceId>
    <SampleRate>4800</SampleRate>
    <LineFrequency>60</LineFrequency>
    <ExportRate>60</ExportRate>
    <ACount>56</ACount>
    <DigitalsCount>928</DigitalsCount>
    <PrefaultTime>500</PrefaultTime>
    <PostfaultTime>500</PostfaultTime>
    <LtrPrefaultTime>40</LtrPrefaultTime>
    <LtrPostfaultTime>40</LtrPostfaultTime>
    <ChatterLimit>20</ChatterLimit>
    <ChatterRate>2.0</ChatterRate>
    <TriggerLimit>500</TriggerLimit>
    <DatabaseDataType>BINARY</DatabaseDataType>
  </System>
</DF>
<DF id="2">
  <IPAddress>155.100.1.1</IPAddress>
  <System>
    <DfrId>2</DfrId>
    <RecordingDeviceId>M9000</RecordingDeviceId>
    <SampleRate>4800</SampleRate>
    <LineFrequency>60</LineFrequency>
    <ExportRate>60</ExportRate>
    <ACount>56</ACount>
    <DigitalsCount>928</DigitalsCount>
    <PrefaultTime>500</PrefaultTime>
    <PostfaultTime>500</PostfaultTime>
    <LtrPrefaultTime>40</LtrPrefaultTime>
    <LtrPostfaultTime>40</LtrPostfaultTime>
    <ChatterLimit>20</ChatterLimit>
    <ChatterRate>2.0</ChatterRate>
    <TriggerLimit>400</TriggerLimit>
    <DatabaseDataType>BINARY</DatabaseDataType>
    <Ps>S</Ps>
  </System>
</DF>

Solution

  • Please try the following.

    SQL

    -- DDL and sample data population, start
    DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, configxml XML);
    INSERT INTO @tbl (configxml) VALUES
    (N'<SubStation id="10" name="West">
        <DFs>
            <DF id="1">
                <IPAddress>155.100.1.1</IPAddress>
                <System>
                    <DfrId>1</DfrId>
                    <RecordingDeviceId>M9000</RecordingDeviceId>
                    <SampleRate>4800</SampleRate>
                    <LineFrequency>60</LineFrequency>
                    <ExportRate>60</ExportRate>
                    <ACount>56</ACount>
                    <DigitalsCount>928</DigitalsCount>
                    <PrefaultTime>500</PrefaultTime>
                    <PostfaultTime>500</PostfaultTime>
                    <LtrPrefaultTime>40</LtrPrefaultTime>
                    <LtrPostfaultTime>40</LtrPostfaultTime>
                    <ChatterLimit>20</ChatterLimit>
                    <ChatterRate>2.0</ChatterRate>
                    <TriggerLimit>500</TriggerLimit>
                    <DatabaseDataType>BINARY</DatabaseDataType>
                </System>
            </DF>
            <DF id="2">
                <IPAddress>155.100.1.1</IPAddress>
                <System>
                    <DfrId>2</DfrId>
                    <RecordingDeviceId>M9000</RecordingDeviceId>
                    <SampleRate>4800</SampleRate>
                    <LineFrequency>60</LineFrequency>
                    <ExportRate>60</ExportRate>
                    <ACount>56</ACount>
                    <DigitalsCount>928</DigitalsCount>
                    <PrefaultTime>500</PrefaultTime>
                    <PostfaultTime>500</PostfaultTime>
                    <LtrPrefaultTime>40</LtrPrefaultTime>
                    <LtrPostfaultTime>40</LtrPostfaultTime>
                    <ChatterLimit>20</ChatterLimit>
                    <ChatterRate>2.0</ChatterRate>
                    <TriggerLimit>400</TriggerLimit>
                    <DatabaseDataType>BINARY</DatabaseDataType>
                    <Ps>S</Ps>
                </System>
            </DF>
        </DFs>
    </SubStation>');
    -- DDL and sample data population, end
    
    SELECT t.c.value('@id','INT') AS DFR_Id,
        z.y.value('local-name(.)', 'NVARCHAR(128)') AS elem_name,
        z.y.value('text()[1]', 'NVARCHAR(MAX)') AS elem_text
    FROM @tbl AS e 
        CROSS APPLY e.configxml.nodes('/SubStation/DFs/DF') as t(c)
        CROSS APPLY t.c.nodes('System/*') as z(y)
    WHERE t.c.value('@id','INT')=1;
    

    Output

    +--------+-------------------+-----------+
    | DFR_Id |     elem_name     | elem_text |
    +--------+-------------------+-----------+
    |      1 | DfrId             | 1         |
    |      1 | RecordingDeviceId | M9000     |
    |      1 | SampleRate        | 4800      |
    |      1 | LineFrequency     | 60        |
    |      1 | ExportRate        | 60        |
    |      1 | ACount            | 56        |
    |      1 | DigitalsCount     | 928       |
    |      1 | PrefaultTime      | 500       |
    |      1 | PostfaultTime     | 500       |
    |      1 | LtrPrefaultTime   | 40        |
    |      1 | LtrPostfaultTime  | 40        |
    |      1 | ChatterLimit      | 20        |
    |      1 | ChatterRate       | 2.0       |
    |      1 | TriggerLimit      | 500       |
    |      1 | DatabaseDataType  | BINARY    |
    +--------+-------------------+-----------+