我有一种情况,我必须在查询的where子句中使用xml exist()函数。我必须将xml中的日期与当前日期进行比较。当我尝试使用GETDATE()函数时,出现以下错误。
XML数据类型方法“存在”的参数1必须为字符串文字。
请考虑以下查询,以供参考。
SELECT
TRY_CONVERT(datetime,NULLIF(t.x.value('(./Expire)[1]','varchar(max)'), '')) as expiration_date
FROM VW_Analytics_Base_Facts(nolock) BaseFact
CROSS APPLY BaseFact.Fact.nodes ('/Fact/Grant') t(x)
WHERE TYPE = '/asset/portfolio/option'
AND BaseFact.Fact.exist('./Expire[(text()[1] cast as xs:date?) le xs:date("' + CONVERT(NVARCHAR(max),CONVERT(date,GETDATE()))+'")]')=1
谢谢。
下面是更新的工作查询。
DECLARE @tbl TABLE (XmlCol xml)
INSERT INTO @tbl VALUES
('<option>
<OptionName>Option 1</OptionName>
<grant>
<GrantName>Grant 1</GrantName>
<schedules>
<schedule>
<scheduleID></scheduleID>
<scheduleName></scheduleName>
<scheduleDate>1/1/2018</scheduleDate>
<scheduleAmount></scheduleAmount>
</schedule>
<schedule>
<scheduleID></scheduleID>
<scheduleName></scheduleName>
<scheduleDate>2/1/2018</scheduleDate>
<scheduleAmount></scheduleAmount>
</schedule>
<schedule>
<scheduleID></scheduleID>
<scheduleName></scheduleName>
<scheduleDate>3/1/2018</scheduleDate>
<scheduleAmount></scheduleAmount>
</schedule>
</schedules>
</grant>
<grant>
<GrantName>Grant 2</GrantName>
<schedules>
<schedule>
<scheduleID></scheduleID>
<scheduleName></scheduleName>
<scheduleDate>1/1/2019</scheduleDate>
<scheduleAmount></scheduleAmount>
</schedule>
<schedule>
<scheduleID></scheduleID>
<scheduleName></scheduleName>
<scheduleDate>2/1/2019</scheduleDate>
<scheduleAmount></scheduleAmount>
</schedule>
<schedule>
<scheduleID></scheduleID>
<scheduleName></scheduleName>
<scheduleDate>3/1/2019</scheduleDate>
<scheduleAmount></scheduleAmount>
</schedule>
</schedules>
</grant>
</option>'
)
SELECT e.XmlCol.value('(/option/OptionName)[1]', 'varchar(100)'),
t.x.value('../.././GrantName[1]','varchar(100)') GrantName,
t.x.value('(./scheduleDate)[1]', 'varchar(100)') scheduleDate
FROM @tbl e
CROSS APPLY (SELECT CONVERT(date,GETDATE())) dt(today)
cross apply e.XmlCol.nodes ('/option/grant/schedules/schedule') t(x)
WHERE e.XmlCol.exist('./scheduleDate[(text()[1] cast as xs:date?) le sql:column("dt.today")]')=1
我想根据计划日期过滤记录。 该查询是视图的一部分,因此我无法声明变量。
答案 0 :(得分:1)
下次,请附加一个独立工作样本,其中包含DDL,数据插入,您自己的代码和预期的输出。这样可以测试解决方案。
在这种情况下,我必须猜测并发布未经测试的内容:
SELECT
TRY_CONVERT(datetime,NULLIF(t.x.value('(./Expire)[1]','varchar(max)'), '')) as expiration_date
FROM VW_Analytics_Base_Facts(nolock) BaseFact
CROSS APPLY (SELECT CONVERT(date,GETDATE())) dt(today)
CROSS APPLY BaseFact.Fact.nodes ('/Fact/Grant') t(x)
WHERE TYPE = '/asset/portfolio/option'
AND BaseFact.Fact.exist('./Expire[(text()[1] cast as xs:date?) le sql:column("dt.today")]')=1;
此查询将再使用CROSS APPLY
以便将信息包括在结果集中。函数sql:column()
允许在XQuery
中使用结果集的列,而不会违反必须是文字规则(使用sql:variable()
声明的变量的值)。
您尽早使用过滤器的想法没有错。作为.nodes()
中的谓词甚至更好。但是您必须依靠隐式转换,这是您不应该做的事情。
表达式(text()[1] cast as xs:date?)
将使用系统的区域性。像1/3/2018
这样的值可能会被视为3月1日或1月3日。因此,我建议将值读取为字符串,并以适当的样式使用CONVERT
:
顺便说一句:我使用两次CROSS APPLY
和.nodes()
来避免向后导航(../../
)
WITH DerivedTable AS
(
SELECT e.XmlCol.value('(/option/OptionName/text())[1]', 'varchar(100)') AS OptionName
,gr.value('(GrantName/text())[1]','varchar(100)') GrantName
,sch.value('(scheduleID/text())[1]', 'varchar(100)') scheduleID --use appropriate type, might be "int"
,sch.value('(scheduleName/text())[1]', 'varchar(100)') scheduleName
,CONVERT(DATE,sch.value('(scheduleDate/text())[1]', 'varchar(100)'),110) scheduleDate --fetch this as varchar, to avoid implicit casts
--use CONVERT with the appropriate style to get a real date
--110 is mdy, 103 is dmy
,sch.value('(scheduleAmount/text())[1]', 'varchar(100)') scheduleAmount --use appropriate type, might be "decimal(12,4)"
FROM @tbl e
CROSS APPLY e.XmlCol.nodes ('/option/grant') A(gr)
CROSS APPLY A.gr.nodes('schedules/schedule') B(sch)
)
SELECT dt.*
FROM DerivedTable dt
--use a simple WHERE here
这将返回XML的内容作为派生表。使用简单的WHERE
过滤此派生表。
答案 1 :(得分:0)
下面是为我工作的工作。
SELECT e.XmlCol.value('(/option/OptionName)[1]', 'varchar(100)') OptionName,
t.x.value('../.././GrantName[1]','varchar(100)') GrantName,
t.x.value('(./scheduleDate)[1]', 'varchar(100)') scheduleDate
FROM @tbl e
CROSS APPLY e.XmlCol.nodes ('/option/grant/schedules/schedule') t(x)
WHERE TRY_CONVERT(datetime,NULLIF(t.x.value('(./scheduleDate)[1]','varchar(max)'), '')) BETWEEN CONVERT(date,GETDATE()) AND DATEADD(YEAR, 1, GETDATE())