Php 从一个表中获取另一个表中不存在的记录
我知道标题听起来好像已经有几十个类似的问题,但我认为这一个有点不同。不过,如果已经有一个类似的问题,请告诉我 基本上,我有两个表:Php 从一个表中获取另一个表中不存在的记录,php,mysql,group-by,unix-timestamp,Php,Mysql,Group By,Unix Timestamp,我知道标题听起来好像已经有几十个类似的问题,但我认为这一个有点不同。不过,如果已经有一个类似的问题,请告诉我 基本上,我有两个表:用户和简历。下面是他们的模式片段: users: id signup_time resumes: id user_id modified_time 现在,我需要获取在用户指定的时间范围内(所有日期都是UNIX时间戳)没有简历的所有用户的总数,一般来说,当他们没有上传简历时,按天、周或月进行分组。这是最让我困扰的问题,因为如果不是分组,查询可能会
用户
和简历
。下面是他们的模式片段:
users:
id signup_time
resumes:
id user_id modified_time
现在,我需要获取在用户指定的时间范围内(所有日期都是UNIX时间戳)没有简历的所有用户的总数,一般来说,当他们没有上传简历时,按天、周或月进行分组。这是最让我困扰的问题,因为如果不是分组,查询可能会如下所示:
SELECT u.id FROM `jb_users` u WHERE
u.id NOT IN (
SELECT r.user_id FROM `jb_resumes` r
WHERE (r.modified_time BETWEEN 1330581600 AND 1335848399)
) AND u.signup_time >= 1330581600
例如,让我们考虑一些例子。希望这样更容易理解
假设我们有数据:
users
id signup_time
---------------
1 1340214369 (20.06.2012)
2 1330754400 (03.03.2012)
3 1329285600 (15.02.2012)
4 1324447200 (21.12.2011)
resumes
id user_id modified_time
--------------------------
1 1 1340214369 (20.06.2012)
2 2 1330840800 (04.03.2012)
3 2 1340214369 (20.06.2012)
4 3 1334506920 (15.04.2012)
5 3 1334638800 (17.04.2012)
6 2 1334638800 (17.04.2012)
7 3 1336798800 (12.05.2012)
对于时间范围2012年3月1日00:00:00-2012年4月30日23:59:59(按月份分组),应返回:
count user_ids time
2 3,4 1330840800 (03.2012 - can be any date in the month, in fact)
1 4 1334506920 (04.2012 - can be any date in the month, in fact)
count user_ids time
2 3,4 1330840800 (04.03.2012)
2 2,4 1334506920 (15.04.2012)
1 4 1334638800 (17.04.2012)
对于相同的时间段,但每天分组,它应该返回:
count user_ids time
2 3,4 1330840800 (03.2012 - can be any date in the month, in fact)
1 4 1334506920 (04.2012 - can be any date in the month, in fact)
count user_ids time
2 3,4 1330840800 (04.03.2012)
2 2,4 1334506920 (15.04.2012)
1 4 1334638800 (17.04.2012)
我希望这个问题足够清楚。如果没有,请告诉我
数据将使用PHP进行处理,因此,如果无法使用单个查询(即使是子查询)实现这一点,也可以使用PHP处理数据
谢谢。试试这个:
SELECT count(u.id) FROM `jb_users` u WHERE
u.id NOT IN (
SELECT distinct r.user_id FROM `jb_resumes` r
WHERE (r.modified_time BETWEEN 1330581600 AND 1335848399)
) AND u.signup_time >= 1330581600 GROUP BY FROM_UNIXTIME(u.signup_time) ORDER BY u.signup_time
将unix时间戳返回为日期格式
它将按日期返回特定时间范围组内的总用户数。您可以根据需要转换日期格式
我在内部选择查询中添加了DISTINCT关键字,因为一个用户可以多次更新简历,否则您也可以获得不在该日期范围内的记录。尝试以下操作:
SELECT count(u.id) FROM `jb_users` u WHERE
u.id NOT IN (
SELECT distinct r.user_id FROM `jb_resumes` r
WHERE (r.modified_time BETWEEN 1330581600 AND 1335848399)
) AND u.signup_time >= 1330581600 GROUP BY FROM_UNIXTIME(u.signup_time) ORDER BY u.signup_time
将unix时间戳返回为日期格式
它将按日期返回特定时间范围组内的总用户数。您可以根据需要转换日期格式
我在内部选择查询中添加了DISTINCT关键字,因为一个用户可以多次更新resume,否则您也可以获得不在该日期范围内的记录。不确定这是否有效,但您可以尝试使用if进行连接
SELECT DISTINCT
if(r.modified_time NOT BETWEEN 1330581600 AND 1335848399, u.id, null) as UID
FROM `jb_users` u
Left Join `jb_resumes` r ON u.id = r.user_id
WHERE
u.signup_time >= 1330581600
不确定这是否有效,但您可以尝试使用if进行连接
SELECT DISTINCT
if(r.modified_time NOT BETWEEN 1330581600 AND 1335848399, u.id, null) as UID
FROM `jb_users` u
Left Join `jb_resumes` r ON u.id = r.user_id
WHERE
u.signup_time >= 1330581600
下面是我提出的按月份分组的解决方案。我在本地MySQL安装中使用了您的数据来测试结果:
SELECT
COUNT(*) AS cnt,
GROUP_CONCAT(b.id ORDER BY b.id) AS user_ids,
a.monthgroup
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
LEFT JOIN
jb_resumes c ON
b.id = c.user_id
AND a.monthgroup = MONTH(FROM_UNIXTIME(modified_time))
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
AND c.user_id IS NULL
GROUP BY
a.monthgroup
ORDER BY
a.monthgroup
导致:
然后为了比较每个monthgroup
和每个用户的组合,找出哪些用户在monthgroup
中没有修改时间,我们必须在monthgroup
和所有用户之间进行笛卡尔积。由于上面的查询已经使用了一个GROUP BY
,因此我们不能直接加入该查询,而是必须将其包装在FROM
子句中的subselect中:
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*,
c.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
LEFT JOIN
jb_resumes c ON
b.id = c.user_id
AND a.monthgroup = MONTH(FROM_UNIXTIME(modified_time))
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
AND c.user_id IS NULL
--
ORDER BY a.monthgroup, b.id #for clarity's sake
导致:
现在我们有了monthgroup
s和allid
s的组合,但我们不想包括signup\u时间晚于时间范围的用户,因此我们通过在WHERE
子句中引入第一个条件来过滤它们:
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*,
c.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
LEFT JOIN
jb_resumes c ON
b.id = c.user_id
AND a.monthgroup = MONTH(FROM_UNIXTIME(modified_time))
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
AND c.user_id IS NULL
--
ORDER BY a.monthgroup, b.id #for clarity's sake
导致:
这里我们是左加入
ing,条件是用户在jb\u resume
中有一个简历修改,并且修改发生在月组
值的月份内。如果用户当月没有修改简历,则LEFT JOIN
返回表中值的NULL
。我们需要那些条件不满足的用户,因此我们必须在where
子句中添加第二个条件:
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*,
c.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
LEFT JOIN
jb_resumes c ON
b.id = c.user_id
AND a.monthgroup = MONTH(FROM_UNIXTIME(modified_time))
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
AND c.user_id IS NULL
--
ORDER BY a.monthgroup, b.id #for clarity's sake
给我们期望的结果:
以下是我提出的按月份分组的解决方案。我在本地MySQL安装中使用了您的数据来测试结果:
SELECT
COUNT(*) AS cnt,
GROUP_CONCAT(b.id ORDER BY b.id) AS user_ids,
a.monthgroup
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
LEFT JOIN
jb_resumes c ON
b.id = c.user_id
AND a.monthgroup = MONTH(FROM_UNIXTIME(modified_time))
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
AND c.user_id IS NULL
GROUP BY
a.monthgroup
ORDER BY
a.monthgroup
导致:
然后为了比较每个monthgroup
和每个用户的组合,找出哪些用户在monthgroup
中没有修改时间,我们必须在monthgroup
和所有用户之间进行笛卡尔积。由于上面的查询已经使用了一个GROUP BY
,因此我们不能直接加入该查询,而是必须将其包装在FROM
子句中的subselect中:
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*,
c.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
LEFT JOIN
jb_resumes c ON
b.id = c.user_id
AND a.monthgroup = MONTH(FROM_UNIXTIME(modified_time))
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
AND c.user_id IS NULL
--
ORDER BY a.monthgroup, b.id #for clarity's sake
导致:
现在我们有了monthgroup
s和allid
s的组合,但我们不想包括signup\u时间晚于时间范围的用户,因此我们通过在WHERE
子句中引入第一个条件来过滤它们:
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*,
c.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
LEFT JOIN
jb_resumes c ON
b.id = c.user_id
AND a.monthgroup = MONTH(FROM_UNIXTIME(modified_time))
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
AND c.user_id IS NULL
--
ORDER BY a.monthgroup, b.id #for clarity's sake
导致:
这里我们是左加入
ing,条件是用户在jb\u resume
中有一个简历修改,并且修改发生在月组
值的月份内。如果用户当月没有修改简历,则LEFT JOIN
返回表中值的NULL
。我们需要那些条件不满足的用户,因此我们必须在where
子句中添加第二个条件:
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
--
ORDER BY a.monthgroup, b.id #for clarity's sake
SELECT
a.monthgroup,
b.*,
c.*
FROM
(
SELECT MONTH(FROM_UNIXTIME(modified_time)) AS monthgroup
FROM jb_resumes
WHERE modified_time BETWEEN
UNIX_TIMESTAMP('2012-03-01 00:00:00')
AND UNIX_TIMESTAMP('2012-04-30 23:59:59')
GROUP BY monthgroup
) a
CROSS JOIN
jb_users b
LEFT JOIN
jb_resumes c ON
b.id = c.user_id
AND a.monthgroup = MONTH(FROM_UNIXTIME(modified_time))
WHERE
b.signup_time < UNIX_TIMESTAMP('2012-04-30 23:59:59')
AND c.user_id IS NULL
--
ORDER BY a.monthgroup, b.id #for clarity's sake
给我们期望的结果:
我完全被这句话弄糊涂了:>按他们没有上传简历的日期分组,所以,嗯,你需要按他们没有提交简历的日期分组?你想按天还是按月分组?不同的查询还是在同一个查询中?@SomnathMuluk-我需要按天、周和月进行分组。@Jason'Bug'Fenter-是的,这听起来很愚蠢,但我需要将它们放在一个图表上,它的x轴使用日期。因此,我需要计算在给定时间间隔内没有上传任何简历的用户。为什么用户id1
不在示例预期结果集中(在用户id
下)?它没有介于两个日期组之间的简历,所以我不应该这样做吗