如何将GETDATE()函数与xml exist()函数一起使用

时间:2018-07-16 13:55:28

标签: sql xml

我有一种情况,我必须在查询的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

我想根据计划日期过滤记录。 该查询是视图的一部分,因此我无法声明变量。

2 个答案:

答案 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())