【发布时间】:2015-11-28 23:44:59
【问题描述】:
我有三个表:users、sessions 和 usersessions。 users-table 包含系统中所有用户的列表,sessions 表是所有当前 Web 客户端会话的列表,usersessions 是跟踪哪些会话有用户登录的表。
注意 session.id(主键整数)和 sessid(本质上是 HTTP cookie)之间的区别。
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
passwd TEXT NOT NULL
);
CREATE TABLE sessions (
id INTEGER PRIMARY KEY,
sessid TEXT UNIQUE NOT NULL,
last_access DATETIME NOT NULL DEFAULT current_timestamp,
ip TEXT NOT NULL
);
CREATE TABLE usersessions (
id INTEGER PRIMARY KEY,
sess_id INTEGER UNIQUE NOT NULL,
user_id INTEGER NOT NULL,
FOREIGN KEY(sess_id) REFERENCES sessions(id),
FOREIGN KEY(user_id) REFERENCES users(id),
UNIQUE(sess_id, user_id)
);
我使用以下测试数据:
users:
id name passwd
---------- ---------- ----------------------------------------
1 frank 8843d7f92416211de9ebb963ff4ce28125932878
2 elena 8843d7f92416211de9ebb963ff4ce28125932878
3 drake 8843d7f92416211de9ebb963ff4ce28125932878
sessions:
id sessid last_access ip
---------- ---------- ------------------- ------------
1 mysess 2015-11-28 18:27:46 172.16.0.128
2 unusedsess 2015-11-28 18:27:46 10.0.0.1
usersessions:
id sess_id user_id
---------- ---------- ----------
1 1 2
当连接到 Web 服务器时,我想查询数据库(使用 cookie 中的会话 id)以获取会话的 id(主键)以及登录的用户 id 和名称(如果有)。
我找到了很多类似问题的答案,但这些往往只涉及两个表格;即喜欢:
SELECT s.id AS sess_id,us.user_id AS user_id,s.ip
FROM sessions AS s
LEFT OUTER JOIN usersessions AS us ON us.sess_id=s.id;
这将返回:
sess_id user_id ip
---------- ---------- ------------
1 2 172.16.0.128
2 10.0.0.1
原则上这是我想要的信息; sess_id=1 的 user_id 中的 NULL 告诉我会话 2 不是登录会话。但是,我还想要获取登录会话的用户名(否则为 NULL);即我想要结果:
sess_id user_id user ip
---------- ---------- ------ ------------
1 2 elena 172.16.0.128
2 10.0.0.1
由于 NULL (us.user_id != u.id),我提出的查询总是最终过滤掉非登录会话。
我通过执行两个查询轻松解决了这个问题,但我的问题是这是否可以在单个查询中完成?我基本上想将“用户”列设置为(概念上)“用户表中的名称列,如果没有匹配,则为 u.id=us.user_id 或 NULL”。
我知道还有其他完全不同的解决方案,比如合并表 usersessions 和 sessions 以便 user_id 是会话中的 NULL:able 列,或者只是进行两个查询等(这些方法正是我一直在使用的多年来“解决”类似情况),但我特别想知道是否有办法使用上面指定的表配置来检查会话是否有效,如果它是登录会话(并获取用户如果是名称),在一个查询中?
【问题讨论】: