tags:

views:

44

answers:

4

Hi,

In my situation, xml data are saved in a text column, how to query this against this column? For example:

create table t1
(
    id INT IDENTITY(1, 1) PRIMARY KEY,
    content text
)


insert into t1(content) values ('<?xml version="1.0"?>
<people>
    <person>
        <firstName>ooo</firstName>
        <lastName>ppp</lastName>
    </person>
</people>
')
insert into t1(content) values ('<?xml version="1.0"?>
<people>
    <person>
        <firstName>mmm</firstName>
        <lastName>nnn</lastName>
    </person>
    <person>
        <firstName>aaa</firstName>
        <lastName>bbb</lastName>
    </person>
</people>
')
insert into t1(content) values ('<?xml version="1.0"?>
<people>
    <person>
        <firstName>aaa</firstName>
        <lastName>bbb</lastName>
    </person>
</people>
')

How to get all rows that have a person, whose first name is aaa and last name is bbb?


Edit:

I changed the insert statement a little, so that you can cast it to XML type directly.

Notes:

The content column is of type text, since it's an example to represent my actual problem. I'm working on a legacy project.

The second row and third row have a person whose first name is aaa and last name is bbb, I just need these rows.

A: 

Try this:

SELECT * FROM t1
WHERE content.value('(//firstName)[1]', 'varchar(MAX)') = 'aaa'
Dusty Roberts
I run the query, but get the following error:Msg 4121, Level 16, State 1, Line 1Cannot find either column "content" or the user-defined function or aggregate "content.value", or the name is ambiguous.
Yousui
It would work if the column was of type xml, rather than text (and the data type as the second argument was change to a varchar type). Is there a reason the column is text?
Damien_The_Unbeliever
@Damien, the use of `text` instead of `xml` or `nvarchar(max)` points to a non-SQL2005-database (either via server or via compatibility level), that's why I asked about the SQL Server version.
Lucero
@Lucero - well, the error message is from 2005 or 2008, so it could only be compatibility. (2000 wouldn't want a column with a dot immediately afterwards)
Damien_The_Unbeliever
@Damien, well spotted. Still the use of `text` is deprecated, so that something is strange in that question anyways. http://msdn.microsoft.com/en-us/library/ms187993(v=SQL.90).aspx
Lucero
A: 

Stealing Dusty's answer, then the following works, if you eliminate the new lines between the opening quotes and the xml declarations in your insert statements:

SELECT * FROM t1
WHERE CONVERT(xml,content).value('(//firstName)[1]', 'varchar(8000)') = 'aaa'
Damien_The_Unbeliever
Thank you. But if the person have a firstName aaa is not the first one on a row, then this query won't work.
Yousui
+1  A: 

The following should do:

SELECT
 *
FROM
(
    SELECT 
        CAST([content] AS XML) AS xmlcontent 
    FROM 
        t1
) det
WHERE 
xmlcontent.exist('//person[firstName[text()="aaa"] and lastName[text()="bbb"]]') = 1

I also added this entry to your set:

insert into t1(content) values ('<?xml version="1.0"?>
<people>
    <person>
        <firstName>ooo</firstName>
        <lastName>ppp</lastName>
    </person>
    <person>
        <firstName>aaa</firstName>
        <lastName>ppp</lastName>
    </person>
    <person>
        <firstName>ooo</firstName>
        <lastName>bbb</lastName>
    </person>
</people>
')

to show that if there is both a person matching the first name and a different person matching the last name, it does not count it as a match.

Locksfree
Thank you Locksfree. I just changed my insert statements to let you can cast it directly to xml. You use //firstName[1] to get the firstname, if the person which i need is not the first one in a row, this doesn't work. right?
Yousui
Yes it works. Thank you Lockfree!
Yousui
A: 

Here's a solution which uses variables for searching the content, so that you don't have to concatenate the exist query.

DECLARE @t1 table (
    id INT IDENTITY(1, 1) PRIMARY KEY,
    content xml
);
insert into @t1(content) values ('<?xml version="1.0"?>
<people>
    <person>
        <firstName>ooo</firstName>
        <lastName>ppp</lastName>
    </person>
</people>');
insert INTO @t1(content) values ('<?xml version="1.0"?>
<people>
    <person>
        <firstName>mmm</firstName>
        <lastName>nnn</lastName>
    </person>
    <person>
        <firstName>aaa</firstName>
        <lastName>bbb</lastName>
    </person>
</people>');
insert into @t1(content) values ('<?xml version="1.0"?>
<people>
    <person>
        <firstName>aaa</firstName>
        <lastName>bbb</lastName>
    </person>
</people>');

DECLARE @firstName nvarchar(50);
DECLARE @lastName nvarchar(50);
SELECT @firstName = 'aaa', @lastName = 'bbb';
SELECT * FROM @t1 t WHERE t.[content].[exist]('//person[firstName=sql:variable("@firstName") and lastName=sql:variable("@lastName")]')=1;
Lucero