我有一个USERS表。
每个用户都在CONNECTIONS表中有连接。
每个连接都有一个日期时间和一些引用的属性,如时区,存储在TZ参考表中。
我想为第一个和最后一个连接选择userID和TimeZoneLabel。即使用户没有连接(因此会显示NULL或其他任何内容)
做类似的事情:
Select USERS.id,
min(TZ.label),
max(TZ.label)
from USERS
join CONNECTION on USERS.id = CONNECTIONS.userid
join TZ on TZ.id = CONNECTIONS.tzid
group by USERS.id
order by max(CONNECTIONS.dateconn)
但我无法做到这一点。我在网上发现了关于这一点的文章,但是当我尝试时没有任何作用。上面的示例不适用于标签,因为没有真正的最小/最大值,而是在第一个CONNECTION上使用的值和在最后一个上使用的值。
我在实际请求中有很多这些,所以我想避免过多的子选择。
答案 0 :(得分:1)
没有时区:
SELECT
u.id AS userId
, MIN(c.dateconn) AS firstConnectionDatetime
, MAX(c.dateconn) AS lastConnectionDateTime
FROM Users AS u
LEFT JOIN Connection AS c
ON u.id = c.userid
GROUP BY u.id
ORDER BY lastConnectionDateTime
使用时区(假设Connection
表格id
为Primary Key
):
SELECT
u.id AS userId
, ConMin.dateconn AS firstConnectionDatetime
, ConMax.dateconn AS lastConnectionDateTime
, TzMin.label AS firstTimeZoneLabel
, TzMax.label AS lastTimeZoneLabel
FROM Users AS u
LEFT JOIN Connection AS ConMax
ON ConMax.id =
( SELECT c.id
FROM Connection AS c
WHERE u.id = c.userid
ORDER BY c.dateconn DESC
LIMIT 1
)
LEFT JOIN TzMax
ON TzMax.id = ConMax.tzid
LEFT JOIN Connection AS ConMin
ON ConMin.id =
( SELECT c.id
FROM Connection AS c
WHERE u.id = c.userid
ORDER BY c.dateconn ASC
LIMIT 1
)
LEFT JOIN TzMin
ON TzMin.id = ConMin.tzid
(userid, dateconn, id)
表上的复合Connection
索引有助于提高性能。
答案 1 :(得分:1)
对于这个答案有一些解释 - 你所追求的实际查询是在底部。
这是一个不仅选择每组最大/最小字段,还要选择与其对应的其他字段的实例。
执行此操作的规范方法是通过LEFT JOIN
将表格移植到自身。
例如,要从CONNECTIONS
中选择与最新连接相对应的整行,您需要执行以下操作:
SELECT c.userid, c.tzid as latestTZ, c.dateconn as latestConn
FROM CONNECTIONS c
LEFT JOIN CONNECTIONS c2 ON c.userid=c2.userid AND c.dateconn<c2.dateconn
WHERE c2.dateconn IS NULL
ORDER BY c.userid;
这基本上会在CONNECTIONS
上将userid
加入到自身,并在该用户ID中c.dateconn<c2.dateconn
内形成每对可能的连接日期。如果c2
中没有一行的日期大于c
,那么您选择了最大的(即最近的)日期。
JOIN
确保您还从表中选择相应行的其余部分。
考虑到这一点,这就是我们为每个用户选择第一个连接日期和标签的方式(如果他们从未连接过,则为NULL
。如果您不想要这种行为(即仅显示)已连接的用户)然后您可以完全忽略USERS
表。
SELECT u.id,c.dateconn as firstConnection,TZ.label AS firstTZ
FROM USERS u
LEFT JOIN CONNECTIONS c ON u.id=c.userid
LEFT JOIN CONNECTIONS c2 ON c.userid=c2.userid AND c.dateconn > c2.dateconn
LEFT JOIN TZ ON c.tzid=TZ.id
WHERE c2.dateconn IS NULL;
选择最新版本是相同的,但您将>
撤消到<
:
SELECT u.id,c.dateconn as latestConnection,TZ.label AS latestTZ
FROM USERS u
LEFT JOIN CONNECTIONS c ON u.id=c.userid
LEFT JOIN CONNECTIONS c2 ON c.userid=c2.userid AND c.dateconn < c2.dateconn
LEFT JOIN TZ ON c.tzid=TZ.id
WHERE c2.dateconn IS NULL;
您的查询有点复杂,因为您不仅要选择最小值或最大值,而且两者 min 和最大值
我认为你可以UNION
前两个查询,或者你可以在基本JOIN
的一次犯规中完成所有这两个查询:
# MIN & MAX
SELECT u.id, c.dateconn as firstCon, TZ.label as firstTZ,
c3.dateconn as latestCon, TZ2.label as latestTZ
FROM USERS u
LEFT JOIN CONNECTIONS c ON u.id=c.userid
LEFT JOIN CONNECTIONS c2 ON c.userid=c2.userid AND c.dateconn > c2.dateconn
LEFT JOIN CONNECTIONS c3 ON c.userid=c3.userid AND c3.dateconn >= c.dateconn
LEFT JOIN CONNECTIONS c4 ON c3.userid=c4.userid AND c3.dateconn < c4.dateconn
LEFT JOIN TZ ON TZ.id=c.tzid
LEFT JOIN TZ TZ2 ON TZ2.id=c3.tzid
WHERE c2.dateconn IS NULL
AND c4.dateconn IS NULL
ORDER BY u.id;
(c,c2)
对找到第一个连接日期/时区,(c3,c4)
对找到最新的。
此外,与c3
的联接实际上并不需要c3.dateconn>=c.dateconn
量词(它只需要加入userid
),但它会使我们拥有的行缩小加入。这是因为我们在(c3,c4)
表中寻找最新的(即MAX)日期,并且c
包含MIN日期,我们只需要查看MAX日期所在的行&gt; ; = MIN日期。
答案 2 :(得分:0)
尝试LEFT JOIN而不是JOIN。 在ORDER BY之前添加GROUP BY USERS.id