Php 请提供复杂SQL查询优化建议
Php 请提供复杂SQL查询优化建议,php,mysql,sql,database,Php,Mysql,Sql,Database,在此处输入code我有一个结构如下的表: | ID (bigint) | APPID (Bigint)| USAGE_START_TIME (datetime) | SESSION_TIME (bigint) | USERID (bigint) | ----------------------------------------------------------------------------------------------------------- | 1
在此处输入code
我有一个结构如下的表:
| ID (bigint) | APPID (Bigint)| USAGE_START_TIME (datetime) | SESSION_TIME (bigint) | USERID (bigint) |
-----------------------------------------------------------------------------------------------------------
| 1 | 1 | 2013-05-03 04:42:55 | 400 | 12 |
| 2 | 1 | 2013-05-12 06:22:45 | 200 | 12 |
| 3 | 2 | 2013-06-12 08:44:24 | 350 | 12 |
| 4 | 2 | 2013-06-24 04:20:56 | 2 | 12 |
| 5 | 3 | 2013-06-26 08:20:26 | 4 | 12 |
| 6 | 4 | 2013-09-12 05:48:27 | 50 | 12 |
现在,如果put是userid,我想得到过去6个月每个月(所有应用程序)的总会话时间(总和)
如果一个应用在一个月内使用超过一次(基于使用情况\开始\时间),则该应用的总和中只应包括最近的会话\时间
对于上面的示例,结果应该是这样的(如果当前月份是10月,输入是userid=13):
此处,月份以数字形式表示月份(例如:10表示10月)
目前,我每个月都使用单独的查询。例如:
SELECT
COALESCE(SUM(failcount),0) AS TOTAL_SESSION_TIME , MONTH(CURRENT_DATE) AS MONTH
FROM appstime
WHERE MONTH(`USAGE_START_TIME`) = MONTH(CURRENT_DATE) AND userid=12
但这并没有给我预期的结果
另外,我想知道我是否可以通过单个查询而不是每个月的查询来实现这一点。
我正在使用PHP+Mysql
请检查此处的sql FIDLE:
谢谢你,Sash您是否需要
分组依据
SELECT
SUM(COALESCE(SESSION_TIME,0)) AS TOTAL_SESSION_TIME ,
MONTH(USAGE_START_TIME) AS THE_MONTH
FROM appstime
WHERE userid=13 AND
DATE(SESSION_TIME) > DATE_SUB(NOW(), INTERVAL 6 MONTH)
GROUP BY THE_MONTH
更新:
这会将结果限制为每个appid每月的最大日期:
SELECT
SUM(COALESCE(session_time,0)) AS TOTAL_SESSION_TIME ,
MONTH(usage_start_time) AS THE_MONTH
FROM appstime
INNER JOIN
(
SELECT appid , MAX(usage_start_time) AS max_app_date
FROM appstime
GROUP BY appid
) grouped_apps ON
grouped_apps.appid = appstime.appid AND
grouped_apps.max_app_date = appstime.usage_start_time
WHERE userid=12
GROUP BY THE_MONTH
您想要分组方式吗
SELECT
SUM(COALESCE(SESSION_TIME,0)) AS TOTAL_SESSION_TIME ,
MONTH(USAGE_START_TIME) AS THE_MONTH
FROM appstime
WHERE userid=13 AND
DATE(SESSION_TIME) > DATE_SUB(NOW(), INTERVAL 6 MONTH)
GROUP BY THE_MONTH
更新:
这会将结果限制为每个appid每月的最大日期:
SELECT
SUM(COALESCE(session_time,0)) AS TOTAL_SESSION_TIME ,
MONTH(usage_start_time) AS THE_MONTH
FROM appstime
INNER JOIN
(
SELECT appid , MAX(usage_start_time) AS max_app_date
FROM appstime
GROUP BY appid
) grouped_apps ON
grouped_apps.appid = appstime.appid AND
grouped_apps.max_app_date = appstime.usage_start_time
WHERE userid=12
GROUP BY THE_MONTH
您需要使用聚合函数(即,
分组依据
):
编辑仅通过
userid
和appid
显示任何月份的最新会话时间
。请注意,因此,调用此字段total\u session\u time
可能不是一个好主意
select latest.userid,
latest.appid,
month(latest.usage_start_time) as month,
latest.session_time as latest_session_time
from appstime as latest
left join appstime as later
on later.userid = latest.userid
and later.appid = latest.appid
and later.usage_start_time > latest.usage_start_time
where later.id is null;
您需要使用聚合函数(即,
分组依据
):
编辑仅通过
userid
和appid
显示任何月份的最新会话时间
。请注意,因此,调用此字段total\u session\u time
可能不是一个好主意
select latest.userid,
latest.appid,
month(latest.usage_start_time) as month,
latest.session_time as latest_session_time
from appstime as latest
left join appstime as later
on later.userid = latest.userid
and later.appid = latest.appid
and later.usage_start_time > latest.usage_start_time
where later.id is null;
如果我正确理解了您的问题,那么这应该是您的查询(当前日期的IBM DB2语法): 这将统计过去6个月每月的所有会话时间 干杯 编辑:
这将获取当月来自同一应用程序的所有应用程序调用。要从同一应用程序id获取最后一次呼叫,您需要一个存储过程来执行此操作。每个月有6个变量,如果日期大于同一个月的最后一个日期,则在select循环中进行检查。我建议您使用MySQL的等效日期(current date)函数来比较从0年开始的日期(以天为单位)。如果我正确理解您的问题,那么这应该是您的查询(当前日期的IBM DB2语法): 这将统计过去6个月每月的所有会话时间 干杯 编辑:
这将获取当月来自同一应用程序的所有应用程序调用。要从同一应用程序id获取最后一次呼叫,您需要一个存储过程来执行此操作。每个月有6个变量,如果日期大于同一个月的最后一个日期,则在select循环中进行检查。我建议您使用MySQL的等效天数(当前日期)功能,以天为单位比较自0年以来的日期。未测试,但类似于以下内容:-
SELECT ForMonths.aMonth, IFNULL(SUM(SESSION_TIME), 0)
FROM
(
SELECT MONTH(DATE_ADD(NOW(), INTERVAL aInt MONTH)) AS aMonth
FROM
(
SELECT 0 AS aInt UNION SELECT -1 UNION SELECT -2 UNION SELECT -3 UNION SELECT -4 UNION SELECT -5
) aCnt
) ForMonths
LEFT OUTER JOIN
(
SELECT a.USERID, a.APPID, aMonth, SESSION_TIME
FROM appstime a
INNER JOIN
(
SELECT USERID, APPID, MONTH(USAGE_START_TIME) AS aMonth, MAX(USAGE_START_TIME) AS USAGE_START_TIME
FROM appstime
GROUP BY USERID, APPID, aMonth
) b
ON a.USERID = b.USERID
AND a.USAGE_START_TIME = b.USAGE_START_TIME
AND a.APPID = b.APPID
WHERE a.USERID = 12
) ForDetails
ON ForMonths.aMonth = ForDetails.aMonth
GROUP BY ForMonths.aMonth
可以简化,但只需一个子查询即可获得过去6个月的每个月,并将该子查询与另一个子查询合并,即可获得用户每个月的最新金额
编辑-使用年和月:-
SELECT ForMonths.aMonth, IFNULL(SUM(SESSION_TIME), 0)
FROM
(
SELECT EXTRACT(YEAR_MONTH FROM DATE_ADD(NOW(), INTERVAL aInt MONTH)) AS aMonth
FROM
(
SELECT 0 AS aInt UNION SELECT -1 UNION SELECT -2 UNION SELECT -3 UNION SELECT -4 UNION SELECT -5
) aCnt
) ForMonths
LEFT OUTER JOIN
(
SELECT a.USERID, a.APPID, aMonth, SESSION_TIME
FROM appstime a
INNER JOIN
(
SELECT USERID, APPID, EXTRACT(YEAR_MONTH FROM USAGE_START_TIME) AS aMonth, MAX(USAGE_START_TIME) AS USAGE_START_TIME
FROM appstime
GROUP BY USERID, APPID, aMonth
) b
ON a.USERID = b.USERID
AND a.USAGE_START_TIME = b.USAGE_START_TIME
AND a.APPID = b.APPID
WHERE a.USERID = 12
) ForDetails
ON ForMonths.aMonth = ForDetails.aMonth
GROUP BY ForMonths.aMonth
ORDER BY ForMonths.aMonth
未测试,但类似于以下内容:-
SELECT ForMonths.aMonth, IFNULL(SUM(SESSION_TIME), 0)
FROM
(
SELECT MONTH(DATE_ADD(NOW(), INTERVAL aInt MONTH)) AS aMonth
FROM
(
SELECT 0 AS aInt UNION SELECT -1 UNION SELECT -2 UNION SELECT -3 UNION SELECT -4 UNION SELECT -5
) aCnt
) ForMonths
LEFT OUTER JOIN
(
SELECT a.USERID, a.APPID, aMonth, SESSION_TIME
FROM appstime a
INNER JOIN
(
SELECT USERID, APPID, MONTH(USAGE_START_TIME) AS aMonth, MAX(USAGE_START_TIME) AS USAGE_START_TIME
FROM appstime
GROUP BY USERID, APPID, aMonth
) b
ON a.USERID = b.USERID
AND a.USAGE_START_TIME = b.USAGE_START_TIME
AND a.APPID = b.APPID
WHERE a.USERID = 12
) ForDetails
ON ForMonths.aMonth = ForDetails.aMonth
GROUP BY ForMonths.aMonth
可以简化,但只需一个子查询即可获得过去6个月的每个月,并将该子查询与另一个子查询合并,即可获得用户每个月的最新金额
编辑-使用年和月:-
SELECT ForMonths.aMonth, IFNULL(SUM(SESSION_TIME), 0)
FROM
(
SELECT EXTRACT(YEAR_MONTH FROM DATE_ADD(NOW(), INTERVAL aInt MONTH)) AS aMonth
FROM
(
SELECT 0 AS aInt UNION SELECT -1 UNION SELECT -2 UNION SELECT -3 UNION SELECT -4 UNION SELECT -5
) aCnt
) ForMonths
LEFT OUTER JOIN
(
SELECT a.USERID, a.APPID, aMonth, SESSION_TIME
FROM appstime a
INNER JOIN
(
SELECT USERID, APPID, EXTRACT(YEAR_MONTH FROM USAGE_START_TIME) AS aMonth, MAX(USAGE_START_TIME) AS USAGE_START_TIME
FROM appstime
GROUP BY USERID, APPID, aMonth
) b
ON a.USERID = b.USERID
AND a.USAGE_START_TIME = b.USAGE_START_TIME
AND a.APPID = b.APPID
WHERE a.USERID = 12
) ForDetails
ON ForMonths.aMonth = ForDetails.aMonth
GROUP BY ForMonths.aMonth
ORDER BY ForMonths.aMonth
虽然我在获取6个月的记录时遇到了问题,但我本可以在我的另一台机器上完成,但在当前机器上没有MySQL。我从Kickstart(因为他在那里的信誉)那里删掉了那部分 无论如何,我从6个月前和现在的12个用户开始,开始了一个最内在的“预查询”(别名PQ)。为了确保我不只是从今天(本月2日)算起6个月,或者即使是在本月26日算起,而是想要6个月前的第一天,我做了一些日期计算,先到6个月前的最后一天,然后在下个月的第一天加上1天。因此,这将创造 10月2-6个月=4月2日。。。然后移到4月30日的最后一天,然后再加上1天到5月1日。现在,从5月1日到10月1日,其中10月是第6个月,如果1天到整个月。如果你想从4月1日到现在,那就回到7个月前 因此,我将每月获得每个应用程序、用户和每个月的最大实例。我将用户包括在内,以防将来需要所有用户,而不仅仅是一个 一旦查询到每个应用程序/用户/月的MAX(),我就会再次加入会话,但只加入匹配的会话 最后,通过一个左连接应用到外部月份列表中,剩下的就剩下了。同样,如果需要所有用户,可以将用户添加到外部查询和GROUPBY子句中
SELECT
AllMonths.aMonth,
COALESCE( SUM( Ap2.Session_Time ), 0 ) as Total_Session_Time
from
( SELECT MONTH(DATE_ADD(NOW(), INTERVAL aInt MONTH)) AS aMonth
FROM
(
SELECT 0 AS aInt
UNION SELECT -1
UNION SELECT -2
UNION SELECT -3
UNION SELECT -4
UNION SELECT -5
) aCnt ) AllMonths
LEFT JOIN
( select
appstime.AppID,
appstime.UserID,
MONTH( appstime.Usage_Start_Time ) as PerMonth,
MAX( appstime.Usage_Start_Time ) as ThisTime
from
( select @StartDate := last_day( now() - interval 6 month ) + interval 1 day ) sqlvars,
appstime
where
appstime.Usage_Start_Time >= @StartDate
AND appstime.UserID = 12
group by
appstime.AppID,
appstime.UserID,
MONTH( appstime.Usage_Start_Time ) ) PQ
ON AllMonths.aMonth = PQ.PerMonth
LEFT JOIN appstime Ap2
ON PQ.AppID = Ap2.AppID
AND PQ.UserID = Ap2.UserID
AND PQ.ThisTime = Ap2.Usage_Start_Time
group by
AllMonths.aMonth
虽然我在获取6个月的记录时遇到了问题,但我本可以在我的另一台机器上完成,但在当前机器上没有MySQL。我从Kickstart(因为他在那里的信誉)那里删掉了那部分 无论如何,我从6个月前和现在的12个用户开始,开始了一个最内在的“预查询”(别名PQ)。为了确保我不只是从今天(本月2日)算起6个月,或者即使是在本月26日算起,而是想要6个月前的第一天,我做了一些日期计算,先到6个月前的最后一天,然后在下个月的第一天加上1天。因此,这将创造 10月2-6个月=4月2日。。。然后移到4月30日的最后一天,然后再加上1天到5月1日。现在,从5月1日到10月1日,其中10月是第6个月,如果1天到整个月。如果你想从4月1日到现在,那就回到7个月前 因此,我将每月获得每个应用程序、用户和每个月的最大实例。我将用户包括在内,以防您需要所有用户,而不仅仅是fu中的一个用户