web-dev-qa-db-ja.com

今月のすべての日付を取得する

mySQLにクエリがあり、今月のすべてのレコードを取得することで非常にうまく機能します。

SELECT date_field,val FROM MY_TABLE WHERE date_field>=(CURDATE()-INTERVAL 1 MONTH);

上記のクエリはうまく機能します。したがって、今月は2つのレコードと28日間しかなかった場合、2つのレコードのみが表示されます。

date_field | val
========================
2015-02-08 | 567
2015-02-09 | 345

ただし、返されるレコードの数を、当月の日数と正確に同じにしたいと考えています。現在の月に28日があり、レコードが2つしかない場合。

date_field | val
========================
2015-02-01 | 0
2015-02-02 | 0
2015-02-03 | 0
2015-02-04 | 0
2015-02-05 | 0
2015-02-06 | 0
2015-02-07 | 0
2015-02-08 | 567
2015-02-09 | 345
2015-02-10 | 0
2015-02-11 | 0
2015-02-12 | 0
2015-02-13 | 0
2015-02-14 | 0
2015-02-15 | 0
2015-02-16 | 0
2015-02-17 | 0
2015-02-18 | 0
2015-02-19 | 0
2015-02-20 | 0
2015-02-21 | 0
2015-02-22 | 0
2015-02-23 | 0
2015-02-24 | 0
2015-02-25 | 0
2015-02-26 | 0
2015-02-27 | 0
2015-02-28 | 0

上記の結果を得るためにクエリを変更するにはどうすればよいですか?

6
indago

まず、条件WHERE date_field >= (CURDATE()-INTERVAL 1 MONTH)は、結果を当月に限定しません。 30〜31日前から現在の日付まで(およびテーブルに将来の日付を持つ行がある場合は、将来まで)のすべての日付をフェッチします。

そのはず:

WHERE date_field >= LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH
  AND date_field < LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY

ここで、主な質問に対して、28-31の日付を作成するには、テーブルにすべての日付の行がない場合でも、Calendarテーブルを使用できます(すべての日付、たとえば1900年から2200年の場合)または次のようなものを使用して、それらをその場で作成します(daysテーブルは一時テーブルにすることも、派生テーブルにすることもできます。これよりもやや複雑なクエリを使用できます)。

CREATE TABLE days
( d INT NOT NULL PRIMARY KEY ) ;

INSERT INTO days
VALUES (0), (1), (2), ....
                  ..., (28), (29), (30) ;

SELECT 
    cal.my_date        AS date_field, 
    COALESCE(t.val, 0) AS val
FROM 
    ( SELECT 
          s.start_date + INTERVAL (days.d) DAY  AS my_date
      FROM 
          ( SELECT LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH
                       AS start_date,
                   LAST_DAY(CURRENT_DATE) 
                       AS end_date
          ) AS s
          JOIN days  
              ON  days.d <= DATEDIFF(s.end_date, s.start_date)
    ) AS cal
    LEFT JOIN my_table AS t 
        ON  t.date_field >= cal.my_date 
        AND t.date_field  < cal.my_date + INTERVAL 1 DAY ; 

上記は、date_field列の任意のタイプ(日付、日時、タイムスタンプ)で機能します。 date_field列がDATEタイプの場合、最後の結合は次のように簡略化できます。

    LEFT JOIN my_table AS t 
        ON  t.date_field = cal.my_date ;
6
ypercubeᵀᴹ

今月の日付の動的テーブルを作成できます

SELECT date_field
FROM
(
    SELECT
        MAKEDATE(YEAR(NOW()),1) +
        INTERVAL (MONTH(NOW())-1) MONTH +
        INTERVAL daynum DAY date_field
    FROM
    (
        SELECT t*10+u daynum
        FROM
            (SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) A,
            (SELECT 0 u 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) B
        ORDER BY daynum
    ) AA
) AAA
WHERE MONTH(date_field) = MONTH(NOW());

注:上記のクエリをそのままカットアンドペーストすると、月全体が生成されます

次に、これを元のクエリに結合します

SELECT
    AAA.date_field,
    IFNULL(BBB.val,0) val
FROM
(
    SELECT date_field
    FROM
    (
        SELECT MAKEDATE(YEAR(NOW()),1) +
        INTERVAL (MONTH(NOW())-1) MONTH +
        INTERVAL daynum DAY date_field
        FROM
        (
            SELECT t*10+u daynum FROM
            (SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) A,
            (SELECT 0 u 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) B ORDER BY daynum
        ) AA
    ) AA WHERE MONTH(date_field) = MONTH(NOW())
) AAA LEFT JOIN (SELECT date_field,val FROM MY_TABLE) BBB
USING (date_field);

試してみる !!!

7
RolandoMySQLDBA
_------ Create Exam Table


DECLARE @MyTable TABLE
(date_field DATETIME
,val INT )

INSERT INTO @MyTable
        ( date_field, val )
VALUES  ( CAST('2015-04-05' AS VARCHAR), -- date_field - datetime
          270  -- val - int
          )
INSERT INTO @MyTable
        ( date_field, val )
VALUES  ( CAST( EOMONTH ( GETDATE() ) AS VARCHAR), -- date_field - datetime
          500  -- val - int
          )



DECLARE @startDate DATETIME=CAST(MONTH(GETDATE()) AS VARCHAR) + '/' + '01/' +  + CAST(YEAR(GETDATE()) AS VARCHAR) -- mm/dd/yyyy
DECLARE @endDate DATETIME= CAST( EOMONTH ( GETDATE() ) AS VARCHAR) -- mm/dd/yyyy
;WITH Calender AS 
(
    SELECT @startDate AS CalanderDate
    UNION ALL
    SELECT CalanderDate + 1 FROM Calender
    WHERE CalanderDate + 1 <= @endDate
)
SELECT CONVERT(VARCHAR(10),CalanderDate,25) AS [DATE], ISNULL(MT.val,0) val
FROM Calender
LEFT JOIN @MyTable MT ON Calender.CalanderDate = MT.date_field
_

MySQLLAST_DAY()関数を代わりに使用できますEOMONTH() in [〜#〜] sql [〜#〜]

0
user2897607