【问题标题】:Selecting rows in SQL database based on value in column matching value in list根据列表中的列匹配值选择SQL数据库中的行
【发布时间】:2021-08-05 12:57:56
【问题描述】:

我有一个包含大约 140 万行的表,我想编写一个 sql 选择语句,它返回列表中第一列中的值(唯一 ID)中存在的所有行。

此列表可以包含 1 到 50k 个 ID,并且每次运行脚本时都会生成,并且每次都可能不同。根据此列表中的 id 编号值,我只想从数据库中提取第一列中具有这些 id 编号的行。

为了更完整:我在 python 脚本中执行上述所有操作。该脚本首先生成我需要的 ID 列表。然后我使用 pyodbc 与 azure ODBC 数据库进行通信。

我的第一个想法是使用“IN”语句:

myquery = SELECT * FROM mydb WHERE id IN mylist

显然,这不起作用,因为您需要在“IN”语句之后指定特定值,因为它基本上是“OR”语句的替代品。

不幸的是,即使经过几个小时的谷歌搜索,我还是找不到一种明显且易于理解的方法来将“IN”语句与 mylist 的变量名结合使用。在这种情况下这甚至可能吗?还是有其他更好的方法来获得相同的结果?

编辑:最好我正在寻找一种方法,而不必每次运行脚本时都为我的 IDlist 生成一个新的数据库表。

【问题讨论】:

  • 你在问什么 DBMS?大多数 DBMS 没有“列表”作为有效数据类型。
  • 我建议将 ID 列表加载到 mydb.id_list 表中,然后按照 select * from mydb.table where id in (select id from mydb.id_list) 的形式或执行 inner join 到假设的 mydb.id_list
  • 为了更加清晰和完整,我正在编写一个生成此 ID 列表的 python 脚本。然后我使用 python (pyodbc) 与 azure 数据库进行通信,以检索我必须进一步处理的请求数据。这部分是关于我需要编写的 SQL 查询以从我需要的数据库中获取数据

标签: sql odbc azure-sql-database pyodbc


【解决方案1】:

我按照建议为 ID 创建了一个额外的额外表来解决这个问题。 首先,我用 ID 号制作了一个附加表,然后我使用这个表从我的完整数据库中获取所需的结果,最后我再次删除了 ID 表。

花了一点时间才找到正确的语法,但以下内容让我可以快速完成整个过程:

# Transform my list of ID's to a list of lists
id_list = [[id] for id in ids] 
ID_TABLE = 'id_db_name'

conn = pyodbc.connect(driver='{ODBC Driver 17 for SQL Server}',
                      server='MY_SERVER',
                      database='MY_DATABASE',
                      uid='USERNAME', pwd='PASSWORD')

cursor = conn.cursor()

# Create a new table to store the ID's
create_table = "CREATE TABLE id_db_name (Casenr varchar(12));"
cursor.execute(create_table)
cursor.commit()

# Fill the new ID table with my data
insert_to_tmp_tbl_stmt = f"INSERT INTO {ID_TABLE} VALUES (?)"
cursor.fast_executemany = True
cursor.executemany(insert_to_tmp_tbl_stmt, id_list)

# Get the rows from my full database based on the created ID table
compare = f"SELECT * FROM full_db_name WHERE Casenr in (SELECT * FROM id_db_name)"
cursor.execute(compare)
results = cursor.fetchall()

# Delete the ID table
delete_table = "DROP TABLE dbo.tempTable"
cursor.execute(delete_table)
cursor.commit()

# Close the connection
cursor.close()
conn.close()

虽然上面的代码可能可以稍微清理一下(我自己仍然在语法上有点挣扎,我对 SQL 还是很陌生),即使对于大型 ID 表,它也很实用且快速。

【讨论】:

    【解决方案2】:

    前段时间我遇到了同样的问题,我的任务是选择用户可以通过 .csv 文件上传的 id(varchar 类型)的查询子集。 id 的数量可能有数千个,所以我不能只使用 IN ('id1', 'id2', ...) 策略,因为 IN 子句文字仅限于 1000 个文字...

    我们的专家(我自己不能声称功劳)想出的是:

    (1) 创建一个类型

    create or replace TYPE ID_ARRAY as table of varchar2(12);
    

    (只需执行一次,该类型将在此语句之后保留在您的数据库中,直到您将其删除)

    (2) 将文字放在类似

    的语句中
    select * from (
    <insert your unrestricted sql here>
    ) FULL_DATA
    where full_data.id in 
    (
    select * from table(ID_ARRAY('id1', 'id2', .... 'id5000'))
    )
    ;
    

    这也适用于您的情况吗?

    【讨论】:

    • 如果我理解正确,您建议使用 ID 在我的数据库中创建一个新表,然后使用这个新表从我的完整数据表中获取正确的数据。这是我目前正在尝试的方法之一。然而,到目前为止我遇到的问题是创建新表也非常慢。它可以包含多达 50.000 个 ID。目前,我正在使用 python for 循环围绕 INSERT INTO 语句来逐个写入表条目,但这需要很长时间。是否有更好的方法可以在此 ID_ARRAY 表中获取我的 ID?
    • 啊,我建议您不需要先将您的 id 插入新表的方式。此外,您不需要 CREATE TABLE 和 DELETE TABLE 语句。当您使用 python 代码编写选择字符串时,您只需将 ID 添加到您的选择子句(我建议的 sql 的 ('id1', 'id2', .... 'id5000') 部分)。你需要做的是使用我在上面(1)中提出的语句创建类型。
    • 要清楚,你是说只要我在我的数据库中创建了 TABLE TYPE 并将我的 ID 在 Python 中分配为这个 TABLE TYPE 它也应该工作?这听起来像是一个更优雅的解决方案!我试试看
    • 是的。您需要按照 (1) 中的说明一次性创建 TYPE ID_ARRAY AS TABLE。如果你有这个,你可以使用 (2) 中描述的语法,创建 ID 文字列表在该语句中。 TYPE ... AS TABLE 似乎充当某种临时表(我真的不是这方面的专家...)。 :D 干杯,祝你好运!
    • 我制作了一个表格类型,但我仍在努力使用 sysntax 以使一切正常。如果我有一个 ID 值的 python 列表,我如何将它们分配给表类型?像 TABLE(ID_ARRAY('list_of_IDs')) 之类的东西。但随后是一个工作版本
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    • 1970-01-01
    • 1970-01-01
    • 2020-12-08
    • 2020-01-04
    相关资源
    最近更新 更多