sql复制到月底的最新记录

Posted

技术标签:

【中文标题】sql复制到月底的最新记录【英文标题】:sql to replicate the latest record through the end of the month 【发布时间】:2015-05-01 17:55:38 【问题描述】:

我需要根据每种货币的最新交易生成截至月底的汇率。

例如,假设我们需要处理 2 天的汇率(该文件可能会带来 x 天的汇率),它们如下所示:

2015 年 4 月 25 日,英镑,美元,1.8 2015 年 4 月 25 日,美元,英镑,1.25 2015 年 4 月 26 日,英镑,美元,1.7346 2015 年 4 月 26 日,美元,英镑,1.1357

在此示例中,我需要在 4/26 获取两条记录并生成到月底的记录,因此输出需要如下所示:

2015 年 4 月 27 日,英镑,美元,1.7346 2015 年 4 月 28 日,英镑,美元,1.7346 2015 年 4 月 29 日,英镑,美元,1.7346 2015 年 4 月 30 日,英镑,美元,1.7346 2015 年 4 月 27 日,美元,英镑,1.1357 2015 年 4 月 28 日,美元,英镑,1.1357 2015 年 4 月 29 日,美元,英镑,1.1357 2015 年 4 月 30 日,美元,英镑,1.1357

我所做的是在 PLSQL 中的以下过程,但这似乎并没有像我预期的那样工作。

DECLARE 
 l_max_date date;

 CURSOR C1 IS
 SELECT         FROM_CURRENCY_DATE,
                FROM_CURRENCY,
                TO_CURRENCY, 
                NUMERATOR_BUY,
                CONVERSION_RATE,
                LEAD(conversion_rate) OVER (PARTITION BY from_currency ORDER BY from_currency_date) AS LEAD_conversion_rate,                
                ROW_NUMBER() OVER (PARTITION BY from_currency ORDER BY from_currency_date DESC) AS rn
        FROM    exchange_rate_staging_tbl
        WHERE   valid_flag is null or valid_flag <> 'E';

cur_rec c1%rowtype;

BEGIN 

 SELECT MAX(from_currency_date)
 INTO l_max_date
 FROM exchange_rate_staging_tbl;


 FOR cur_rec IN c1 LOOP

   if cur_rec.lead_conversion_rate is null then -->Null means it is the latest transaction
   dbms_output.put_line(cur_rec.from_currency||' '||
                       cur_rec.to_currency||' '||
                       'Inside IF'||' '||
                       cur_rec.conversion_rate);
   ELSE --> Records here are not the latest transaction but they still need to be inserted with their respective exch rate
   --dbms_output.put_line(l_max_date||last_day(l_max_date)); 
   dbms_output.put_line(cur_rec.from_currency||' '||
                       cur_rec.to_currency||' '||
                       'Inside Else'||' '||
                       cur_rec.conversion_rate);
   END IF;

  l_max_date := l_max_date+1; 
  END LOOP; 
 END; 

上述过程输出:

GBP USD 25-APR-15 25-APR-15 Inside Else 1.8

GBP USD 26-APR-15 26-APR-15 内部 IF 1.7346

我将如何在 SQL 或 PLSQL 中根据每个货币的最新交易生成记录。

【问题讨论】:

获取缺失日期列表(例如通过递归查询),选择最大日期和值或这个日期,加入并插入 我用我所有的研究和代码编辑了这篇文章。您能详细说明一下您的 cmets 吗? 【参考方案1】:

这个查询看起来很有希望:

with 
  dm as (select max(from_currency_date) d from exchange_rate_staging_tbl),
  dr as (select distinct from_currency fc, to_currency tc,
      last_value(conversion_rate ignore nulls) over 
        (partition by from_currency, to_currency order by from_currency_date 
        rows between unbounded preceding and unbounded following) rate
    from exchange_rate_staging_tbl, dm where from_currency_date = dm.d),
  days as (select d+level-1 day from dm connect by d+level-1 <= last_day(d))
select days.day, dr.fc, dr.tc, rate
  from days cross join dr 

SQLFiddle demo

有一个问题 - 如果 4 月 26 日我们有 GBP/USD 的汇率,但没有 USD/GBP,那么只会复制 GBP/USD。 我不知道是否会发生这种情况,如果是,则必须更改查询。还有更多的疑问,比如 如果相同货币等有两种汇率怎么办,但我不知道在这种情况下你想要什么。

它是如何工作的:

第一个子查询dm 只是在表中查找最大日期,您可能想在此处添加月份过滤器,例如where from_currency_date &lt;= 'date 2015-04-30'dr 收集当天所有货币汇率的信息,distinct last_value 保证每对货币只占用一行, days 是分层日期生成器,生成到月底的缺失日期, 最终选择加入日期和费率。

根据评论编辑:

我怎样才能仍然带来 4/25 的转化率

with 
  dm as (select date '2015-04-25' d from dual), 
  dc as (
    select distinct from_currency, to_currency
      from exchange_rate_staging_tbl, dm 
      where from_currency_date between d and last_day(d)),
  days as (
    select d+level-1 from_currency_date 
      from dm connect by d+level-1 <= last_day(d))
select from_currency_date, from_currency, to_currency,
    last_value(conversion_rate ignore nulls) over 
      (partition by from_currency, to_currency order by from_currency_date 
      rows unbounded preceding ) rate 
  from dc cross join days 
  left join exchange_rate_staging_tbl e
    using (from_currency_date, from_currency, to_currency)  
  order by from_currency_date, from_currency, to_currency

SQLFiddle demo

此查询显示从给定日期(您在第一行中定义)到月底填补空白的数据 - 假设我们没有周六和周日的转化率,查询用周五的数据填补了这个空白。


函数last_value() 查找转化率的最后一个值 从某种以某种方式分组(分区)的值集。在我们的例子中,这些分区是货币对,order 是 currency_date。 用人类的话来说:找到给定时期内每对货币的兑换率的最后一个非空值。请注意,此期间每行都会发生变化。 Last_value 是使用范围非常广泛的分析函数之一。 关于这些功能的好文章:Analytic functions by Example。

【讨论】:

我运行了您的查询,我认为它有效,但我注意到它缺少 4/25 的信息。它带来 4/26 并持续到月底(这也是我所需要的)。除此之外,还需要反映 4/25。我怎样才能仍然带来 4/25 的转化率? 我已经编辑了答案,请看底部。还更正了第一部分中指向 SQLFiddle 的链接。 非常感谢@Ponder Stibbons,您的最后一个查询似乎按预期工作。此外,您发送的链接非常有帮助。您能否详细说明last_value(conversion_rate ignore nulls) over (partition by from_currency, to_currency order by from_currency_date rows between unbounded preceding and unbounded following) rate 在查询中的作用? 乐于助人。我为last_value 添加了解释,请参阅答案中的最后编辑。很抱歉有任何语言错误,英语不是我的主要语言。【参考方案2】:

您的数据看起来不像我见过的任何费率数据。通常,一切都以一种货币为参考。就我而言,它是美元。现在,您每天只需为每种货币输入一个条目。像这样:

Effective  Code Factor
2015-05-02 GBP  0.662251656 --based on today's rate of 1.51 GBP->USD

从美元到英镑:美元 * 因子 = 英镑 从英镑到美元:英镑/因子=美元

有一个幻灯片演示显示了这样的表格设计here。货币讨论从幻灯片/第 12 页开始,查询从第 16 页开始。表格设计很简单:

create table XRates(
    Code       char( 3 ) not null,
    Effective  date not null,
    Factor     decimal( 12, 9 ) not null
    constraint PK_XRates primary key( Code, Effective )
);

该设计的几个不错的功能是您可以在同一张表中维护历史汇率,并且不需要每日输入。仅当汇率发生变化时才进行输入。该查询返回在给定日期生效的汇率,即使该汇率是由一周前的条目确定的(在今天的货币市场中不太可能)。

【讨论】:

以上是关于sql复制到月底的最新记录的主要内容,如果未能解决你的问题,请参考以下文章

SQL 如何复制一条记录的指定字段的内容到另一条记录的指定字段?

如何在 mysql 5.7 上显示从月份的第一个日期到 MYSQL 5.7 上的月底日期的日期? [复制]

使用存储过程将记录从 SQL Server 复制到 SQL Server (2005)

SQL 返回另一个日期前 18 个月的所有记录(到月底)

SQL Server 将现有表复制到新表中但跳过重复记录

如何使用 PHP 将记录从远程 SQL Server 2005 复制到本地 mySQL?