单左连接查询,具有额外的间接级别

时间:2015-11-28 23:44:59

标签: sql sqlite join

我有三个表:用户,会话和usersessions。 users-table包含系统中所有用户的列表,sessions表是所有当前Web客户端会话的列表,usersessions是一个表,用于跟踪哪些会话具有用户登录。

注意sessions.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    

这原则上是我想要的信息; user_id中sess_id = 1的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和session,以便user_id在会话中是NULL:able列,或者只是进行两次查询等(这些方法正是我所做的那样)这些年来一直在使用以解决类似情况,但我特别想知道是否有一种方法,使用上面指定的表配置来检查会话是否有效,如果是登录会话(如果是,则获取用户名),在一个查询中?

1 个答案:

答案 0 :(得分:0)

您可以链接左外连接:

SELECT s.id AS sess_id,us.user_id AS user_id,s.ip, users.name
  FROM sessions AS s
  LEFT OUTER JOIN usersessions AS us ON us.sess_id=s.id
  LEFT OUTER JOIN users ON users.id = us.user_id

这将为每个没有user_sessions.user_id值的用户表记录获取空值