V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
JasonTsang
V2EX  ›  MySQL

mysql 求一条 SQL 写法

  •  
  •   JasonTsang · 2019-07-15 18:31:50 +08:00 · 5833 次点击
    这是一个创建于 1991 天前的主题,其中的信息可能已经有所发展或是发生改变。

    用户表 1 user 用户登录日志表 2 user_login_log

    两表通过 member_id 关联

    现在 user_login_log 左连接到 user 表中 ( LEFT   JOIN )

    select * from user left join user_login_log on user.id=user_login_log.member_id

    ...

    问题来了,如何通过联表 如何查询 没有登录过的用户?就是说 查询 user_login_log 表中没有登录日志的用户。

    我试过

    select * from user left join user_login_log on user.id=user_login_log.member_id where user_login_log.member_id is null 不行

    select * from user left join user_login_log on user.id=user_login_log.member_id where user_login_log.member_id="" 也不行

    20 条回复    2019-08-04 18:12:11 +08:00
    FleyX
        1
    FleyX  
       2019-07-15 18:45:35 +08:00
    可以用子查询来解决。类似这样的写法:select * from ( selec * from a left join b on a.id = b.aId )a where a.bId is null

    但是:非常不推荐这么写,效率太低了,数据量一大就会慢的怀疑人生。
    建议这么来实现这个功能:用户表新增一个字段,记录用户上次登录时间。这样就能方便快捷的进行各种查询。
    zpaopao
        2
    zpaopao  
       2019-07-15 18:54:29 +08:00
    SELECT * FROM USER a
    WHERE NOT EXISTS (SELECT * FROM user_login_log b on a.id=b.member_id)
    zpaopao
        3
    zpaopao  
       2019-07-15 19:02:06 +08:00
    我也不知道我的对不对,你可以试试。。。
    JasonTsang
        4
    JasonTsang  
    OP
       2019-07-15 19:03:12 +08:00
    @zpaopao 一定要嵌套么?因为框架 无法使用嵌套
    @FleyX 框架不能嵌套 SQL 有没有别的方法 就在 where 后加条件?
    lanterboy
        5
    lanterboy  
       2019-07-15 19:12:11 +08:00
    2L 正解
    lanterboy
        6
    lanterboy  
       2019-07-15 19:13:47 +08:00
    select * from user a
    where not exists (select 1 from user_login_log b where a.id=b.member_id)
    2L 把 where 打成 on 了
    starsriver
        7
    starsriver  
       2019-07-15 19:14:34 +08:00 via Android
    这么写业务容易出问题
    NullErro
        8
    NullErro  
       2019-07-15 19:54:17 +08:00
    我想知道 left outer join 为啥不行????
    user 表结构:
    +---------+-----------+
    | user_id | user_name |
    +---------+-----------+
    | 1 | a |
    | 2 | b |
    | 3 | c |
    +---------+-----------+
    login_log 表:
    +-----------+-------+
    | member_id | other |
    +-----------+-------+
    | 2 | te |
    +-----------+-------+
    mysql> select a.user_id, a.user_name
    -> from
    -> (select user_id, user_name from tmp_user_0715)a
    -> left outer join
    -> (select member_id from tmp_user_login_log_0715)b
    -> on a.user_id=b.member_id
    -> where b.member_id is null;
    +---------+-----------+
    | user_id | user_name |
    +---------+-----------+
    | 1 | a |
    | 3 | c |
    +---------+-----------+
    2 rows in set (0.01 sec)

    完全可以啊
    lolizeppelin
        9
    lolizeppelin  
       2019-07-15 20:08:57 +08:00
    连登陆日志表,用户量大等死吧 233
    你以为你是 pg 啊
    ma836323493
        10
    ma836323493  
       2019-07-15 23:00:57 +08:00
    建议楼主先去了解了解 left join 和 join 的用法
    @zpaopao not exits 和 这个 哪个好 呢 select * from user join user_login_log on user.id=user_login_log.member_id where user_login_log.member_id is null
    zpaopao
        11
    zpaopao  
       2019-07-16 09:01:31 +08:00
    @ma836323493

    个人意见:楼主的写法是错误的,在 LEFT JOIN 或者 JOIN 的时候,下面的 WHERE 语句,只是对原始数据表 user_login_log 的进行条件判定,而不是对笛卡尔积,在本身的错误的情况下,且如果 user_login_log 的 MEMBER_ID 是 PRIMARY KEY,是不会出现为空的子集。
    zpaopao
        12
    zpaopao  
       2019-07-16 09:11:28 +08:00
    如果楼主不想嵌套,

    可以用 FULL OUTER JOIN
    LeeSeoung
        13
    LeeSeoung  
       2019-07-16 09:45:04 +08:00
    先把 left join 结果包一层 select,把 is null 的判断放这里试试。我印象中这样写是没问题的。
    husky
        14
    husky  
       2019-07-16 10:04:09 +08:00
    一定要联表吗,分两次查?
    fuxiuyin
        15
    fuxiuyin  
       2019-07-16 10:26:59 +08:00
    select user.id, count(user_login_log.id) as count from user left join user_login_log on user.id=user_login_log.member_id group by id having count=0;
    fuxiuyin
        16
    fuxiuyin  
       2019-07-16 10:27:50 +08:00
    实验了一下,没错,这样可以,count user_login_log 表的任意字段就行。
    fuxiuyin
        17
    fuxiuyin  
       2019-07-16 10:47:22 +08:00
    并且这么做应该是比嵌套查询快的。SQL 是描述要什么的语法,字查询更像是程序那种命令式的语法,先做什么后做什么,这样的话数据库自己是没什么优化的余地的。
    回复不支持 md,所以要好好看的话还是复制走吧,join 会用 index,字查询就是扫表。

    https://paste.ubuntu.com/p/MsFyKXbrW3/
    zpaopao
        18
    zpaopao  
       2019-07-16 12:55:47 +08:00
    感觉自己说复杂了,不知道为什么发不出来,其实楼主用 LEFT JOIN 也可以,只是不能写 where member_id is null 应该写 where 登陆日期 is null .. (至少我在自己本地数据库创建了 2 个表试了下是没问题的)
    zpaopao
        19
    zpaopao  
       2019-07-16 13:01:52 +08:00
    初学 SQL 的我,感觉自己也混乱了。。。楼主都试试吧···
    fuxiuyin
        20
    fuxiuyin  
       2019-08-04 18:12:11 +08:00
    今天看自己的回复列表的时候突然看到这个,反应过来了,这个就是集合 A-集合 B
    select * from user left join user_login_log on user.id=user_login_log.member_id where user_login_log.member_id is null;
    应该是可以的,然后又试了一下,这个在 PostgreSQL 上是没问题的,MySQL 上有问题,是 MySQL 自己的问题,MySQL 的实现看上去不是完整的关系运算。
    https://stackoverflow.com/questions/406294/left-join-vs-left-outer-join-in-sql-server
    可以看一下第一个回答的图。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5509 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 06:54 · PVG 14:54 · LAX 22:54 · JFK 01:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.