MySQL 显示特定值后计数
MySQL Count after an specific value shows
问题是,我需要在达到人数后计算 pages/hits 的平均人数
页面(包括 pax hit)。
数据库是:
CREATE TABLE search (
SESSION_ID INTEGER,
HIT_NUMBER INTEGER,
PAGE VARCHAR(24),
MEDIUM_T VARCHAR(24)
);
INSERT INTO search
(SESSION_ID, HIT_NUMBER, PAGE, MEDIUM_T)
VALUES
('123', '1', 'home', 'direct'),
('123', '2', 'flights_home', 'direct'),
('123', '3', 'results', 'direct'),
('456', '1', 'pax', 'metasearch'),
('789', '1', 'home', 'partners'),
('789', '2', 'flights_home', 'partners'),
('789', '3', 'results', 'partners'),
('789', '4', 'home', 'partners'),
('146', '1', 'results', 'SEM'),
('146', '2', 'pax', 'SEM'),
('146', '3', 'payment', 'SEM'),
('146', '4', 'confirmation', 'SEM');
而我的做法是:
SELECT s1.SESSION_ID, COUNT(*) as sCOUNT
FROM search s1
WHERE PAGE = 'pax'
GROUP BY s1.SESSION_ID
UNION ALL
SELECT 'Total AVG', AVG(a.sCOUNT)
FROM (
SELECT COUNT(*) as sCOUNT
FROM search s2
GROUP BY s2.SESSION_ID
) a
显然 3r 行是错误的,我的代码遗漏了显示 'pax' 之后开始计数的部分,我对此一无所知。
先谢谢你:)
查找所有 pax
个页面及其之后的页面可以用 exists
完成。休息很简单:
SELECT AVG(hits)
FROM (
SELECT session_id, COUNT(*) AS hits
FROM search AS s1
WHERE page = 'pax' OR EXISTS (
SELECT *
FROM search AS s2
WHERE s2.session_id = s1.session_id
AND s2.hit_number < s1.hit_number
AND s2.page = 'pax'
)
GROUP BY session_id
) AS x
如果使用 MySQL 8 那么 window 函数提供了一个更简单的解决方案:
WITH cte1 AS (
SELECT session_id, MAX(CASE WHEN page = 'pax' THEN 1 END) OVER (
PARTITION BY session_id
ORDER BY hit_number
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS countme
FROM search
), cte2 as (
SELECT COUNT(*) AS hits
FROM cte1
WHERE countme IS NOT NULL
GROUP BY session_id
)
SELECT AVG(hits)
FROM cte2
我的方法使用 WITH CTE (common-table-expression) pre-declare 底层查询基础是什么,然后从中进行查询和平均。
第一个前提未明确包含在您的样本数据中。会发生什么 IF 用户在多个页面之间来回跳动并多次点击 PAX 页面。您现在有多个 pax 页面点击。我会假设你想要第一个实例到这样的 pax 页面,并且包括所有页面点击。此解决方案应该有助于解决这个问题。
让我们看看带有最终别名“pxHits”的 inner-most from 子句。
我按会话 ID 分组并获取 pax 页面命中的第一个实例(如果没有遇到此类 pax 页面,则为 null),但也获取每个会话的最高命中数。 HAVING 子句将确保仅 returns 返回具有 PAX 页面的那些会话,而将所有其他会话排除在结果之外。
这将导致两个条目传递到外部 select,其中包括 1 + lastHitNumber - firstPaxHit
计算。 1 + 的原因是因为您至少点击了该页面一次。但是,在您的会话 456 的情况下,第一个和最后一个点击是第一页,您需要它,因为 lastHitNumber - firstPaxHit 将净为零。如果一个人有 25 个页面点击并到达第 26 页的 pax 页面,这将是正确的。你的结果仍然是 1 通过 1 + 26 - 26 = 1 总页面包括 pax 页面,而不是之前的 25。
您的其他排位赛将是 146。第一个 pax hit 是 2,但他们进行了最高页面点击 4。所以 1 + 4 - 2 = 3 总页数。
现在进入决赛。由于您可以看到事情是如何准备的,我们现在可以得到平均值。您不能 mix/auto 转换不同的数据类型(session_id 与 'Total Avg' 的固定消息。它们必须是同一类型。所以我的查询是将 session_id 转换为要匹配的字符。我碰巧首先从 WITH CTE 别名中获取 AVERAGE 查询作为简单的 select,然后获取实际的 session_id 和计数。
with PaxSummary as
(
select
pxHits.*,
1 + lastHitNumber - firstPaxHit HitsIncludingPax
from
( select
session_id,
min( case when page = 'pax'
then hit_number
else null end ) firstPaxHit,
max( hit_number ) lastHitNumber
from
search
group by
session_id
having
min( case when page = 'pax'
then hit_number
else null end ) > 0 ) pxHits
)
select
'Avg Pax Pages' FinalMsg,
avg( ps2.HitsIncludingPax ) HitsIncludingPax
from
PaxSummary ps2
union all
select
cast( ps1.session_id as varchar) FinalMsg,
ps1.HitsIncludingPax
from
PaxSummary ps1
作为 EXISTS (correlated subquery)
模式的替代方案,我们可以编写一个查询,为每个 session_id 获取第一个 'pax' 命中的 hit_number,然后使用作为内联视图。
大致如下:
-- count hits on or after the first 'pax' of each session_id that has a 'pax' hit
SELECT s.session_id
, COUNT(*) AS cnt_hits_after_pax
FROM ( -- get the first 'pax' hit for each session_id
-- exclude session_id that do not have a 'pax' hit
SELECT px.session_id AS pax_session_id
, MIN(px.hit_number) AS pax_hit_number
FROM search px
WHERE px.page = 'pax'
) p
-- all the hits for session_id on or after the first 'pax' hit
JOIN search s
ON s.session_id = p.session_id
AND s.hit_number >= p.hit_number
GROUP BY s.session_id
要从该查询中获取平均值,我们可以将其包裹起来并将其转换为内联视图
SELECT AVG(c.cnt_hits_after_pax) AS avg_cnt_hits_after_pax
FROM (
-- query above goes here
) c
问题是,我需要在达到人数后计算 pages/hits 的平均人数 页面(包括 pax hit)。
数据库是:
CREATE TABLE search (
SESSION_ID INTEGER,
HIT_NUMBER INTEGER,
PAGE VARCHAR(24),
MEDIUM_T VARCHAR(24)
);
INSERT INTO search
(SESSION_ID, HIT_NUMBER, PAGE, MEDIUM_T)
VALUES
('123', '1', 'home', 'direct'),
('123', '2', 'flights_home', 'direct'),
('123', '3', 'results', 'direct'),
('456', '1', 'pax', 'metasearch'),
('789', '1', 'home', 'partners'),
('789', '2', 'flights_home', 'partners'),
('789', '3', 'results', 'partners'),
('789', '4', 'home', 'partners'),
('146', '1', 'results', 'SEM'),
('146', '2', 'pax', 'SEM'),
('146', '3', 'payment', 'SEM'),
('146', '4', 'confirmation', 'SEM');
而我的做法是:
SELECT s1.SESSION_ID, COUNT(*) as sCOUNT
FROM search s1
WHERE PAGE = 'pax'
GROUP BY s1.SESSION_ID
UNION ALL
SELECT 'Total AVG', AVG(a.sCOUNT)
FROM (
SELECT COUNT(*) as sCOUNT
FROM search s2
GROUP BY s2.SESSION_ID
) a
显然 3r 行是错误的,我的代码遗漏了显示 'pax' 之后开始计数的部分,我对此一无所知。
先谢谢你:)
查找所有 pax
个页面及其之后的页面可以用 exists
完成。休息很简单:
SELECT AVG(hits)
FROM (
SELECT session_id, COUNT(*) AS hits
FROM search AS s1
WHERE page = 'pax' OR EXISTS (
SELECT *
FROM search AS s2
WHERE s2.session_id = s1.session_id
AND s2.hit_number < s1.hit_number
AND s2.page = 'pax'
)
GROUP BY session_id
) AS x
如果使用 MySQL 8 那么 window 函数提供了一个更简单的解决方案:
WITH cte1 AS (
SELECT session_id, MAX(CASE WHEN page = 'pax' THEN 1 END) OVER (
PARTITION BY session_id
ORDER BY hit_number
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS countme
FROM search
), cte2 as (
SELECT COUNT(*) AS hits
FROM cte1
WHERE countme IS NOT NULL
GROUP BY session_id
)
SELECT AVG(hits)
FROM cte2
我的方法使用 WITH CTE (common-table-expression) pre-declare 底层查询基础是什么,然后从中进行查询和平均。
第一个前提未明确包含在您的样本数据中。会发生什么 IF 用户在多个页面之间来回跳动并多次点击 PAX 页面。您现在有多个 pax 页面点击。我会假设你想要第一个实例到这样的 pax 页面,并且包括所有页面点击。此解决方案应该有助于解决这个问题。
让我们看看带有最终别名“pxHits”的 inner-most from 子句。
我按会话 ID 分组并获取 pax 页面命中的第一个实例(如果没有遇到此类 pax 页面,则为 null),但也获取每个会话的最高命中数。 HAVING 子句将确保仅 returns 返回具有 PAX 页面的那些会话,而将所有其他会话排除在结果之外。
这将导致两个条目传递到外部 select,其中包括 1 + lastHitNumber - firstPaxHit
计算。 1 + 的原因是因为您至少点击了该页面一次。但是,在您的会话 456 的情况下,第一个和最后一个点击是第一页,您需要它,因为 lastHitNumber - firstPaxHit 将净为零。如果一个人有 25 个页面点击并到达第 26 页的 pax 页面,这将是正确的。你的结果仍然是 1 通过 1 + 26 - 26 = 1 总页面包括 pax 页面,而不是之前的 25。
您的其他排位赛将是 146。第一个 pax hit 是 2,但他们进行了最高页面点击 4。所以 1 + 4 - 2 = 3 总页数。
现在进入决赛。由于您可以看到事情是如何准备的,我们现在可以得到平均值。您不能 mix/auto 转换不同的数据类型(session_id 与 'Total Avg' 的固定消息。它们必须是同一类型。所以我的查询是将 session_id 转换为要匹配的字符。我碰巧首先从 WITH CTE 别名中获取 AVERAGE 查询作为简单的 select,然后获取实际的 session_id 和计数。
with PaxSummary as
(
select
pxHits.*,
1 + lastHitNumber - firstPaxHit HitsIncludingPax
from
( select
session_id,
min( case when page = 'pax'
then hit_number
else null end ) firstPaxHit,
max( hit_number ) lastHitNumber
from
search
group by
session_id
having
min( case when page = 'pax'
then hit_number
else null end ) > 0 ) pxHits
)
select
'Avg Pax Pages' FinalMsg,
avg( ps2.HitsIncludingPax ) HitsIncludingPax
from
PaxSummary ps2
union all
select
cast( ps1.session_id as varchar) FinalMsg,
ps1.HitsIncludingPax
from
PaxSummary ps1
作为 EXISTS (correlated subquery)
模式的替代方案,我们可以编写一个查询,为每个 session_id 获取第一个 'pax' 命中的 hit_number,然后使用作为内联视图。
大致如下:
-- count hits on or after the first 'pax' of each session_id that has a 'pax' hit
SELECT s.session_id
, COUNT(*) AS cnt_hits_after_pax
FROM ( -- get the first 'pax' hit for each session_id
-- exclude session_id that do not have a 'pax' hit
SELECT px.session_id AS pax_session_id
, MIN(px.hit_number) AS pax_hit_number
FROM search px
WHERE px.page = 'pax'
) p
-- all the hits for session_id on or after the first 'pax' hit
JOIN search s
ON s.session_id = p.session_id
AND s.hit_number >= p.hit_number
GROUP BY s.session_id
要从该查询中获取平均值,我们可以将其包裹起来并将其转换为内联视图
SELECT AVG(c.cnt_hits_after_pax) AS avg_cnt_hits_after_pax
FROM (
-- query above goes here
) c