所以我有一个程序,我目前正在调试过程中,我已将其缩小到这个选择语句。
注意:to_date(''),3300,5220表示来自参数的内容。
现在假设要做的是取参数作为时间戳并减去偏移值
偏移量是自星期日午夜时间= 0以来经过的分钟数。(因此,如果是午夜的星期一,则偏移量将= 1440)。
当从参数中减去偏移量时,您将获得本周的开头。然后,您可以从已预先确定的表中获取偏移值,并将该值添加到星期的开头以获取时间戳。
这样做是为了获得班次的开始日期和结束日期。
我的原始代码在下面没有问题,但它缺少星期六进入星期日的边界条件。
SELECT SHIFT_ID_PK, SHIFT_NAME_FK,
SHIFT_START_DAY, SHIFT_START_TIME,
SHIFT_END_DAY, SHIFT_END_TIME,
SITE_ID_FK, SHIFT_DAY_ID,
STARTOFFSET, ENDOFFSET,
TO_TIMESTAMP_TZ(TO_CHAR((PSTARTTIMESTAMP - (VSTARTOFFSET / 24 / 60)) + (STARTOFFSET / 24 / 60), 'YYYY-MM-DD HH:MI:SS AM'), 'YYYY-MM-DD HH:MI:SS AM TZH:TZM') as SHIFT_START_DATE,
TO_TIMESTAMP_TZ(TO_CHAR((PENDTIMESTAMP - (VENDOFFSET / 24 / 60)) + (ENDOFFSET / 24 / 60), 'YYYY-MM-DD HH:MI:SS AM') ,'YYYY-MM-DD HH:MI:SS AM TZH:TZM') as SHIFT_END_DATE
from shift_tbl
WHERE
ENDOFFSET >= VSTARTOFFSET
and STARTOFFSET < VENDOFFSET
order by shift_start_date asc;
现在我已经提出来处理这个边界条件了,我已经在脚本中进行了测试。
declare
VSTARTOFFSET integer;
VENDOFFSET integer;
SHIFTOFFSET integer;
PSTARTTIMESTAMP timestamp;
PENDTIMESTAMP timestamp;
begin
VSTARTOFFSET := 10020;
VENDOFFSET := 420;
PSTARTTIMESTAMP := TO_DATE('3/17/2012 23:00', 'mm/dd/yyyy hh24:mi');
PENDTIMESTAMP := TO_DATE('3/18/2012 7:00', 'mm/dd/yyyy hh24:mi');
SELECT SHIFT_ID_PK, SHIFT_NAME_FK,
SHIFT_START_DAY, SHIFT_START_TIME,
SHIFT_END_DAY, SHIFT_END_TIME,
SITE_ID_FK, SHIFT_DAY_ID,
STARTOFFSET, ENDOFFSET,
TO_TIMESTAMP_TZ(TO_CHAR((PSTARTTIMESTAMP - (VSTARTOFFSET / 24 / 60)) + (STARTOFFSET / 24 / 60), 'YYYY-MM-DD HH:MI:SS AM'),'YYYY-MM-DD HH:MI:SS AM TZH:TZM') as SHIFT_START_DATE,
TO_TIMESTAMP_TZ(TO_CHAR((PENDTIMESTAMP- (VENDOFFSET / 24 / 60)) + (ENDOFFSET / 24 / 60), 'YYYY-MM-DD HH:MI:SS AM'),'YYYY-MM-DD HH:MI:SS AM TZH:TZM') AS SHIFT_END_DATE
from SHIFT_TBL
where
case
when SHIFT_START_DAY = 7 and SHIFT_END_DAY = 1 then
SHIFTOFFSET:= ENDOFFSET + 10080;
and VENDOFFSET := VENDOFFSET + 10080;
else
SHIFTOFFSET := ENDOFFSET;
end
SHIFTOFFSET >= VSTARTOFFSET
and STARTOFFSET < VENDOFFSET
order by SHIFT_START_DATE asc;
end;
正如您所看到的,我不确定如何处理where子句中的case语句。基本上我想要做的是如果开始日是星期六而结束日是星期日,那么将10080(一周)添加到结束偏移/ vend偏移量,如果它不符合该条件,则使用原始值。
基本上我的问题很简单......我相信但是我很难获得解决方案。所以我想知道的是如何在where子句中正确使用case语句。如果我不想在where子句中使用这种形式的case语句我将如何设置这个select语句。
非常感谢任何帮助或建议。 谢谢。
答案 0 :(得分:3)
您不需要在WHERE子句中设置任何变量,实际上即使您不能这样做。 您要做的是编写正确的逻辑谓词(即返回true或false的表达式),描述您想要获取的行。
以下是我将如何尝试定义它的两个示例(据我了解您的要求):
没有CASE:
WHERE
( SHIFT_START_DAY = 7 and SHIFT_END_DAY = 1 AND ENDOFFSET + 10080 >= VSTARTOFFSET and STARTOFFSET < VENDOFFSET + 10080) OR
( NOT (SHIFT_START_DAY = 7 and SHIFT_END_DAY = 1) AND SHIFTOFFSET >= VSTARTOFFSET and STARTOFFSET < VENDOFFSET )
使用CASE:
WHERE
(CASE WHEN SHIFT_START_DAY = 7 and SHIFT_END_DAY = 1 THEN ENDOFFSET + 10080 ELSE ENDOFFSET END) >= VSTARTOFFSET
AND STARTOFFSET < (CASE WHEN SHIFT_START_DAY = 7 and SHIFT_END_DAY = 1 THEN VENDOFFSET + 10080 ELSE VENDOFFSET END)
我没有调试这个表达式,所以不要指望它们可以工作;),但我希望你有这个想法。
答案 1 :(得分:0)
我建议不要尝试在WHERE子句中设置变量,而是将基本查询放入游标并使用它来循环驱动主查询。这将允许您为每次迭代设置查询之外的变量。它看起来像这样:
declare
--variables
cursor c_shifts is
select SHIFT_ID_PK, SHIFT_START_DAY, SHIFT_END_DAY
from SHIFT_TBL;
begin
for r_result in c_shifts
loop
if r_result.SHIFT_START_DAY = 1 and r_result.SHIFT_END_DAY = 7 then
--set variables to values for special case shifts
else
--set variables for all other cases
end if;
--run your query for the particular result in this loop iteration based upon r_result.SHIFT_ID_PK, using the variables you set above
--save results to a staging table, directly dbms_output from the block, etc., as needed
end loop;
--commit results if saving to a staging table, etc., as needed once the loop completes
end;
答案 2 :(得分:0)
不要计算,查询:)
建议:考虑使用auxiliary calendar table
我为什么要考虑使用辅助日历表?
日历表可以更容易地开发解决方案 任何涉及日期的商业模式。最后我查了一下,这个 对于某些人来说,几乎涵盖了你能想到的任何商业模式 学位。持续存在的问题最终需要冗长, 复杂而低效的方法包括以下问题:
x和y之间有多少个工作日?
3月的第二个星期二和4月的第一个星期五之间的所有日期是什么?
- ...
......也许是a column for julianized business days。