【问题标题】:SQL Read Where IN (Long List from .TXT file)SQL 读取 Where IN(来自 .TXT 文件的长列表)
【发布时间】:2018-03-09 10:19:23
【问题描述】:

我有一个长长的列表,大约有 5000 多个 ID(数字)。

ID
4
5
6
9
10
14
62
63
655
656
657
658
659
661
662

我想知道是否有一种方法可以调用从 txt 文件中读取 ID,而不是在查询中输入全部 5000?

例子

SELECT count(*) from table where ID in (file1.txt)

【问题讨论】:

  • 最好将这些临时加载到表中,然后与现有表进行内部连接。只要你有正确的索引,我希望性能更快而不是ID in (thousands of values)
  • 不确定您使用的是哪个版本的 SQL,但在 Firebird 2.5 中,如果“in”子句中的值超过 1500 个,我发现查询失败。
  • 这是什么 DBMS 产品?在读取或写入外部文件等方面,不同的产品非常不同。对于他们中的大多数人来说,如果需要一次性将列表从 GUI 复制并粘贴到表格中,通常会更容易。
  • @user206168 我已经添加了一个答案。对不起,我不能早点回复你。随意评论答案。我认为你问了一个非常好的问题。

标签: sql where-clause where-in


【解决方案1】:

第 1 步:在 sublime 或 notepad++ 中复制所有值 第 2 步:按 ctrl+h 选择“正则表达式”选项 第 3 步:在每行末尾添加“,”,

在“查找内容”字段中键入 $, 和“,”在“替换为”字段中。然后点击“全部替换”。

然后只需复制粘贴 SQL 查询中的值

SELECT COUNT(*) FROM `admins` WHERE id in (4,
5,
6,
9,
10,
14,
62,
63,
655,
656,
657,
658,
659,
661,
662)

PS:请务必从最后一个值中删除逗号。

【讨论】:

  • 虽然这会起作用(至少在大多数数据库中),但在 OP 提到的 5000 多个项目中使用 in 条件将导致执行速度极慢。
【解决方案2】:

你有几个选择,其中一个是我推荐的。

选项 1

像这样在你的数据库中创建一个表:

create table ID_Comparer (
    ID int primary key
);

使用您选择的编程语言,清空该表,然后在该表中加载您最终要查询的 5000 多个 ID。

然后,编写以下查询之一来提取您想要的数据:

select *
from main_table m
where exists (
    select 1 from ID_Comparer where ID = m.ID
)

select *
from main_table m
inner join ID_Comparer c on m.ID = c.ID

由于 ID_Comparer 和(假设)main_table 的 ID 是索引/键控的,因此匹配应该相对较快。

选项 1 已修改

此选项与上面的选项类似,但对并发性有所帮助。这意味着,如果应用程序 1 想要比较 2000 个 ID,而应用程序 2 想要同时将 5000 个 ID 与您的主表进行比较,则您不希望从比较表中删除数据。所以,稍微改变一下表格。

create table ID_Comparer (
    ID int primary key,
    token char(32), -- index this
    entered date default current_date() -- use the syntax of your DB
);

然后,使用您最喜欢的编程语言创建 GUID。将所有 ID 和相同的 GUID 加载到表中,如下所示:

1, 7089e5eced2f408eac8b390d2e891df5
2, 7089e5eced2f408eac8b390d2e891df5
...

另一个执行相同操作的进程将使用 GUID 加载自己的 ID

2412, 96d9d6aa6b8d49ada44af5a99e6edf56
9434, 96d9d6aa6b8d49ada44af5a99e6edf56
...

现在,您的选择:

select *
from main_table m
where exists (
    select 1 from ID_Comparer where ID = m.ID and token = '<your guid>'
)

select *
from main_table m
inner join ID_Comparer c on m.ID = c.ID and token = '<your guid>'

收到数据后,请务必执行delete from ID_Comparer where token = '&lt;your guid&gt;' - 这将是很好的清理工作

您可以创建一个夜间任务来删除所有超过 2 天的数据或一些类似的数据以进行额外的内务管理。

由于 ID_Comparer 和(假设)main_table 的 ID 是索引/键控的,因此即使 GUID 是附加键控查找,匹配也应该相对较快。

选项 2

您可以像这样创建一个大型 SQL 查询,而不是创建一个表:

select * from main_table where id = <first id>
union select * from main_table where id = <second id>
union select * from main_table where id = <third id>
...

select * from main_table where id IN (<first 5 ids>)
union select * from main_table where id IN (<next 5 ids>)
union select * from main_table where id IN (<next 5 ids>)
...

如果性能可以接受,并且您觉得像选项 1 那样创建新表不合适,您可以尝试其中一种方法。

(假设)main_table 的 ID 是索引/键控的,单独匹配可能会导致更快的查询,而不是匹配一长串逗号分隔值。那是一种猜测。您必须查看查询计划并针对测试用例运行它。

选择哪个选项?

测试这些选项应该很快。我建议使用您的数据库引擎和表的大小尝试所有这些选项,看看哪一个最适合您的用例。

【讨论】:

    【解决方案3】:

    简单回答(PostgreSQL,Ubuntu 16.04):

    假设您有一张表userdogs,其中包含许多用户及其狗的名字: 用户狗

    id    user     dog
    

    您还有一个文件friendsfile.txt,其中有您朋友的姓名。并且您只想从userdogs 表中选择您的朋友。

    friendsfile.txt

    Emily
    John
    Bill
    Charlie
    Cameron
    

    1。创建一个新表并从里面的文件插入东西:

    CREATE TABLE friends (name varchar(200));

    COPY friends
    FROM '/home/friendsfile.txt' 
    WITH DELIMITER '~';
    

    如果文件看起来像这样

    Emily/John/Bill/Charlie/Cameron
    

    这样的东西应该可以工作(未经测试,我的情况是换行):

    COPY friends
    FROM '/home/friendsfile.txt' 
    WITH DELIMITER('|');
    

    2.

    然后你去选择他们:

    SELECT DISTINCT  user, dog FROM userdogs 
    WHERE (SELECT COUNT(*) 
    FROM friends 
    WHERE friends.name=userdogs.user)>0;
    

    【讨论】:

      猜你喜欢
      • 2016-10-24
      • 2020-02-14
      • 2016-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多