如何减少每个月的查询量

时间:2018-07-31 13:20:48

标签: mysql coldfusion cfml coldfusion-11

我正在使用My Sql 5.7和CF11。我想从下面的查询中获取每个月的总qTotalPrice和quoteKeyID。但不是整整一年。我想从当前月份到最近六个月的数据(从7月到2月)获取它。如果特定月份没有数据,则该月份需要显示为0。

<cfquery name="thisYearsQuotes" datasource="myDB">
    SELECT * , MONTH(qDateTime) as qMonth
    FROM Quotes
    INNER JOIN Accounts
    ON Quotes.aID = Accounts.aID
    WHERE Accounts.aID = <cfqueryparam value="#VNAI.aID#" cfsqltype="cf_sql_clob" maxlength="255">
    AND Quotes.qDateTime > DATE_ADD(NOW(), INTERVAL -365 DAY)
</cfquery>

这些查询的结果Query Results

为了获取每个月的记录,我编写了一个查询查询,如下所示。

获取当前月份

<cfquery name="SalesTotalThisMonth" dbtype="query">
    SELECT SUM(qTotalPrice) as DollarTotal , COUNT(quoteKeyID) as QuoteCount
    FROM thisYearsQuotes
    WHERE qMonth = #MONTH(NOW())#
</cfquery>

要获得一个月的返还

<cfquery name="SalesTotal1MonthAgo" dbtype="query">
    SELECT SUM(qTotalPrice) as DollarTotal , COUNT(quoteKeyID) as QuoteCount
    FROM thisYearsQuotes
    WHERE qMonth = #MONTH(DateAdd("m",-1,NOW()))#
</cfquery>

要恢复两个月,

<cfquery name="SalesTotal2MonthAgo" dbtype="query">
    SELECT SUM(qTotalPrice) as DollarTotal , COUNT(quoteKeyID) as QuoteCount
    FROM thisYearsQuotes
    WHERE qMonth = #MONTH(DateAdd("m",-2,NOW()))#
</cfquery>

等等...明智的是,我必须得过去六个月。所以我每个月写了许多查询。

是否有可能减少代码?

3 个答案:

答案 0 :(得分:2)

更新

解决方案是针对您需要的所有月份创建一个查询,然后使用左联接。

SELECT 8 AS monthNum UNION SELECT 7 AS m UNION SELECT 6 AS m UNION SELECT 5 AS m UNION SELECT 4 AS m UNION SELECT 3 AS m

因此,要使其自动化,我添加了一些CF代码来创建上述查询。

<cfset today=now()>
<cfset start = 0>
<cfset numberOfMonths = 6>
<cfset listOfMonths = ''>
<cfloop condition="numberOfMonths+start GT 0">
  <cfset listOfMonths = listappend(listOfMonths, ' SELECT ' & Month(DateAdd('m', start, today)) & ' AS m ')>
  <cfset start-->
</cfloop>
<cfoutput>
<cfquery>
  SELECT SUM(O.order_Total) AS totalOrder, COUNT(O.order_ID) AS numOrders, MONTH(O.order_Date) AS qMonth
  FROM tbl_orders O 
    RIGHT JOIN (
      #ListChangeDelims(listOfMonths, 'UNION')#
    ) monthList ON monthList.m = MONTH(O.order_Date) AND O.order_Date > DATE_ADD(NOW(), INTERVAL -6 MONTH)
  GROUP BY qMonth;
</cfquery>
<cfoutput>

初始

我认为您可以使用正确的group by在单个查询中完成此操作。

<cfquery name="thisYearsQuotesPerMonth" datasource="mySQL_MILESTONEBMDB">
    SELECT 
      SUM(qTotalPrice) AS DollarTotal, COUNT(quoteKeyID) AS QuoteCount, MONTH(qDateTime) as qMonth
    FROM 
      Quotes
      INNER JOIN Accounts ON Quotes.aID = Accounts.aID
    WHERE 
      Accounts.aID = <cfqueryparam value="#VNAI.aID#" cfsqltype="cf_sql_clob" maxlength="255">
      AND Quotes.qDateTime > DATE_ADD(NOW(), INTERVAL -6 MONTH)
    GROUP BY qMonth
</cfquery>

答案 1 :(得分:0)

更新:抱歉,没有注意到您使用的是Sql 5.7。 CTE需要MySQL 8+。 IMO,MySQL 5的最佳选择是建立一个日历表并使用下面的OUTER JOIN。 This thread适用于SQL Server,但基本概念与MySQL相同。


正常的JOIN仅返回具有 个数据的月份。要返回所有月份,即使没有记录,您也需要某种calendar table和其他表的OUTER JOIN。日历表对于需要动态日期过滤器的报表,处理假期的事物等非常有用。

Newer versions of MySQL support CTE's,可用于创建动态日历表。但是,如果您的应用程序需要频繁的日期报告,那么我强烈建议您创建一个永久日历表(与动态cte不同,可以对它进行索引以获得更好的性能)。

出于演示目的,我将使用CTE。仅显示CTE的工作原理,运行此查询,您会看到它返回过去6个月的所有日期:

CTE:

WITH RECURSIVE  cte (TheDate) AS (
    SELECT cast(DATE_FORMAT(now(), '%Y-%m-%d') AS date)
    UNION ALL
    SELECT CAST(DATE_ADD(TheDate, INTERVAL -1 DAY)  AS date)
    FROM   cte 
    WHERE  TheDate >= cast(DATE_ADD(now(), INTERVAL -6 MONTH)  AS date)
) 
SELECT TheDate FROM cte;

结果:

MySQL CTE Results

现在要按月计算总数和计数,只需将OUTER JOIN添加到其他表中即可:

完整查询:

WITH RECURSIVE  cte (TheDate) AS (
    SELECT cast(DATE_FORMAT(now(), '%Y-%m-%d') AS date)
    UNION ALL
    SELECT CAST(DATE_ADD(TheDate, INTERVAL -1 DAY)  AS date)
    FROM   cte 
    WHERE  TheDate >= cast(DATE_ADD(now(), INTERVAL -6 MONTH)  AS date)
) 
SELECT YEAR(cte.TheDate) AS TheYear
        , MONTH(cte.TheDate) AS TheMonth
        , SUM(q.qTotalPrice) AS DollarTotal 
        , COUNT(q.quoteKeyID) as QuoteCount
FROM cte LEFT JOIN (
        SELECT Quotes.qDateTime
            , Quotes.QuoteKeyID
            , Quotes.qTotalPrice
        FROM Quotes INNER JOIN Accounts
        ON Quotes.aID = Accounts.aID
        WHERE Accounts.aID = <cfqueryparam value="#VNAI.aID#" cfsqltype="cf_sql_clob" maxlength="255">
        AND 
        Quotes.qDateTime > DATE_ADD(NOW(), INTERVAL -365 DAY)
    ) q ON q.qDateTime = cte.TheDate
GROUP BY YEAR(cte.TheDate) 
        , MONTH(cte.TheDate)

哪个将返回月份/年份,总计如下:

CTE + OUTER JOIN Results

NB:您的“ AID”列可能不是 cf_sql_clob。检查数据类型并相应地更新cfsqltype。

答案 2 :(得分:0)

我通过添加一个主表名称作为reportmonths获得了解决方案。其中有12行的数据,最近一年为“月份和年份”列。因此,可以通过将表与我的查询正确连接来实现。现在,我可以使用LIMIT 6获得最近六个月的记录。

SELECT RP.ReportYear AS `year`, RP.ReportMonth AS `month`, A.DollarTotal, A.QuoteCount
    FROM
        (   
            SELECT
                YEAR(qDateTime) AS qYear, MONTH(qDateTime) AS qMonth,
                SUM(qTotalPrice) AS DollarTotal , COUNT(quoteKeyID) AS QuoteCount
            FROM Accounts A
                INNER JOIN Quotes Q ON A.aID = Q.aID
            WHERE A.aID = 216
            GROUP BY YEAR(qDateTime), MONTH(qDateTime)
        ) A
    RIGHT JOIN ReportMonths RP ON  RP.ReportYear = qYear 
    AND  RP.ReportMonth =  qMonth 
    ORDER BY `year` DESC, `month` DESC LIMIT 6