2017-05-03 10 views
0

これは、このリンクで記事に関連している:MySQLの合計

MySQL : sum of every day

datetime (datetime) count (int) 
2012-12-27 09:22:15 5 
2012-12-27 18:20:15 4 
2012-12-27 23:19:15 3 
2012-12-26 13:45:15 8 
2012-12-26 04:56:15 7 
2012-12-25 01:50:15 2 
2012-12-25 12:02:15 1 

私はだけでなく、エントリが存在し、これらの日のために、日常のCOUNTを合計したいと思いますまた、エントリーがない日も含まれます。

SELECT DATE(datetime) as DATE, SUM(`count`) totalCOunt 
FROM  tableName 
GROUP BY DATE(datetime) 

上記のコードは、エントリーがある日のみ返信します。

私は2016年4月から2017年2月の間に毎日合計をカウントしたいと思いますが、どうすればいいですか?ありがとう。例:

+1

あなたはそこにないものを選択することはできません。おそらく、生成されたリストへの結合を含むいくつかのハックな解決策がありますか?しかしおそらくそうではありません。私はあなたのデータベースにすべての日のリストが必要だと言います。 – Pharaoh

+1

カレンダーテーブルを使用します。あなたはこれのためにGoogleにすることができ、多くのものを見つけるでしょう。 –

+0

だから、テーブルの最小日付から最大日付までの合計を必要とします。そうですか? – Avi

答えて

0

次のコードに示すように、カレンダーテーブルを作成できます。必要なときに正確なカレンダーを作成できます。 そのカレンダーテーブルにエントリを作成します。

DROP TABLE IF EXISTS time_dimension; 

CREATE TABLE time_dimension (
     id      INTEGER PRIMARY KEY, -- year*10000+month*100+day 
     db_date     DATE NOT NULL, 
     year     INTEGER NOT NULL, 
     month     INTEGER NOT NULL, -- 1 to 12 
     day      INTEGER NOT NULL, -- 1 to 31 
     quarter     INTEGER NOT NULL, -- 1 to 4 
     week     INTEGER NOT NULL, -- 1 to 52/53 
     day_name    VARCHAR(9) NOT NULL, -- 'Monday', 'Tuesday'... 
     month_name    VARCHAR(9) NOT NULL, -- 'January', 'February'... 
     holiday_flag   CHAR(1) DEFAULT 'f' CHECK (holiday_flag in ('t', 'f')), 
     weekend_flag   CHAR(1) DEFAULT 'f' CHECK (weekday_flag in ('t', 'f')), 
     event     VARCHAR(50), 
     UNIQUE td_ymd_idx (year,month,day), 
     UNIQUE td_dbdate_idx (db_date) 

) Engine=MyISAM; 

DROP PROCEDURE IF EXISTS fill_date_dimension; 
DELIMITER // 
CREATE PROCEDURE fill_date_dimension(IN startdate DATE,IN stopdate DATE) 
BEGIN 
    DECLARE currentdate DATE; 
    SET currentdate = startdate; 
    WHILE currentdate < stopdate DO 
     INSERT INTO time_dimension VALUES (
         YEAR(currentdate)*10000+MONTH(currentdate)*100 + DAY(currentdate), 
         currentdate, 
         YEAR(currentdate), 
         MONTH(currentdate), 
         DAY(currentdate), 
         QUARTER(currentdate), 
         WEEKOFYEAR(currentdate), 
         DATE_FORMAT(currentdate,'%W'), 
         DATE_FORMAT(currentdate,'%M'), 
         'f', 
         CASE DAYOFWEEK(currentdate) WHEN 1 THEN 't' WHEN 7 then 't' ELSE 'f' END, 
         NULL); 
     SET currentdate = ADDDATE(currentdate,INTERVAL 1 DAY); 
    END WHILE; 
END 
// 
DELIMITER ; 

TRUNCATE TABLE time_dimension; 

CALL fill_date_dimension('2000-01-01','2018-01-01'); 

このカレンダーテーブルが作成されると、以下のクエリを書くと問題が解決されます。

SELECT COUNT(datetime) ,DB_DATE FROM time_dimension TD 
LEFT JOIN TABLENAME TN ON DATE(TN.datetime)=TD.db_date 
WHERE TD.DB_DATE BETWEEN '2017-05-01' AND '2017-05-30' 
GROUP BY DATE(DB_DATE); 

希望すると、これが役立ちます。

0

最初の行は、あなたがコードをいじるされていると、古いバージョンを削除したいときに便利です

DROP PROCEDURE IF EXISTS SumCountAllDays; 

DELIMITER // 
    CREATE PROCEDURE SumCountAllDays(startDate DATE, 
             endDate DATE) 
    BEGIN 
     DECLARE daysCount INT; 
     DECLARE daysIndex INT DEFAULT 0; 

     SELECT DATEDIFF(endDate, 
         startDate) 
     INTO daysCount; 

     SET @selectStatementString := CONCAT("SELECT allDays.intervalDate AS `Date`,", 
               "  COALESCE(SUM(`count`), 0) AS totalCount ", 
               "FROM (SELECT '", 
               startDate, 
               "' AS intervalDate"); 

     daysLister : LOOP 
      SET daysIndex = daysIndex + 1; 
      IF daysIndex <= daysCount THEN 
       SET @selectStatementString := CONCAT(@selectStatementString, 
                 " UNION SELECT '", 
                 DATE_ADD(startDate, 
                   INTERVAL daysIndex DAY), 
                 "'"); 
       ITERATE daysLister; 
      END IF; 
      LEAVE daysLister; 
     END LOOP daysLister; 

     SET @selectStatementString := CONCAT(@selectStatementString, 
               ") AS allDays ", 
               "LEFT JOIN tableName ON allDays.intervalDate = DATE(`datetime`) ", 
               "GROUP BY allDays.intervalDate;"); 

     PREPARE selectStatement FROM @selectStatementString; 
     EXECUTE selectStatement; 
     DEALLOCATE PREPARE selectStatement; 
    END // 
DELIMITER ; 

...次のことを試してみてください。

コードの残りの部分は問題に呼ばれ、期間の開始日と終了日を経過したときには、daysCountに値を格納し、日間とstartDateendDateなどの数を計算するDATEDIFF()を使用して開始することプロシージャを作成します。

この手順では、@selectStatementStringが最終的な声明の最初の部分に初期化されます。この最初の部分は、startDateendDateを含む各日付を選択するために使用される一連のSELECTステートメントの最初の部分で終了します。このSELECTの初期値はstartDateであり、これらすべての日付の和集合によって形成されるフィールドの名前はintervalDateです。

ループには、ループのインデックスdaysIndexに基づいて計算された日付ごとにSELECTが追加されます。

UNION演算子は、生成された日付ごとに垂直結合を実行するために使用されます。

LOOPが終了した後、残りのステートメントがこれまでのステートメントに追加されます。 startDateendDate2012-02-132012-02-15だったなら、私たちは今、次の文を持っているでしょう...

SELECT allDays.intervalDate AS `Date`, 
     COUNT(`count`) AS totalCount 
FROM (SELECT '2012-02-13' AS intervalDate 
     UNION 
     SELECT '2012-02-14' 
     UNION 
     SELECT '2012-02-15') AS allDays 
LEFT JOIN tableName ON allDays.intervalDate = DATE(`datetime`) 
GROUP BY allDays.intervalDate; 

私は、テスト・データベースに対して、私の文は次のスクリプトを使用して作成したテスト...

CREATE TABLE tableName 
(
    `datetime` DATETIME, 
    `count`  INT 
); 
INSERT INTO tableName (`datetime`, 
         `count`) 
VALUES ('2012-12-27 09:22:15', 5), 
     ('2012-12-27 18:20:15', 4), 
     ('2012-12-27 23:19:15', 3), 
     ('2012-12-26 13:45:15', 8), 
     ('2012-12-26 04:56:15', 7), 
     ('2012-12-25 01:50:15', 2), 
     ('2012-12-25 12:02:15', 1); 

私はあなたが何か質問やコメントがあれば、それに応じてコメントを投稿すること自由に感じなさい

CALL SumCountAllDays('2012-12-01', 
         '2012-12-31'); 

...次のステートメントを使用してプロシージャを呼び出しました。

+0

コードが修正され、説明が追加されました。 – toonice