我必须通过格式化包含员工详细信息的xml来构建一个WHERE
子句来搜索员工。
我已将xml数据移动到临时表,并使用CTE
查询来获取每个节点描述。我面临的问题是将子元素分组为父级,必须为多个级别完成。
最终条件为Null的父元素必须填充子项的最终条件,直到顶层,如下面的屏幕截图所示。
请在下面找到sql查询和所需的输出:
DECLARE @SearchCriteriaXML XML
DECLARE @TempTable TABLE
(
ParentName NVARCHAR(250)
,LocalName NVARCHAR(250)
,FilterType NVARCHAR(MAX)
,Property NVARCHAR(250)
,Comparator NVARCHAR(250)
,ComparatorCondition NVARCHAR(250)
,ComparatorSign NVARCHAR(250)
,value NVARCHAR(MAX)
,InternalType NVARCHAR(MAX)
,FinalCondition NVARCHAR(MAX)
,Id int
,Parentid int
);
SET @SearchCriteriaXML =
N'<searchcriteria>
<filter type=''and''>
<filter type=''or''>
<filter type=''and''>
<condition property =''group'' comparator =''equals'' value=''Regional West Sales Team'' />
<condition property =''group'' comparator =''equals'' value=''Everyone Christmas 2016'' not=''true'' />
<filter type=''or''>
<condition property =''lastname'' comparator =''equals'' value=''John'' />
<condition property =''lastname'' comparator =''equals'' value=''Miller'' />
</filter>
<condition property =''State'' comparator =''equals'' value=''California'' />
</filter>
<filter type=''and''>
<condition property =''group'' comparator =''equals'' value=''Metro West Sales Team'' />
<condition property =''group'' comparator =''equals'' value=''Everyone Christmas 2016 1'' not=''true'' />
<filter type=''or''>
<condition property =''lastname'' comparator =''equals'' value=''John 1'' />
<condition property =''lastname'' comparator =''equals'' value=''Miller 1'' />
</filter>
<condition property =''State'' comparator =''equals'' value=''Virginia'' />
</filter>
</filter>
<condition property =''company'' comparator =''equals'' value=''Test Company'' />
</filter>
</searchcriteria>'
DECLARE @idoc int, @doc varchar(1000);
EXEC sp_xml_preparedocument @idoc OUTPUT, @SearchCriteriaXML;
--SELECT * into #temp
--FROM OPENXML (@idoc, 'searchcriteria//*')
;WITH CTE
AS(
-- SELECT stmt using OPENXML rowset provider
SELECT *
FROM OPENXML (@idoc, '/searchcriteria//*')
WITH
(
ParentName NVARCHAR(400) '@mp:parentlocalname'
,LocalName NVARCHAR(400) '@mp:localname'
,Prefix NVARCHAR(200) '@mp:prev'
,[type] NVARCHAR(100) '@type'
,[Internaltype] NVARCHAR(100) '../@type'
,[property] NVARCHAR(100) '@property'
,[comparator] NVARCHAR(250) '@comparator'
,[comparatorCondition] NVARCHAR(250) '@not'
,[value] NVARCHAR(250) '@value',
[id] int '@mp:id',
[parentid] int '@mp:parentid'
))
INSERT INTO @TempTable
SELECT ParentName,LocalName,[type] AS FilterType,property,comparator,[comparatorCondition],
CASE
WHEN comparator = 'equals' AND [comparatorCondition] = 'true' THEN '<>'
WHEN comparator = 'equals' THEN '='
WHEN comparator = 'greaterthan' THEN '>'
WHEN comparator = 'lessthan' THEN '<'
WHEN comparator = 'greaterthanorequal' THEN '>='
WHEN comparator = 'lessthanorequal' THEN '<='
END AS ComparatorSign
,value
,[Internaltype]
, NULL AS FinalCondition,
[id],
[parentid]
FROM CTE ORDER BY [parentid] DESC
UPDATE @TempTable SET
FinalCondition =
CASE WHEN LocalName = 'condition' THEN ISNULL(property,'') + ' ' + ISNULL(ComparatorSign,'') + ' '+ ''''+ISNULL(value,'')+'''' END
select * from @TempTable
;With EmployeeDetails (Id, ParentId, FilterType, FinalCondition, Level)
AS
(
SELECT Id, Parentid, FilterType, FinalCondition, Plevel = 1 FROM @TempTable WHERE Parentid = 0
UNION ALL
SELECT t.Id, t.Parentid, t.FilterType, t.FinalCondition,
Plevel = e.Level + 1 FROM @TempTable t INNER JOIN EmployeeDetails e on e.Id = t.ParentId
)
select * from EmployeeDetails
(company = 'Test Company') and
((group = 'Metro West Sales Team' and group <> 'Everyone Christmas 2016 1' and (lastname = 'John 1' or lastname = 'Miller 1') and State = 'Virginia') or
(group = 'Regional West Sales Team' and group <> 'Everyone Christmas 2016' and (lastname = 'John1' or lastname = 'Miller1') and State = 'California'))
答案 0 :(得分:0)
不确定是否可以使用单个递归查询完成此任务:
首先 - 你必须从下到上移动,而不是试图从上到下处理这个树(当你从where parentid = 0
的代码开始时。那是因为你不知道有多少个括号你必须在访问下一个(更低)级别之前打开。
从底部移动到顶部使得它变得更加容易 - 当处理特定级别的条件树时,您肯定可以使用括号来包含它。然后将其用作完整的代码块。
第二件事是你需要不加入关卡或构建树 - 你需要折叠所有嵌套元素以获得上层元素的组合代码。因此,正如您在示例递归代码中所述,您必须下降(或者从下往上移动时上升)到下一级并同时 - 聚合当前的所有嵌套级别。 / p>
像
这样的东西;with my_cte as
(
select a, b, c
from MyTable
where parentid is null
union all
select a, b, group_concat(t.c)
from MyTable t
inner join my_cte tt
on t.parent_id = tt.id
group by t.parent_id
)
或FOR XML
子查询,这些都不可能在SQL SERVER中使用递归CTE 。
现在,我尝试完成这项任务:
DECLARE @SearchCriteriaXML XML
DECLARE @TempTable TABLE
(
ParentName NVARCHAR(250)
,LocalName NVARCHAR(250)
,FilterType NVARCHAR(MAX)
,Property NVARCHAR(250)
,Comparator NVARCHAR(250)
,ComparatorCondition NVARCHAR(250)
,ComparatorSign NVARCHAR(250)
,value NVARCHAR(MAX)
,InternalType NVARCHAR(MAX)
,FinalCondition NVARCHAR(MAX)
,Id int
,Parentid INT
,processed BIT
);
SET @SearchCriteriaXML =
N'<searchcriteria>
<filter type=''and''>
<filter type=''or''>
<filter type=''and''>
<condition property =''group'' comparator =''equals'' value=''Regional West Sales Team'' />
<condition property =''group'' comparator =''equals'' value=''Everyone Christmas 2016'' not=''true'' />
<filter type=''or''>
<condition property =''lastname'' comparator =''equals'' value=''John'' />
<condition property =''lastname'' comparator =''equals'' value=''Miller'' />
</filter>
<condition property =''State'' comparator =''equals'' value=''California'' />
</filter>
<filter type=''and''>
<condition property =''group'' comparator =''equals'' value=''Metro West Sales Team'' />
<condition property =''group'' comparator =''equals'' value=''Everyone Christmas 2016 1'' not=''true'' />
<filter type=''or''>
<condition property =''lastname'' comparator =''equals'' value=''John 1'' />
<condition property =''lastname'' comparator =''equals'' value=''Miller 1'' />
</filter>
<condition property =''State'' comparator =''equals'' value=''Virginia'' />
</filter>
</filter>
<condition property =''company'' comparator =''equals'' value=''Test Company'' />
</filter>
</searchcriteria>'
DECLARE @idoc int, @doc varchar(1000);
EXEC sp_xml_preparedocument @idoc OUTPUT, @SearchCriteriaXML;
;WITH CTE AS(
SELECT *
FROM OPENXML (@idoc, '/searchcriteria//*')
WITH
(
ParentName NVARCHAR(400) '@mp:parentlocalname'
,LocalName NVARCHAR(400) '@mp:localname'
,Prefix NVARCHAR(200) '@mp:prev'
,[type] NVARCHAR(100) '@type'
,[Internaltype] NVARCHAR(100) '../@type'
,[property] NVARCHAR(100) '@property'
,[comparator] NVARCHAR(250) '@comparator'
,[comparatorCondition] NVARCHAR(250) '@not'
,[value] NVARCHAR(250) '@value',
[id] int '@mp:id',
[parentid] int '@mp:parentid'
)
)
INSERT INTO @TempTable(ParentName,
LocalName,
FilterType,
PROPERTY,
Comparator,
ComparatorCondition,
ComparatorSign,
VALUE,
InternalType,
FinalCondition,
Id,
Parentid)
SELECT
ParentName,
LocalName,[type] AS FilterType,property,comparator,[comparatorCondition],
CASE
WHEN comparator = 'equals' AND [comparatorCondition] = 'true' THEN '<>'
WHEN comparator = 'equals' THEN '='
WHEN comparator = 'greaterthan' THEN '>'
WHEN comparator = 'lessthan' THEN '<'
WHEN comparator = 'greaterthanorequal' THEN '>='
WHEN comparator = 'lessthanorequal' THEN '<='
END AS ComparatorSign
,value
,[Internaltype]
, NULL AS FinalCondition,
[id],
[parentid]
FROM CTE ORDER BY [parentid] DESC
UPDATE t SET
FinalCondition =
CASE WHEN LocalName = 'condition' THEN ISNULL(property,'') + ' ' + ISNULL(ComparatorSign,'') + ' '+ ''''+ISNULL(value,'')+'''' END
FROM @TempTable t
-- processing the lowest level
UPDATE t
SET FinalCondition = CAST( '(' AS VARCHAR(MAX)) + STUFF(
(
SELECT ' ' + REPLICATE(' ', 3 -LEN(tf.InternalType)) + tf.InternalType + ' ' + tf.FinalCondition
FROM @TempTable tf
WHERE tf.parentid = t.id
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)'), 1, 4, '') + ')',
Processed = 1
FROM @TempTable t
WHERE NOT EXISTS(
SELECT 1
FROM @TempTable t3
INNER JOIN @TempTable t2
ON t2.Parentid = t3.id
WHERE t3.Parentid = t.Id
)
AND t.FinalCondition IS NULL
-- moving from bottom to top of the condition tree
WHILE @@ROWCOUNT > 0
BEGIN
UPDATE t
SET FinalCondition = CAST('(' AS VARCHAR(MAX)) + STUFF(
(
SELECT ' ' + REPLICATE(' ', 3 -LEN(tf.InternalType)) + tf.InternalType + ' ' + tf.FinalCondition
FROM @TempTable tf
WHERE tf.parentid = t.id
AND tf.FinalCondition IS NOT NULL
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)'), 1, 4, '') + ')',
Processed = 1
FROM @TempTable t
WHERE t.FinalCondition IS NULL
AND NOT EXISTS(SELECT 1 FROM @TempTable tt WHERE tt.Parentid = t.Id AND tt.FinalCondition IS NULL)
END
SELECT FinalCondition
FROM @TempTable
WHERE Parentid = 0
我没有仔细审查所有可能和最有效的解决方案,但无论如何,主要的想法是: - 处理最低级别的条件树 - 转到上一级并组合/汇总较低级别的处理条件
所以最后的select
给出了:
(
(
( group = 'Regional West Sales Team' and group <> 'Everyone Christmas 2016' and ( lastname = 'John' or lastname = 'Miller') and State = 'California')
or ( group = 'Metro West Sales Team' and group <> 'Everyone Christmas 2016 1' and ( lastname = 'John 1' or lastname = 'Miller 1') and State = 'Virginia')
)
and company = 'Test Company'
)
当然,没有线刹和格式化。 请求的结果是:
(company = 'Test Company') and
((group = 'Metro West Sales Team' and group <> 'Everyone Christmas 2016 1' and (lastname = 'John 1' or lastname = 'Miller 1') and State = 'Virginia') or
(group = 'Regional West Sales Team' and group <> 'Everyone Christmas 2016' and (lastname = 'John1' or lastname = 'Miller1') and State = 'California'))
在逻辑上是相同的。