【问题标题】:Single left join query with an extra level of indirection具有额外间接级别的单左连接查询
【发布时间】: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.i​​d=us.user_id 或 NULL”。

我知道还有其他完全不同的解决方案,比如合并表 usersessions 和 sessions 以便 user_id 是会话中的 NULL:able 列,或者只是进行两个查询等(这些方法正是我一直在使用的多年来“解决”类似情况),但我特别想知道是否有办法使用上面指定的表配置来检查会话是否有效,如果它是登录会话(并获取用户如果是名称),在一个查询中?

【问题讨论】:

    标签: sql sqlite join


    【解决方案1】:

    您可以链接左外连接:

    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 值的用户表记录获取空值

    【讨论】:

    • 这是我尝试过的事情之一,但我将两个连接的顺序颠倒了。我没想到订单很重要。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-12
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    相关资源
    最近更新 更多