我正在使用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>
为了获取每个月的记录,我编写了一个查询查询,如下所示。
获取当前月份
<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>
等等...明智的是,我必须得过去六个月。所以我每个月写了许多查询。
是否有可能减少代码?
答案 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;
结果:
现在要按月计算总数和计数,只需将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)
哪个将返回月份/年份,总计如下:
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