user897645
user897645

Reputation: 95

XQuery with dynamic XPath from XML Sql Server Column

I have a log table has xml column which contains log contents

There is also table called logType which is the type of log

I need to create query descripes the xml contents as readable string

I added a column with name logXPath to logtype table

and i created the following query

SELECT   contents.value(LogXPath, 'nvarchar(max)')
FROM    dbo.Log 
        JOIN dbo.LogType ON dbo.Log.logTypeID = dbo.LogType.logTypeID

and I got the following error

The argument 1 of the XML data type method "value" must be a string literal

and I searched for a way to do this with no results!!

Is there any do dynamic xpath in Sql Server XML Column?

Edit

for example assume the following schema and data

CREATE TABLE [dbo].[logType]
    (
      [logTypeID] [int] NOT NULL ,
      [logTypeName] [nvarchar](50) NOT NULL ,
      [xPath] [nvarchar](MAX) NOT NULL ,
      CONSTRAINT [PK_logType] PRIMARY KEY CLUSTERED ( [logTypeID] ASC )
    )

GO
INSERT  [dbo].[logType]
        ( [logTypeID] ,
          [logTypeName] ,
          [xPath]
        )
VALUES  ( 1 ,
          N'Patient Data' ,
          N'(/Patient/PatientName)[1]'
        )
INSERT  [dbo].[logType]
        ( [logTypeID] ,
          [logTypeName] ,
          [xPath]
        )
VALUES  ( 2 ,
          N'Clinic Data' ,
          N'(/Clinic/ClinicName)[1]'
        )
/****** Object:  Table [dbo].[log]    Script Date: 02/04/2015 13:58:47 ******/
GO
CREATE TABLE [dbo].[log]
    (
      [logID] [int] NOT NULL ,
      [logTypeID] [int] NOT NULL ,
      [Contents] [xml] NULL ,
      CONSTRAINT [PK_log] PRIMARY KEY CLUSTERED ( [logID] ASC )
    )
GO
INSERT  [dbo].[log]
        ( [logID] ,
          [logTypeID] ,
          [Contents]
        )
VALUES  ( 1 ,
          1 ,
          N'<Patient><PatientID>1</PatientID><PatientName>john</PatientName></Patient>'
        )
INSERT  [dbo].[log]
        ( [logID] ,
          [logTypeID] ,
          [Contents]
        )
VALUES  ( 2 ,
          2 ,
          N'<Clinic><ClinicID>1</ClinicID><ClinicName>Clinic 1</ClinicName></Clinic>'
        )

When I make query like the following ,it gives me the error

SELECT  logTypeName ,
        [Contents].value(dbo.logType.xPath, 'nvarchar(max)') AS data
FROM    dbo.[log]
        JOIN dbo.logType ON dbo.[log].logTypeID = dbo.logType.logTypeID

Upvotes: 2

Views: 2763

Answers (3)

Mark Ward
Mark Ward

Reputation: 11

Okay, so this has been here a while (a year), but this might be helpful...

A VERY helpful TABLE function: http://beyondrelational.com/modules/2/blogs/28/posts/10495/xquery-lab-58-select-from-xml.aspx

Using that function, you can get the values you're after something like this:

Select l.Contents, t.XPath, x.Value
  From [log] l With (NoLock)
 Inner Join [LogType] t With (NoLock)
         on t.LogTypeID=l.LogTypeID
 CROSS APPLY XMLTable(l.Contents) AS x
 Where REPLACE(REPLACE(REPLACE(t.XPath,'[1]',''),'(',''),')','')=REPLACE('/'+x.XPath,'[1]','')

Upvotes: 1

Mikael Eriksson
Mikael Eriksson

Reputation: 138960

You can build a query dynamically using the table LogType.

declare @SQL nvarchar(max);

set @SQL = 'select case L.logTypeID'+
            (
            select ' when '+cast(LT.logTypeID as varchar(11))+
                     ' then L.Contents.value('''+LT.xPath+''', ''nvarchar(max)'')'
            from LogType as LT
            for xml path('')
            )+' end as Name from dbo.[Log] as L;';

exec (@SQL);

It will give you a query that looks like this:

select case L.logTypeID 
         when 1 then L.Contents.value('(/Patient/PatientName)[1]', 'nvarchar(max)')
         when 2 then L.Contents.value('(/Clinic/ClinicName)[1]', 'nvarchar(max)') 
       end as Name 
from dbo.[Log] as L;

Upvotes: 1

nativehr
nativehr

Reputation: 1161

SQL Server does not allow replacing entire XPath expression with a variable, but you can use sql:variable and sql:column extensions inside the expression (I can't say how exactly without seeing your xml structure and what information you want to query from XML column).

Or, as mentioned above, you can use dynamic SQL:

DECLARE @xpath NVARCHAR(MAX);
SET @xpath = ... //Calculate xpath expression here

DECLARE @sql NVARCHAR(MAX);
SET @sql = N'SELECT contents.value(''' + @xpath + ''', ''NVARCHAR(MAX)''
             FROM dbo.Log 
             JOIN dbo.LogType ON dbo.Log.logTypeID = dbo.LogType.logTypeID';

EXEC sp_executesql @sql;

Upvotes: 0

Related Questions