【问题标题】:Combining multiple SELECT query results from ONE table组合来自一张表的多个 SELECT 查询结果
【发布时间】:2019-04-20 03:14:08
【问题描述】:

我的表coordinates是:

id (PK) SERIAL, address (VARCHAR), city (VARCHAR), latitude (VARCHAR), longitude (VARCHAR)

我有一个包含 10,000 个地址的列表,如果该地址存在于表中,我将遍历这些地址以检索相应的纬度/经度。

SELECT 查询看起来像:

SELECT ADDRESS, CITY, LATITUDE, LONGITUDE FROM coordinates WHERE address = ? AND city = ?

然后我检查结果集以查看是否有匹配项。其他 9,999 个地址然后通过上面的查询循环,这需要太长时间。

有没有办法创建一个包含所有 10,000 个地址的查询并返回一个包含 4 列的结果集:|address|city|latitude|longitude|

任何未找到的地址在该结果集列中都应该有一个空的(0 或 null)纬度/经度值。我假设我可以循环结果集以识别任何遗漏的内容,这比 10,000 条语句要快得多。

最好的方法是什么?

【问题讨论】:

  • 你为什么同时做=LIKE?条件x LIKE '%FOO%' 包括所有x = 'FOO' 为真的记录。
  • “我正在执行 10,000 次 SELECT 查询” 但您也说 “这里是其中的 1/4” 并显示了一个带有 3 SELECT 的语句子句,所以如果 3 是 1/4,那么你正在执行 12 个 SELECT 查询,而不是 10,000 个。
  • 不,你误会了,这可能是我的错。我会改写它:SELECT 涉及 UNION 的查询是 12 个查询....但它的目的是在我的表中找到一个地址/坐标匹配。就像我解释的那样,这 12 个查询解释了地址的差异。我有 10,000 addresses 每个将通过 12 查询 SELECT/UNION 块。明白了吗?
  • 因此,与其循环所有 10,000 个地址并单独将它们的地址/城市放入 SELECT/UNION 查询中...我想要一个包含所有 10,000 个地址的查询,因此速度要快得多。

标签: java postgresql


【解决方案1】:

更新:更改为在结果中包含不匹配的“查询”地址,并添加了 QUERY_ID 以帮助识别“查询”地址,这可能只是列表中提供查询参数的索引。

由于是PostgreSQL,可以使用VALUES子句,例如

SELECT q.QUERY_ID
     , c.ADDRESS
     , c.CITY
     , c.LATITUDE
     , c.LONGITUDE
  FROM (VALUES (1, ?, ?)
             , (2, ?, ?) // repeat as many times as needed
             , (3, ?, ?)
       ) AS q (QUERY_ID, ADDRESS, CITY)
  LEFT JOIN coordinates AS c
       ON  c.ADDRESS LIKE q.ADDRESS
       AND c.CITY LIKE q.CITY

现在您需要遍历您的 10000 个地址并为该 PreparedStatement 设置所有值。

【讨论】:

  • 谢谢,这看起来很有希望。你介意解释一下这个查询在做什么,因为我很困惑tc 是什么。此外,不匹配的地址必须作为空的纬度/经度包含在结果集中,以便我可以识别哪些不匹配。
  • 这行得通,而且肯定更快。非常感谢安德烈亚斯
【解决方案2】:

查询长度可能是 10,000 对的问题。另外,如果你绝对需要一击完成,你可以试试这个。

将值插入临时表。那么:

SELECT tbl.val1, tbl.val2
FROM tbl
WHERE (tbl.val1, tbl.val2) in (select tmp_table.val1, tmp_table.val2 from tmp_table);

也可以选择 JOIN,而不是 IN。

更新:

(1) 插入必须是每行一个。可能会创建一个带有一些 COMMIT 的脚本文件;几百行中的语句。如果它是从 Java 完成的,您可以使用 JDBC addBatch 在 500/1000 行中提交一次。

--Create temp table before this with two columns address (VARCHAR), city (VARCHAR)
INSERT INTO TMP_TABLE VALUES ( ?, ?); //Prepare statement and addBatch

(2, 3, 4)

SELECT ADDRESS, CITY, LATITUDE, LONGITUDE
FROM coordinates
WHERE (ADDRESS, CITY) in (select tmp_table.address, tmp_table.city from tmp_table);

【讨论】:

  • 谢谢,如果有更快的替代方法,我不需要在一个查询中执行此操作。您的回答让我想知道(1)insert to temp table 代码是什么样的(2)您的代码实际上在做什么。 (3) val1 和 val2 在我的问题中对应什么。 (4) 我的查询响应需要 4 列 (address, city, lon, lat) 而不仅仅是 2 (val1, val2)。
  • @Andreas 正在将整个 10,000 加载到查询中的虚拟表中并进行连接。如果可行,它可能是更好的选择。即便如此,您也可以一次尝试他的方法 500 或 1000。但是,由于字符串的长度可能会发生变化,因此巨大的查询可能会变得不可预测。我的方法相对更安全,但可能会慢一些。但是,它仍然比 10,000 个单独的选择查询要快。所以,这是一种中等性能的方法。
  • 谢谢。为什么字符串的长度会发生变化?如果我使用 StringBuilder 构建准备好的语句,然后设置适当数量的参数,我看不出字符串长度在哪里起作用。
  • 一个 1MB 的查询字符串,然后一个 PreparedStatement 应该就可以了。一个难得的机会,它可能会抛出 OutOfMemoryError。如果您按行数对其进行批处理,并且每行的大小可能不同,则查询的大小也会有所不同。 1000 行在一次运行中可能是 10KB,或者在下一次运行中可能是 50KB。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多