如何在where子句中正确使用case

时间:2012-03-20 19:56:07

标签: sql oracle plsql

所以我有一个程序,我目前正在调试过程中,我已将其缩小到这个选择语句。

  

注意: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语句。

非常感谢任何帮助或建议。 谢谢。

3 个答案:

答案 0 :(得分:3)

您不需要在WHERE子句中设置任何变量,实际上即使您不能这样做。 您要做的是编写正确的逻辑谓词(即返回true或false的表达式),描述您想要获取的行。

以下是我将如何尝试定义它的两个示例(据我了解您的要求):

  1. 没有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 )
    
  2. 使用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)
    
  3. 我没有调试这个表达式,所以不要指望它们可以工作;),但我希望你有这个想法。

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