根据日期显示选择费率

时间:2012-09-13 02:28:02

标签: sql postgresql case

我正在尝试根据正在搜索的星期几从表中选择2个速率列中的1个。我试图为这个查询使用两个表:一个日历表(表名=日历,列名= caldates),这是一个严格的日期列表,其中每一行是2012-06-30和2014-05-31之间的日期。我还有另一个表(表名=费率)有4列:start_date,end_date,weekday_rate和weekend_rate。

Start_date      end_date     weekday_rate     weekend_rate
"2012-05-01"  "2012-06-30"        69              150
"2012-07-01"  "2012-08-31"        74              200
"2012-09-01"  "2012-11-14"        75              210
"2012-11-15"  "2013-01-31"        90              150

执行查询时,系统需要查找正确的费率。现在我的查询看起来像这样:

SELECT  
    CASE cast(extract(dow from caldates) as int)
    WHEN '0'  then (select weekday_rate from rates)
    WHEN '1'  then (select weekday_rate from rates)
    WHEN '2'  then (select weekday_rate from rates)
    WHEN '3'  then (select weekday_rate from rates)
    WHEN '4'  then (select weekday_rate from rates)
    WHEN '5'  then (select weekend_rate from rates)
    When '6'  then (select weekend_rate from rates)
    End AS the_date_rate
FROM calendar WHERE caldates >= '2012-08-30' and  caldates <=  '2012-09-04' ;

当我运行查询时,收到错误“错误:用作表达式的子查询返回的多行。”

我希望输出显示日期范围以及与日期相关的费率。上面的例子看起来像

caldates        the_date_rate
2012-08-30           74
2012-08-31           200
2012-09-01           210
2012-09-02           75
2012-09-03           75
2012-09-04           75

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

这可以大大简化。

SELECT d.day
      ,CASE WHEN extract(isodow from d.day) < 6
         THEN weekday_rate
         ELSE weekend_rate
       END AS rate
FROM  (SELECT generate_series('2012-06-30'::date
                             ,'2014-05-31'::date, '1d'::interval)::date AS day
      ) d
LEFT   JOIN rates r ON d.day BETWEEN r.start_date AND r.end_date
ORDER  BY d.day

重点

  • 对于PostgreSQL中无间隙的一系列日期,您不需要calendar表。请改为使用generate_series()代替。

  • 您需要加入rates表。目前接受的答案根本不起作用。

  • 我使用的是LEFT JOIN,所以没有匹配率的日子仍然会以NULL为结果。

  • 目前接受的答案将星期日视为工作日,星期五视为周末。我不认为这是预期的。
    使用extract(isodow FROM source)只有两种情况,CASE语句也可以简单得多。

  • 您无需将extract()的结果投射到integer。我们比较的文字将自动转换为匹配类型double precision

答案 1 :(得分:0)

这就足够了(同时看看你是否真的需要在when子句之后的星期日值附近引用):

SELECT  
    CASE 
        WHEN cast(extract(dow from caldates) as int) < 6  then weekday_rate
        ELSE weekend_rate
    End AS the_date_rate
FROM 
    calendar 
WHERE 
    caldates >= '2012-08-30' and  caldates <=  '2012-09-04' ;