【问题标题】:looping a SQL insert statement with dates使用日期循环 SQL 插入语句
【发布时间】:2011-07-04 05:38:10
【问题描述】:

我需要运行一个语句,该语句每次都会使用相同的信息填充数据库,日期除外。

我目前正在尝试这些方法,但没有任何运气。

DECLARE 
i_int BINARY_INTEGER := 1;
  BEGIN
    WHILE i_int <= 30 LOOP
      INSERT INTO bs_events (eventDate,eventTime,title,spaces,description,entryFee,payment_required,max_qty,allow_multiple) VALUES ('2011-03-i_int 00:00:00', '10:00','Carpet Cleaner 3000','4','This is rad','25.99','1','1','2');
      i_int := i_int + 1;
    END LOOP;
  END;
  /

我似乎无法让它工作,我陷入了一个代码洞,无法思考。

我基本上希望日期从 01 到 30 增加一个,然后我将手动更改月份并在一年中的所有 12 个月再次运行脚本。

【问题讨论】:

  • 你已经用 'php' 标记了它——使用 php 之类的过程语言很容易实现这一点,而使用 SQL 之类的声明性语言(相对而言)则非常困难。使用php!
  • 我希望活动日期是唯一改变的事情

标签: php sql database loops insert


【解决方案1】:

考虑创建一个Calendar table

我在使用的任何数据库中创建的第一个表是一个数字表,从 1 到 1000000。这样的表有很多用途,例如在 SQL 中实现循环。此外,它还可用于生成我在使用的任何数据库上创建的第二个表:日历表。

日历表的每个日期都有一行,从数据库中第一个记录的业务事件开始(加上一年左右)。为所有相关的业务查询保留足够的未来日期(加上几年以确保安全)。

您的具体问题可以使用上述任一表来解决,但日历表方法会容易得多。

我将在下面的 MySQL 中为您提供一个简单但有效的示例:

create table digits(n int);
insert into digits values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);

create table numbers(
   n int not null
  ,primary key(n)
);

digits 表只是一个工作表,一旦创建了实数表,它将被删除。数字表只有一列,它是主键。接下来,从 1 开始生成 100 万个连续整数。(这听起来很慢,但在我 2 岁的笔记本电脑上,它实际上在 10 秒内完成)。

insert 
  into numbers(n)
select 1 
      + (d1.n * 1)
      + (d2.n * 10)
      + (d3.n * 100)
      + (d4.n * 1000)
      + (d5.n * 10000)
      + (d6.n * 100000) as n
  from digits d1
      ,digits d2
      ,digits d3
      ,digits d4
      ,digits d5
      ,digits d6;

/* Drop the working table. */
drop table digits;

接下来,我将创建一个日历表。显然,它目前毫无用处,因为它没有任何有用的列。有用列的示例有 year、monthname、week number、isFirstMonthDay、isLastMonthDay、Financial Year、isHoliday、Holidayname、dayname、 Quarter、tertial。对于非标准时期,这是黄金时期。

create table calendar(
   datum date not null
  ,primary key(datum)
);

好的,现在我们可以使用数字表作为行生成器来构建我们的日历表。假设我想生成 2000-01-01 和 2019-12-31 之间的所有日期。那将是 7305 天。很简单,只需从数字表中选择那么多行,然后将 int 列 N 添加到日期即可。这将创建一个递增日期列表。

insert 
  into calendar(datum)
select date_add('1999-12-31', interval n day)
  from numbers
 where n <=7305;

完成。您可能会看到仅使用数字表是如何解决您的问题的?

最后,这里有一个示例,说明如何使用日历表解决您的特定问题。如果您添加年份和月份的列,当然会更容易。在这里,我将您的问题解释为 “在一年的剩余时间里,每个月的每一天都生成一个相同的行”。

insert 
  into bs_events(
        eventDate,        eventTime,      title
       ,spaces,           description,    entryFee
       ,payment_required, max_qty,        allow_multiple
       )
 select datum,            '10:00',        'Carpet Cleaner 3000'
       ,'4',              'This is rad',  '25.99'
       ,'1',              '1',            '2'
   from calendar
  where datum >= date '2011-03-01'
    and datum <= date '2011-12-31';

【讨论】:

    【解决方案2】:
    DECLARE 
    i_int BINARY_INTEGER := 0;
      BEGIN
        WHILE i_int < 30 LOOP
          INSERT INTO bs_events (
            eventDate, eventTime, title,
            spaces, description, entryFee,
            payment_required, max_qty, allow_multiple)
          VALUES (
            DATEADD(day, i_int, '2011-03-01 00:00:00'), '10:00', 'Carpet Cleaner 3000',
            '4', 'This is rad', '25.99',
            '1', '1', '2');
          i_int := i_int + 1;
        END LOOP;
      END;
      /
    

    【讨论】:

      【解决方案3】:
      INSERT INTO bs_events (eventDate, ... ) 
      VALUES ('2011-03-i_int 00:00:00', ...);
      

      这个值2011-03-i_int 00:00:00 是一个字符串,而不是时间戳。您希望您的 SQL 环境将 i_int 的值替换为它的符号。它不会那样做。

      相反,在 INSERT 语句之外执行日期算术。

      在 PostgreSQL (PL/pgsql) 中,您可以这样做以将一天添加到“时间戳”类型的变量中。

      this_date = this_date + interval '1 day';
      

      在 INSERT 语句中,

      INSERT INTO bs_events (eventDate, ... ) 
      VALUES (this_date, ...);
      

      检查您的文档以了解适合您平台的语法。

      【讨论】:

        【解决方案4】:

        你可以试试DATEADD(ms,i_int,GETDATE()) 约会。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-02-28
          • 1970-01-01
          • 1970-01-01
          • 2015-10-13
          • 2015-06-04
          • 2021-10-16
          • 2016-03-08
          • 1970-01-01
          相关资源
          最近更新 更多