对于下表:
房间
+----+--------+
| ID | NAME |
+----+--------+
| 1 | ROOM_1 |
| 2 | ROOM_2 |
+----+--------+
ROOM_STATE
+----+---------+------+------------------------+
| ID | ROOM_ID | OPEN | DATE |
+----+---------+------+------------------------+
| 1 | 1 | 1 | 2000-01-01 00:00:00 |
| 2 | 2 | 1 | 2000-01-01 00:00:00 |
| 3 | 2 | 0 | 2000-01-06 00:00:00 |
+----+---------+------+------------------------+
存储的数据是最后更改状态的空间:
ROOM_1仍处于打开状态,ROOM_2已关闭(自2000-01-06以来未开启)。如何通过连接选择实际打开的房间名称?如果我写道:
SELECT ROOM.NAME
FROM ROOM
INNER JOIN ROOM_STATE ON ROOM.ID = ROOM_STATE.ROOM_ID
WHERE ROOM_STATE.OPEN = 1
选择了ROOM_1和ROOM_2,因为ROOM_STATE
ID
2
为OPEN
。
答案 0 :(得分:3)
在Postgres中,我建议distinct on
:
select distinct on (rs.room_id) r.name, rs.*
from room_state rs join
room r
on rs.room_id = r.id
order by rs.room_id, rs.date desc;
distinct on
特定于Postgres。它保证每个房间的结果只有一行(这就是你想要的)。所选行是遇到的第一行,因此选择具有最大日期的行。
另一种有趣的方法是使用横向连接:
select r.*, rs.*
from room r left join lateral
(select rs.*
from room_state rs
where rs.room_id = r.id
order by rs.date desc
fetch first 1 row only
) rs;
答案 1 :(得分:2)
您可以使用以下查询:
SELECT R.ID, R.NAME
FROM ROOM AS R
INNER JOIN ROOM_STATE AS RS ON R.ID = RS.ROOM_ID AND RS.OPEN = 1
LEFT JOIN ROOM_STATE AS RS2 ON R.ID = RS2.ROOM_ID AND RS2.OPEN = 0 AND RS2.DATE > RS.date
WHERE RS2.ID IS NULL
这将返回与“开放”状态相关的所有房间和与“关闭”状态无关,该状态的日期位于“开放”状态的日期之后。< / p>
答案 2 :(得分:0)
如果你可以保证每次打开你都关闭并且总是如此,你也可以使用这个疯狂的sql;)
SELECT r.ID, r.NAME
FROM ROOM r
WHERE (select sum(CASE WHEN OPEN = 0 THEN -1 ELSE 1 END) from room_state rs where rs.room_id=r.id) = 1;
答案 3 :(得分:0)
有几种方法可以给这只猫上皮。 @ GiorgosBetsos&#39;答案是一种方式。另:
WITH Numbered_Status AS
(
SELECT
id,
room_id,
open,
ROW_NUMBER() OVER (PARTITION BY room_id ORDER BY date DESC) AS row_num
FROM
Room_State
)
SELECT
R.id,
R.name,
S.open
FROM
Numbered_Status S
INNER JOIN Room R ON R.room_id = S.room_id
WHERE
row_num = 1 AND
open = 1
您也可以使用NOT EXISTS
:
SELECT
R.id,
R.name,
S.open
FROM
Room_State S
INNER JOIN Room R ON R.id = S.room_id
WHERE
S.open = 1 AND
NOT EXISTS
(
SELECT *
FROM Room_State S2
WHERE
S2.room_id = S.room_id AND
S2.date > S.date
)
答案 4 :(得分:0)
连接条件在想要的ROOM_STATE行上的可能解决方案:
SELECT R.ID, R.NAME
FROM ROOM AS R
INNER JOIN ROOM_STATE AS RS ON R.ID = RS.ROOM_ID
AND RS.DATE = (
SELECT DATE
FROM ROOM_STATE
WHERE ROOM_ID = R.ID
ORDER BY DATE DESC
LIMIT 1
)
WHERE RS.OPEN = 1