2012-07-20 46 views
1

我有一個表,其中nvarchar(max)列可能包含已知結構的xml。我想分析它執行一些聚合,所以需要過濾掉「壞」條目。下面是測試例:視圖的嵌套查詢中的計算列

create table TestTable ([Message] nvarchar(max)) 
insert into TestTable ([Message]) values 
    ('<root m="1"/>'), 
    ('<root m="7"/>'), 
    ('<rooo') 
go 

set quoted_identifier on 
go 

create view TestView as 
select data.value('(/root/@m)[1]', 'int') as MyValue 
from (
    select cast([Message] as xml) as data 
    from (
     select [Message] from dbo.TestTable where [Message] like '<root%>' 
    ) as T1 
) as T2 
where data.exist('/root') = 1 
go 

select * from TestView 

這產生:

消息9400,級別16,狀態1,行1周的XML分析:行1,字符5, 輸入意外結束

我不明白爲什麼,因爲我辦的嵌套查詢:

select cast([Message] as xml) as data 
    from (
     select [Message] from dbo.TestTable where [Message] like '<root%>' 
    ) as T1 

它完美地返回2個有效行。爲什麼??

p.s. Microsoft Windows Server 2008(SP3) - 10.0.5500.0(X64)Sep 21 2011 22:45:45 Copyright(c)1988-2008 Windows NT 6.1上的Microsoft Corporation Express Edition(64位)(Build 7601:Service Pack 1 )

+0

SQL Server可以重新排序表達式所以沒有保證的'其中[信息]像「」'首先發生。您需要將潛在有問題的表達式放在'CASE'語句中 – 2012-07-20 11:59:13

+0

可能的重複[TSQL除以零而遇到儘管沒有包含0的列](http://stackoverflow.com/questions/5191701/tsql-divide-by-零遇到儘管沒有列包含0) – 2012-07-20 12:00:52

+0

如果這打破了選擇語義,這怎麼可能?我的查詢可以以某種方式重寫,以實現我所需要的功能嗎? – UserControl 2012-07-20 12:18:21

回答

1

你的問題不是SELECT子句中,但在where子句:

where data.exist('/root') = 1 

我懷疑你在想:「啊哈!如果XML的格式不正確,那麼這將返回0或NULL」。不,這個函數 - 和其他xml函數一樣 - 需要有效的xml。或者它得到一個錯誤。

您可能也有興趣SQL Server: inline conditional convert with XML?In SQL Server, what is the best way to determine if a given string is a valid XML or not?

似乎沒有一種簡單的方法來做你想做的事情。但是,您可能可以對原始字符串進行簡單檢查,以查看它是否合理xml。例如,下面的檢查是否存在相等數目的「<」和「>」:

select (case when len(replace(val, '<', '')) = len(replace(val, '>', '')) 
      then 'MAYBE OKAY' 
      else 'NOPE' 
     end) 
from (select '<badness' as val) t