web-dev-qa-db-ja.com

XML列セットの正確な値に対してクエリする方法

80以上のスパース列と列セット列を含むテーブルがあります。これは簡単な例です。

DROP TABLE IF EXISTS #ColumnSet
GO

CREATE TABLE #ColumnSet
(
    Id        INT          NOT NULL
  , Value1    VARCHAR(100) SPARSE NULL 
  , Value2    VARCHAR(100) SPARSE NULL 
  , Value3    VARCHAR(100) SPARSE NULL 
  , Value4    VARCHAR(100) SPARSE NULL 
  , AllValues XML COLUMN_SET FOR ALL_SPARSE_COLUMNS
)
GO

INSERT INTO #ColumnSet
(Id, Value1, Value2, Value3, Value4)

VALUES
(1, 'POSITIVE', NULL, NULL, NULL),
(2, 'NEGATIVE', NULL, 'NEGATIVE', NULL),
(3, NULL, NULL, 'NEGATIVE', 'POSITIVE'),
(4, 'NEGATIVE', NULL, 'THIS IS NOT A POSITIVE RESULT', NULL)
GO

列セットをクエリして、いずれかの列の値がPOSITIVEである行を特定します。

列セットでvalueメソッドを使用すると、すべての値が1つの文字列に連結され、LIKEを使用できますが、値が別の文字列内にある結果は必要ありません。

SELECT
    *

FROM
    #ColumnSet

WHERE
    AllValues.value('/', 'nvarchar(4000)') LIKE '%POSITIVE%'

上記を達成するために列セットをクエリする別の方法はありますか? APPLYnodesメソッドと一緒に使用すると、同じ連結文字列出力が提供されますが、構文が正しくない可能性があります。

必要な出力:

id
1
3
6
mheptinstall

述語の前にtext()ノードを指定すると、述語にtext()を指定するよりも効率的です。

_select *
from #ColumnSet as C
where AllValues.exist('*/text()[. = "POSITIVE"]') = 1
_

enter image description here


述語AllValues.exist('*[text() = "POSITIVE"]') = 1にテキストを含むクエリプラン

enter image description here

8
Mikael Eriksson

これがXPathソリューションですが、どれほど効率的かはわかりません。

SELECT *
FROM #ColumnSet
WHERE AllValues.exist('//*[text() = "POSITIVE"]') = 1
5
Forrest

これが別のxqueryソリューションです。

SELECT *, cs.AllValues.query('. [contains(., "POSITIVE")]')
FROM #ColumnSet AS cs
WHERE cs.AllValues.exist('. [contains(., "POSITIVE")]') = 1

サンプルデータを変更したため、上記は機能しません。

代わりにこれを行うことができます:

SELECT      cs.*
FROM        #ColumnSet AS cs
CROSS APPLY cs.AllValues.nodes('/*') AS x(c)
WHERE       x.c.exist('text()[. = "POSITIVE"]') = 1;

しかし、それがミカエルの答えと大規模にどのように競合するかはわかりません。

NUTS

4
Erik Darling