48

2011-01-01から2011-12-31までのすべての日付を保持するMySQLテーブルが必要です。「_date」という1つの列名でDATEと入力するテーブルを作成しました。

どのクエリを使用して、(手動で入力する代わりに)必要なすべての日付をテーブルに入力できますか?

4

10 に答える 10

54

これを試して:

DROP PROCEDURE IF EXISTS filldates;
DELIMITER |
CREATE PROCEDURE filldates(dateStart DATE, dateEnd DATE)
BEGIN
  WHILE dateStart <= dateEnd DO
    INSERT INTO tablename (_date) VALUES (dateStart);
    SET dateStart = date_add(dateStart, INTERVAL 1 DAY);
  END WHILE;
END;
|
DELIMITER ;
CALL filldates('2011-01-01','2011-12-31');

これで遊ぶSQL Fiddleは次のとおりです。http://sqlfiddle.com/#!2/65d13/1

Andrew Foxの質問に応じて EDIT (日付が既に存在するかどうかを確認するため) 。

CREATE PROCEDURE filldates(dateStart DATE, dateEnd DATE)

BEGIN

DECLARE adate date;

    WHILE dateStart <= dateEnd DO

        SET adate = (SELECT mydate FROM MyDates WHERE mydate = dateStart);

        IF adate IS NULL THEN BEGIN

            INSERT INTO MyDates (mydate) VALUES (dateStart);

        END; END IF;

        SET dateStart = date_add(dateStart, INTERVAL 1 DAY);

    END WHILE;

END;//

これで遊ぶSQL Fiddleは次のとおりです。http://sqlfiddle.com/#!2/66f86/1

于 2012-04-12T21:28:39.523 に答える
27

SQL クエリに外部依存関係 (カレンダー テーブル、一時テーブルに日付を入力するための手順などが必要) を必要としたくなかったのです。このクエリの元のアイデアはhttp://jeffgarretson.wordpress.com/2012から来ました。 /05/04/generating-a-range-of-dates-in-mysql/は、わかりやすく使いやすいようにわずかに最適化しました。

SELECT (CURDATE() - INTERVAL c.number DAY) AS date
FROM (SELECT singles + tens + hundreds number FROM 
( SELECT 0 singles
UNION ALL SELECT   1 UNION ALL SELECT   2 UNION ALL SELECT   3
UNION ALL SELECT   4 UNION ALL SELECT   5 UNION ALL SELECT   6
UNION ALL SELECT   7 UNION ALL SELECT   8 UNION ALL SELECT   9
) singles JOIN 
(SELECT 0 tens
UNION ALL SELECT  10 UNION ALL SELECT  20 UNION ALL SELECT  30
UNION ALL SELECT  40 UNION ALL SELECT  50 UNION ALL SELECT  60
UNION ALL SELECT  70 UNION ALL SELECT  80 UNION ALL SELECT  90
) tens  JOIN 
(SELECT 0 hundreds
UNION ALL SELECT  100 UNION ALL SELECT  200 UNION ALL SELECT  300
UNION ALL SELECT  400 UNION ALL SELECT  500 UNION ALL SELECT  600
UNION ALL SELECT  700 UNION ALL SELECT  800 UNION ALL SELECT  900
) hundreds
ORDER BY number DESC) c  
WHERE c.number BETWEEN 0 and 364

このテーブルを他の用途に合わせて最適化およびスケーリングするのは簡単です。1 週間分のデータだけが必要な場合は、数十や数百のテーブルを簡単に取り除くことができます。

より大きな数のセットが必要な場合は、千のテーブルを簡単に追加できます。数百の表をコピーして貼り付け、0 から 9 の数字を追加するだけです。

于 2014-07-08T03:24:28.883 に答える
11

このペーストアンドゴーバリアントが機能していることがわかりました:

DROP PROCEDURE IF EXISTS FillCalendar;
DROP TABLE IF EXISTS calendar;
CREATE TABLE IF NOT EXISTS calendar(calendar_date DATE NOT NULL PRIMARY KEY);

DELIMITER $$
    CREATE PROCEDURE FillCalendar(start_date DATE, end_date DATE)
    BEGIN
    DECLARE crt_date DATE;
    SET crt_date = start_date;
    WHILE crt_date <= end_date DO
        INSERT IGNORE INTO calendar VALUES(crt_date);
        SET crt_date = ADDDATE(crt_date, INTERVAL 1 DAY);
    END WHILE;
    END$$
DELIMITER ;

CALL FillCalendar('2013-01-01', '2013-01-03');
CALL FillCalendar('2013-01-01', '2013-01-07');
于 2013-10-25T11:00:25.010 に答える
5

最近、calendar_date次のようなテーブルを作成する必要がありました。

CREATE TABLE `calendar_date` (
    `date`    DATE NOT NULL      -- A calendar date.
    , `day`   SMALLINT NOT NULL  -- The day of the year for the date, 1-366.
    , `month` TINYINT NOT NULL   -- The month number, 1-12.
    , `year`  SMALLINT NOT NULL  -- The year.
    , PRIMARY KEY (`id`));

次に、以下のクエリを使用して、 ~ の間 (両方を含む)January 1, 2001のすべての可能な日付を入力しました。December 31, 2100

INSERT INTO `calendar_date` (`date`
    , `day`
    , `month`
    , `year`)
SELECT
    DATE
    , INCREMENT + 1
    , MONTH(DATE)
    , YEAR(DATE)
FROM
    -- Generate all possible dates for every year from 2001 to 2100.
    (SELECT
        DATE_ADD(CONCAT(YEAR, '-01-01'), INTERVAL INCREMENT DAY) DATE
        , INCREMENT
    FROM
        (SELECT
            (UNITS + TENS + HUNDREDS) INCREMENT
        FROM
            (SELECT 0 UNITS UNION
            SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION
            SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION
            SELECT 7 UNION SELECT 8 UNION SELECT 9) UNITS
        CROSS JOIN
            (SELECT 0 TENS UNION
            SELECT 10 UNION SELECT 20 UNION SELECT 30 UNION
            SELECT 40 UNION SELECT 50 UNION SELECT 60 UNION
            SELECT 70 UNION SELECT 80 UNION SELECT 90) TENS
        CROSS JOIN
            (SELECT 0 HUNDREDS UNION
            SELECT 100 UNION SELECT 200 UNION SELECT 300 UNION
            SELECT 400 UNION SELECT 500 UNION SELECT 600 UNION
            SELECT 700 UNION SELECT 800 UNION SELECT 900) HUNDREDS
        ) INCREMENT
        -- For every year from 2001 to 2100, find the number of days in the year.
        , (SELECT
            YEAR
            , DAYOFYEAR(CONCAT(YEAR, '-12-31')) - DAYOFYEAR(CONCAT(YEAR, '-01-01')) + 1 DAYS
        FROM
            -- Generate years from 2001 to 2100.
            (SELECT
                (2000 + UNITS + TENS) YEAR
            FROM
                (SELECT 0 UNITS UNION
                SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION
                SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION
                SELECT 7 UNION SELECT 8 UNION SELECT 9) UNITS
            CROSS JOIN
                (SELECT 0 TENS UNION
                SELECT 10 UNION SELECT 20 UNION SELECT 30 UNION
                SELECT 40 UNION SELECT 50 UNION SELECT 60 UNION
                SELECT 70 UNION SELECT 80 UNION SELECT 90) TENS
            ) YEAR
        WHERE
            YEAR BETWEEN 2001 AND 2100
        ) YEAR
      WHERE
          INCREMENT BETWEEN 0 AND DAYS - 1
      ORDER BY
          YEAR
          , INCREMENT) DATE;

私のローカル MySQL データベースでは、INSERTクエリに数秒しかかかりませんでした。これが誰かに役立つことを願っています。

于 2018-01-31T09:40:01.280 に答える
2

これは、単純な for ループを使用して PHP で実現できます。いくつかの方法があります。1 つの方法は、元の日付を変数に配置し、各ループに +1 日を追加して毎日ループを実行させることです。たとえば、2011 年 1 月 1 日に開始すると、ループは次のようになります。最初は 0 を追加し、次は 1 日を追加し、その後 2 日、というように $i 変数に追加します。その後、日付を印刷したり、データベースに追加したりできます。この場合、$i は開始点が 0 のカウンターを表し、<=365 は通過するループの数で、日数以下であり、$i++ は $i 変数に +1 を追加します。各ループで。

date('Ymd' は日付を yyyy-mm-dd に変換します。大文字の Y を使用すると完全な 4 桁の年が得られますが、小文字の y を使用すると年の下 2 桁が得られます。 mySQL の日付フィールドに追加します。

strtotime($originalDate は日付を Unix タイム スタンプに解析し、."+".$i." day") は基本的に $i の値 (日数) を日付に追加します。

最後に、mysqli クエリがあります。$db はデータベース接続変数を表します。これは、接続用に設定した変数に変更する必要があります。これに実際のクエリが続きます。table という単語をテーブル名に、VALUES の前の日付を日付行名に交換するだけで準備完了です。

次に例を示します。

<?php
for($i=0;$i<=365;$i++){ 
$originalDate = "01/01/2011";
$date = date('Y-m-d',strtotime($originalDate . "+".$i." day"));
mysqli_query($db, "INSERT INTO table (date)VALUES('$date')");
}

for 関数を使用してこれを実現する別の方法は、カウンター変数とは対照的に、for アクションに strtotime 日付を直接含めることです。これはさらに短いコードです。$i=0 (開始カウンター ポイント) を開始日のポイントに置き換え、その後に終了日のポイント (ループの数) 以下の値を付け、最後に、最初のステートメントに +1 をプラスして、変数を使用する準備ができました。

最後に、日付をデータベースに配置できる Ymd 形式に変換し、クエリを実行します。

繰り返しますが、最初の例と同様に、これを印刷するか、データベースに直接配置することができます。

次に例を示します。

<?php
for ($startdate = strtotime("2011-01-01"); $startdate <= strtotime("2011-12-31"); $startdate = strtotime("+1 day", $startdate)) {
$date= date("Y-m-d", $startdate);
mysqli_query($db, "INSERT INTO tracking (date)VALUES('$date')");
}

おそらく実際よりもややこしく聞こえるようにしましたが、少なくともそれがどのように機能するかについてのアイデアを与えることを願っています.

于 2016-08-08T01:43:47.913 に答える