硬编码日期有效,但在sql

时间:2019-12-16 19:34:46

标签: sql oracle

现在更好地提出我的问题。

我创建了一个查询,其中我要输入日期和日期。添加了valid_date列检查,因此它应该介于 from_date和to_date。如果有效日期没有任何值,则应检查此条件,如“ from_date”一样,以便查询仍然 给出结果以及其余的列详细信息。

当我传递硬编码值时:

AND To_char(ppa.effective_date(+), 'YYYY-MM-DD') BETWEEN '2019-09-01' AND '2019-11-02'

这给了我正确的结果。但是当我使用以下条件时:

AND To_char(Nvl(ppa.effective_date(+), :p_from_date), 'YYYY-MM-DD') BETWEEN To_char( Nvl(:p_from_date, SYSDATE), 'YYYY-MM-DD') AND To_char ( Nvl(:p_TO_date, SYSDATE), 'YYYY-MM-DD')

我没有得到正确的结果。

总体查询为:

 SELECT * 
    FROM   (SELECT DISTINCT PAPF.person_number, 
                            paam.assignment_number, 
                            pprd.payroll_relationship_number, 
                            payf.payroll_name, 
                            ppa.payroll_action_id action_number, 
                            ppa.action_type, 
                           to_char( ppa.effective_date,'DD-MM-YYYY')  effective_date, 
                            PCS.consolidation_set_name, 
                            name.first_name, 
                            name.last_name 
            FROM   pay_payroll_actions PPA, 
                   pay_payroll_rel_actions PPRA, 
                   pay_pay_relationships_dn pprd, 
                   per_all_people_f PAPF, 
                   per_all_assignments_m PAAM, 
                   per_assignment_status_types_vl pasv, 
                   pay_payroll_assignments ppasg, 
                   pay_assigned_payrolls_dn papd, 
                   pay_all_payrolls_f payf, 
                   pay_consolidation_sets pcs, 
                   pay_time_periods ptp, 
                   per_legislative_data_groups_vl ldg, 
                   pay_payroll_terms pt, 
                   per_person_names_f name 
            WHERE  1 = 1 
                   AND pt.payroll_relationship_id = pprd.payroll_relationship_id 
                   AND papd.payroll_term_id = pt.payroll_term_id 
                   AND ( action_type IN ( 'Q', 'R' ) 
                          OR action_type IS NULL ) 
                   AND papf.person_id = name.person_id 
                   AND name.name_type = 'GLOBAL' 
                   AND paam.person_id = papf.person_id 
                   AND pprd.person_id = papf.person_id 
                   AND Trunc(SYSDATE) BETWEEN PAAM.effective_start_date AND 
                                       PAAM.effective_end_date 
                   AND PAAM.assignment_number NOT LIKE 'ET%' 
                   AND PAAM.assignment_type = 'E' 
                   AND paam.primary_flag = 'Y' 
                   AND pasv.assignment_status_type_id = 
                       paam.assignment_status_type_id 
                   --AND paam.assignment_status_type = 'ACTIVE' 
                   AND pasv.pay_system_status = 'P' 
                   AND ptp.payroll_id = payf.payroll_id 
                   AND ( finc > ptp.start_date 
                          OR finc IS NULL ) 
                   AND PTP.period_category = 'E' 
                   AND ppa.payroll_action_id(+) = ppra.payroll_action_id 
                   AND ppra.payroll_relationship_id(+) = 
                       pprd.payroll_relationship_id  
                   **AND To_char(Nvl(ppa.effective_date(+), :p_from_date), 
                       'YYYY-MM-DD') 
                       BETWEEN 
                       To_char( 
                       Nvl(:p_from_date, SYSDATE), 'YYYY-MM-DD') AND To_char ( 
                           Nvl(:p_TO_date, SYSDATE), 'YYYY-MM-DD')** 
            ORDER  BY pprd.payroll_relationship_number DESC 
           --95278  
           ) 
    WHERE 1=1
    and action_type IS NULL 
and person_number = '67373'

如果有效日期为null的结果集应类似于:

PERSON_NUMBER PAYROLL_NAME ACTION_TYPE EFFECTIVE_DATE CONSOLIDATION_SET_NAME ASSIGNMENT_NUMBER PAYROLL_RELATIONSHIP_NUMBER ACTION_NUMBER
     67373       US Biweekly                            US_CONSOLIDATION_GROUP   E67373                  67373

如果我传递了硬编码值,则返回上面的查询。生效日期,action_type在同一表中。如果在传递的p_from_date中 并且p_to_date action_type为null,则查询应给出上述结果。

1 个答案:

答案 0 :(得分:0)

我假设ppa.effective_datedate。如果是这样,您真的想比较日期,而不是字符串。

要了解比较字符串时会发生什么样的隐形混乱,让我们只看一个表达式

To_char(Nvl(ppa.effective_date(+), :p_from_date), 'YYYY-MM-DD')

首先,我们必须评估nvl。为了做到这一点,我们必须首先将ppa.effective_date转换为字符串,以便比较相同的数据类型。由于它是隐式转换,因此我们必须使用会话的nls_date_format。这不仅意味着不同的会话和用户可能会遇到不同的行为,这还意味着仅查看代码的人将不知道您正在获得哪种行为。如果您使用默认的nls_date_format,则ppa.effective_date将转换为格式为“ DD-MON-RR”的字符串。在这种情况下,无论nvl是否为effective_dateNULL都将以不同的格式返回字符串。但是,也许您已将会话的nls_date_format更改为“ YYYY-MM-DD”,以便nvl返回相同格式的字符串,而不管effective_date是否为NULL。

完成nvl后,我们需要评估to_char。但是to_char不带字符串,只带日期。因此,我们需要将字符串从nvl(可能以不同的格式)到date进行另一次隐式转换,以将其传递给to_char。最好的情况是,我们采用一个字符串,使用会话的date隐式地将其强制转换为nls_date_format,以便使用提供的“ YYYY-MM-DD”将其显式转换为字符串。格式。根据您从nvl返回的内容以及会话的nls_date_format的实际情况,这可能会正确运行,也可能无法正确运行。

如果您查看属于between子句的两个表达式,则会遇到一系列类似的转换问题。然后您的between使用字符串比较语义而不是日期比较语义,因此,如果三个表达式之一返回意外字符串,则比较只是默默地执行您想要的操作,而不是抛出错误。

实际上,您要比较日期。因此,您想将参数转换为日期并进行比较。这样的事情(假设:p_from_date:p_to_date始终是“ yyyy-mm-dd”格式的字符串)

AND nvl( ppa.effective_date(+), to_date( :p_from_date, 'yyyy-mm-dd' ) ) 
      BETWEEN nvl( to_date( :p_from_date, 'yyyy-mm-dd' ), trunc(sysdate) )
          AND nvl( to_date( :p_to_date,   'yyyy-mm-dd' ), trunc(sysdate) )

由于date始终具有日期和时间成分,因此我想您要与trunc(sysdate)(今天午夜)进行比较,而不是与当前日期和时间进行比较。您可能希望今天的上限是晚上11:59:59,在这种情况下,您应该

AND nvl( ppa.effective_date(+), to_date( :p_from_date, 'yyyy-mm-dd' ) ) 
      BETWEEN nvl( to_date( :p_from_date, 'yyyy-mm-dd' ), trunc(sysdate) )
          AND nvl( to_date( :p_to_date,   'yyyy-mm-dd' ), trunc(sysdate+1) - interval '1' second )