2014-11-05 61 views
2

我有一個SQL Server 2014中的數據庫表,只有ID列(int)和XML類型的列xmldataSQL Server 2014 - XQuery - 獲取逗號分隔列表

xmldata列包含例如:

<book> 
    <title>a nice Novel</title> 
    <author>Maria</author> 
    <author>Peter</author> 
</book> 

正如預期的那樣,我必須多本書籍,因此與xmldata多行。

我現在要對所有書籍執行查詢,其中Peter是作者。我在一些xPath2.0測試人員嘗試了這一點,得出如下結論:

/book/author/concat(text(), if(position() != last())then ',' else '') 

工作。

如果試圖端口這一成功到SQL Server 2014次特快它看起來像這樣,這是正確轉義語法等:

SELECT id 
FROM books 
WHERE 'Peter' IN (xmldata.query('/book/author/concat(text(), if(position() != last())then '','' else '''')')) 

的SQL Server但似乎不支持像建設由於/concat(...)的:

不支持XQuery語法'/ function()'。

我很茫然,然後但是,爲什麼會/text()工作:

SELECT id, xmldata.query('/book/author/text()') 
FROM books 

它一樣。

我的約束:

  • 我一定要使用SQL Server
  • 我一定要XPath或別的東西可「注入」如上聲明(如果XML或結構數據庫的變化,上面的XPath可以改變隔離及以上的應用程序邏輯構建Where條款將不被感動)請參閱編輯

有沒有辦法讓這個WOR K +

問候,

BillDoor

編輯:

我的第二個制約因素歸結爲:

應用程序通過

expression <operator> value(s) 
01構建Where子句

表達存儲在數據庫中,並且由例如xmlTag:

| tokenname| querystring 
    | "author" | "xmldata.query(/book/author/text())" 

值由所述請求用戶呈現映射。所以如果用戶請求作者「Peter」與操作符「EQUALS」,則應用程序構造如下:

xmaldata.query(/book/author/text()) = "Peter" 

作爲where子句。

如果客戶現在決定作者需要嵌套在<authors>元素中,我可以簡單地更改構造數據庫中的表達式,並且整個機器可以在沒有對代碼進行任何更改的情況下繼續運行,只需管理即可。

所以我需要一種方法來實現這一

<xPath> <operator> "Peter" 

或這三個孤立的組件的任何其他組合(見上:"Peter" IN <xPath>...)讓我所有的彼得斯的書,即使有多個未分類作者。

這是不夠或者(它不是SQLSERVER語法,但你的想法):

WHERE xmldata.exist('/dossier/client[text() = "$1"]', "Peter") = 1; 

因爲運營商仍然是嵌套在表達,我不能要求<> "Peter"

我知道這是奇怪的,請不要質疑這個概念作爲一個整體 - 它有一個歷史:/

編輯:進一步澄清:

過濾規則來爲應用程序在XML結構基本上是:

  • 操作員: 「EQ」
  • 字段: 「名稱」
  • 值 「彼得」

的計算結果爲:

  • 表達= lookupExpressionForField("name") - > 「table2.xmldata.value( '書/作者/名稱[1]', 'VARCHAR')」
  • 運算符= lookUpOperatorMapping("EQ") - - > 「=」
  • 值= FormatValues("Peter") - > 「彼得」(如果有多個值被傳遞FormatValues cosntructs一個逗號分隔的列表)

應用程序然後構建: - constructClause(String expression,String operator,String value)

「table2.xmldata.value( '書籍/作者/名稱[1]', 'VARCHAR')」 + 「=」 + 「彼得」

然後構建一個SELECT語句的結果作爲WHERE子句。

它不會像這樣構建,未經過濾,未經過濾等等,但這是基本思想。

我可以影響輸入是如何Transalted,這意味着我可以實現的方法:

  • lookupExpressionForField(String field)
  • lookUpOperatorMapping(String operator)
  • Formatvalues(List<String> values) | Formatvalues(String value)
  • constructClause(String expression,String operator,String value)

但是我選擇做什麼,我可以改變參數類型,我可以自由地實現它們。當然越好越好。因此,簡單地用xPath構造逗號分隔列表將是最佳的(就像我可以在sqlserver中的某處打勾「enable/function() - xPath中的語法」)和/ concat(if ...)將工作)

+0

'/文()'是不是函數,即使它在語法上看起來像一個。 – choroba 2014-11-05 15:42:55

回答

2

怎麼是這樣的:

SET NOCOUNT ON; 

DECLARE @Books TABLE (ID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY, BookInfo XML); 

INSERT INTO @Books (BookInfo) 
VALUES (N'<book> 
    <title>a nice Novel</title> 
    <author>Maria</author> 
    <author>Peter</author> 
</book>'); 

INSERT INTO @Books (BookInfo) 
VALUES (N'<book> 
    <title>another one</title> 
    <author>Bob</author> 
</book>'); 

SELECT * 
FROM @Books bk 
WHERE bk.BookInfo.exist('/book/author[text() = "Peter"]') = 1; 

這僅返回的第一個「書」條目。從那裏你可以使用「值」功能提取XML字段的任何部分。

「存在」函數返回一個布爾值/ BIT。這將掃描「書籍」中的所有「作者」節點,因此不需要連接到僅用於IN列表的逗號分隔列表中,這不會起作用;-)。

有關「價值」和更多信息「存在」的功能,以及其他功能,用於處理XML數據的使用,請參閱:

xml Data Type Methods

+0

感謝您的解決方案,我添加了我的第二個約束的解釋 - 因爲它現在對我來說似乎也有點模糊^^。你的建議需要一些重大的改變,因爲這個值是表達式的一部分,並且缺少一個操作符(參見我的編輯)。如果您對此有任何進一步的想法,我請求您的幫助 - 但您的答案是至少要考慮的,再次感謝! – billdoor 2014-11-06 07:27:49

+0

@billdoor:好的,我看了一下這個問題的更新,他們需要更多的信息。 ''的可能值是多少?搜索字符串(當前是「Peter」)是否也是動態的?看起來你正在尋找一個動態的WHERE子句。 – 2014-11-06 16:10:12

+0

運算符可以是任何字符串(「=」,「IN」,「LIKE」,任何真正的),「Peter」是有問題的值,所以動態也是, – billdoor 2014-11-10 12:01:55