日期范围的递归查询
Recursive Query for Date Range
我正在尝试创建一个查询,以便生成特定起点和终点之间的日期范围。
我有以下内容:
WITH DATE_RANGE(DATE_FOR_SHIFT)
AS (SELECT DATE('2015-04-01')
FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT DATE_FOR_SHIFT + 1 DAY
FROM DATE_RANGE
WHERE DATE_FOR_SHIFT <= @END)
SELECT DATE_FOR_SHIFT
FROM DATE_RANGE;
输出(假设@END
等于2015-05-01
):
2015-04-01
2015-04-02
2015-04-03
2015-04-04
...
2015-05-01
输出是正确的,但我希望能够根据提供的参数更改起点和点,而不必重写查询或使用 SQL 容易注入的查询。
我将如何重写此查询以实现此目的?
在 perl 中稍微玩一下这个给了我:
#!/opt/myperl/5.20.2/bin/perl
use 5.10.0;
use DBI;
use DBD::DB2;
use Data::Dump;
my $sql = <<EOSQL;
WITH DATE_RANGE(DATE_FOR_SHIFT)
AS (SELECT CAST(? AS DATE)
FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT DATE_FOR_SHIFT + 1 DAY
FROM DATE_RANGE
WHERE DATE_FOR_SHIFT < CAST(? AS DATE))
SELECT DATE_FOR_SHIFT
FROM DATE_RANGE;
EOSQL
my $dbh = DBI->connect('dbi:DB2:sample');
my $sth = $dbh->prepare_cached($sql);
$sth->execute('2015-04-01','2015-05-01');
my $rc = $sth->fetchall_arrayref();
dd($rc);
这确实在准备期间给出了一个错误("The recursive common table expression "MYSCHEMA.DATE_RANGE“可能包含一个无限循环”),我还没有弄清楚,但是提取确实有效,最后的 return 从 04-01 到 05-01。希望您可以将其移植到您想要的语言。
你的 SELECT 没问题,除了硬编码的开始日期。
我认为您缺少的是将其包装在存储过程或用户定义的 table 函数 (UDTF) 中。假设您想要加入其他 table 的日期范围,我建议使用 UDTF。
create function date_range (@str date, @end date)
returns table (date_for_shift date)
language SQL
reads SQL data
return
WITH DATE_RANGE(DATE_FOR_SHIFT)
AS (SELECT @str
FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT DATE_FOR_SHIFT + 1 DAY
FROM DATE_RANGE
WHERE DATE_FOR_SHIFT <= @END)
SELECT DATE_FOR_SHIFT
FROM DATE_RANGE;
那你就叫它...
select * from table(date_range(date('2015-04-01'),date('2015-05-01'))) as tbl;
但是,与其动态生成此日期范围,不如考虑简单地创建一个日历(又名日期)table。基本上只是一个 table,日期从 1900-01-01 到 2500-12-31.. 或者任何你想要的。除了日期列之外,您还可以包含许多其他列,例如 business_day、假期等,让生活变得更轻松。
Google "SQL calendar table" 有很多例子。
我正在尝试创建一个查询,以便生成特定起点和终点之间的日期范围。
我有以下内容:
WITH DATE_RANGE(DATE_FOR_SHIFT)
AS (SELECT DATE('2015-04-01')
FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT DATE_FOR_SHIFT + 1 DAY
FROM DATE_RANGE
WHERE DATE_FOR_SHIFT <= @END)
SELECT DATE_FOR_SHIFT
FROM DATE_RANGE;
输出(假设@END
等于2015-05-01
):
2015-04-01
2015-04-02
2015-04-03
2015-04-04
...
2015-05-01
输出是正确的,但我希望能够根据提供的参数更改起点和点,而不必重写查询或使用 SQL 容易注入的查询。
我将如何重写此查询以实现此目的?
在 perl 中稍微玩一下这个给了我:
#!/opt/myperl/5.20.2/bin/perl
use 5.10.0;
use DBI;
use DBD::DB2;
use Data::Dump;
my $sql = <<EOSQL;
WITH DATE_RANGE(DATE_FOR_SHIFT)
AS (SELECT CAST(? AS DATE)
FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT DATE_FOR_SHIFT + 1 DAY
FROM DATE_RANGE
WHERE DATE_FOR_SHIFT < CAST(? AS DATE))
SELECT DATE_FOR_SHIFT
FROM DATE_RANGE;
EOSQL
my $dbh = DBI->connect('dbi:DB2:sample');
my $sth = $dbh->prepare_cached($sql);
$sth->execute('2015-04-01','2015-05-01');
my $rc = $sth->fetchall_arrayref();
dd($rc);
这确实在准备期间给出了一个错误("The recursive common table expression "MYSCHEMA.DATE_RANGE“可能包含一个无限循环”),我还没有弄清楚,但是提取确实有效,最后的 return 从 04-01 到 05-01。希望您可以将其移植到您想要的语言。
你的 SELECT 没问题,除了硬编码的开始日期。
我认为您缺少的是将其包装在存储过程或用户定义的 table 函数 (UDTF) 中。假设您想要加入其他 table 的日期范围,我建议使用 UDTF。
create function date_range (@str date, @end date)
returns table (date_for_shift date)
language SQL
reads SQL data
return
WITH DATE_RANGE(DATE_FOR_SHIFT)
AS (SELECT @str
FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT DATE_FOR_SHIFT + 1 DAY
FROM DATE_RANGE
WHERE DATE_FOR_SHIFT <= @END)
SELECT DATE_FOR_SHIFT
FROM DATE_RANGE;
那你就叫它...
select * from table(date_range(date('2015-04-01'),date('2015-05-01'))) as tbl;
但是,与其动态生成此日期范围,不如考虑简单地创建一个日历(又名日期)table。基本上只是一个 table,日期从 1900-01-01 到 2500-12-31.. 或者任何你想要的。除了日期列之外,您还可以包含许多其他列,例如 business_day、假期等,让生活变得更轻松。
Google "SQL calendar table" 有很多例子。