【问题标题】:In SQL How to iterate through a list of value in where clause在SQL中如何遍历where子句中的值列表
【发布时间】:2022-01-17 10:59:31
【问题描述】:

我有一个名为“titles”的表,它具有以下值:

id   title  time
1    ABC    1-1-2021
2    EEE    1-1-2021
3    ABC    1-1-2020
4    123    2-1-2020

现在我想从这个表中选择带有给定列表的记录,例如:

let title_to_search = [ABC, 123]

按 DESC 中的“时间”列排序

我想在搜索表“标题”后得到以下结果:

id   title  time
1    ABC    1-1-2021
4    123    2-1-2020

我尝试过以下状态:

select * from titles where title in title_to_search order by time DESC

结果是

id   title  time
1    ABC    1-1-2021
3    ABC    1-1-2020
4    123    2-1-2020

这是由 id "3" 也有 title 值 "ABC" 引起的。但是,我想要的是遍历列表,这意味着如果“ABC”已在where子句中使用,则不应再次使用,因此应选择记录“1”,不应选择“3” , 应该选择 4。

这样的SQL语句怎么写?

我正在使用 MySQL 数据库。

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    我认为你需要这样的东西

    SELECT a.*
    FROM titles a
    WHERE a.title IN ( 'ABC', '123' )
    AND NOT EXISTS (
     SELECT 1
     FROM titles b
     WHERE b.title = a.title
     AND b.id < a.id
    )
    

    b.id &lt; a.id 可以根据您的要求更改,可能是time

    关于性能

    mysql> SELECT COUNT(*) FROM titles a WHERE a.title IN ( 'A2617', 'A6983' );
    +----------+
    | COUNT(*) |
    +----------+
    |       33 |
    +----------+
    1 row in set (0.00 sec)
    
    mysql> select count(*) from titles;
    +----------+
    | count(*) |
    +----------+
    |   707280 |
    +----------+
    1 row in set (0.03 sec)
    
    mysql> EXPLAIN SELECT a.* FROM titles a WHERE a.title IN ( 'A2617', 'A6983' ) AND NOT EXISTS (  SELECT 1  FROM titles b  WHERE b.title = a.title  AND b.id < a.id );
    +----+-------------+-------+------------+-------+---------------+-------+---------+--------------+------+----------+--------------------------------------+
    | id | select_type | table | partitions | type  | possible_keys | key   | key_len | ref          | rows | filtered | Extra                                |
    +----+-------------+-------+------------+-------+---------------+-------+---------+--------------+------+----------+--------------------------------------+
    |  1 | SIMPLE      | a     | NULL       | range | _Idx1         | _Idx1 | 32      | NULL         |   33 |   100.00 | Using index condition                |
    |  1 | SIMPLE      | b     | NULL       | ref   | PRIMARY,_Idx1 | _Idx1 | 32      | test.a.title |    1 |   100.00 | Using where; Not exists; Using index |
    +----+-------------+-------+------------+-------+---------------+-------+---------+--------------+------+----------+--------------------------------------+
    2 rows in set, 3 warnings (0.00 sec)
    
    mysql> SELECT a.* FROM titles a WHERE a.title IN ( 'A2617', 'A6983' ) AND NOT EXISTS (  SELECT 1  FROM titles b  WHERE b.title = a.title  AND b.id < a.id );
    +--------+-------+------------+
    | id     | title | time       |
    +--------+-------+------------+
    | 404071 | A2617 | 2021-12-14 |
    | 397458 | A6983 | 2021-12-14 |
    +--------+-------+------------+
    2 rows in set (0.01 sec)
    
    mysql> SELECT a.* FROM titles a WHERE a.title IN ( 'A2617', 'A6983' );
    +--------+-------+------------+
    | id     | title | time       |
    +--------+-------+------------+
    | 404071 | A2617 | 2021-12-14 |
    | 495677 | A2617 | 2021-12-14 |
    | 505974 | A2617 | 2021-12-14 |
    | 522148 | A2617 | 2021-12-14 |
    | 523088 | A2617 | 2021-12-14 |
    | 545776 | A2617 | 2021-12-14 |
    | 546174 | A2617 | 2021-12-14 |
    | 565224 | A2617 | 2021-12-14 |
    | 594082 | A2617 | 2021-12-14 |
    | 634224 | A2617 | 2021-12-14 |
    | 663641 | A2617 | 2021-12-14 |
    | 684980 | A2617 | 2021-12-14 |
    | 727136 | A2617 | 2021-12-14 |
    | 733046 | A2617 | 2021-12-14 |
    | 738378 | A2617 | 2021-12-14 |
    | 747396 | A2617 | 2021-12-14 |
    | 397458 | A6983 | 2021-12-14 |
    | 398483 | A6983 | 2021-12-14 |
    | 416826 | A6983 | 2021-12-14 |
    | 418081 | A6983 | 2021-12-14 |
    | 426902 | A6983 | 2021-12-14 |
    | 454826 | A6983 | 2021-12-14 |
    | 479057 | A6983 | 2021-12-14 |
    | 486494 | A6983 | 2021-12-14 |
    | 492336 | A6983 | 2021-12-14 |
    | 515798 | A6983 | 2021-12-14 |
    | 570730 | A6983 | 2021-12-14 |
    | 587073 | A6983 | 2021-12-14 |
    | 627372 | A6983 | 2021-12-14 |
    | 672636 | A6983 | 2021-12-14 |
    | 699460 | A6983 | 2021-12-14 |
    | 722743 | A6983 | 2021-12-14 |
    | 747387 | A6983 | 2021-12-14 |
    +--------+-------+------------+
    33 rows in set (0.00 sec)
    

    【讨论】:

    • 谢谢,但是这种方法的性能有点慢。它甚至比我使用 Java 代码通过数组“titles”迭代来进行多个数据库查询还要慢。
    • 比较纯 SQL 和应用程序代码的性能是不公平的。 SQL 是通用的,高度依赖于索引设置,而你的应用程序代码确切地知道业务逻辑,有时它是更好的选择。
    • @ZhangZhan 在这种特殊情况下,如果id 是主键并且标题也被索引,则添加NOT EXISTS 子句不会花费
    【解决方案2】:

    以下将适用于示例数据以及所有额外数据:

    从 id 所在的标题中选择 * (SELECT MIN(ID) FROM TITLES WHERE TITLE IN TITLE_TO_SEARCH GROUP BY TITLE)

    【讨论】:

    • 谢谢,但是您缺少“时间”列,如果我只是在选择中添加“时间”,我会收到错误:[代码:1055,SQL 状态:42000] SELECT 的表达式#3列表不在 GROUP BY 子句中,并且包含非聚合列“TITLES.time”,它在功能上不依赖于 GROUP BY 子句中的列;这与 sql_mode=only_full_group_by 不兼容
    • 这应该可以工作 :: Select * from Titles where id in (SELECT MIN(ID) FROM TITLES WHERE TITLE IN TITLE_TO_SEARCH GROUP BY TITLE)
    • 不,它没有。时间需要汇总。使用 * 将无法摆脱它。此外,逻辑是按时间排序的,不一定与您正在执行的 ID 相关 MIN(ID)
    • 抱歉,我不确定我是否理解需要聚合的时间的含义。 where 子句子查询获取按标题分组的最小 id,如果您需要按时聚合,则在子查询组中按标题后的子句添加。然后根据该 ID 选择整行。你能发布你得到的查询和结果吗?
    猜你喜欢
    • 1970-01-01
    • 2021-12-05
    • 2023-03-03
    • 2018-10-12
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-09
    相关资源
    最近更新 更多