现在更好地提出我的问题。
我创建了一个查询,其中我要输入日期和日期。添加了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,则查询应给出上述结果。
答案 0 :(得分:0)
我假设ppa.effective_date
是date
。如果是这样,您真的想比较日期,而不是字符串。
要了解比较字符串时会发生什么样的隐形混乱,让我们只看一个表达式
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_date
,NULL
都将以不同的格式返回字符串。但是,也许您已将会话的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 )