【问题标题】:How to rewrite SQL query without IN clause如何在没有 IN 子句的情况下重写 SQL 查询
【发布时间】:2017-07-12 04:21:14
【问题描述】:

架构:

Table A: AID(PK), RECEIVE_DATE
Table B: BID(PK), AID(FK), MESSAGE, ITEMID, ITEMTYPE

表 A 到 B 具有一对多映射。

这是一个有效的 SQL 查询(在 SQL Server 中),用于查找按 ITEMID 分组的最新消息,即针对不同的 ITEMID(ITEMTYPE 表示为“XYZ”)。

 SELECT 
     b.MESSAGE, b.ITEMID
 from a
 inner join b on b.aid = a.aid AND b.ITEMTYPE = 'XYZ'
 where a.receive_date in (select max(receive_date)
                                             from a a1
                                             inner join b b1 on b1.aid = a1.aid   
                                             where b1.itemid = b.itemid
                                             );

我们如何在没有IN 子句的情况下重写这个 SQL 查询[也没有使用行号概念],因为 ORACLE 对 IN 子句有限制。获取 java.sql.SQLSyntaxErrorException: ORA-01795: 对于上述表达式,列表中的最大表达式数为 1000。

【问题讨论】:

  • 您确定这是查询产生的错误吗? AFAIK,该限制仅在 IN 子句中传递值时应用,例如 a.receive_date in ('2017-01-01','2017-02-01',..)
  • 您可以简单地将IN 更改为= 并获得相同的结果,而不是使用INNER JOIN 重写查询
  • @Prdp 也许错误是由于在具有太多记录的IN 表达式中存在中间查询引起的。只是猜测。
  • IN 子句有两种形式——基于值和基于子查询。该限制仅适用于他们的第一个。第二个被优化器默默地重写到一个连接上。我不相信您的查询确实返回了该错误。当子查询返回多于一列时,您可能会收到错误 - 但这是语义错误。您的子查询仅返回一个值,因此 IN 甚至可以被纯 = 替换。我认为您在发布之前“匿名”了查询,真正的问题在其他地方。 ps:使用解析函数可以避免自连接。
  • 如果您的一个表有 > 1000 个分区,那么 ORA-01795 可能与此处提到的错误有关:-stackoverflow.com/a/45050530/430567(还提到了 NO_EXPAND_TABLE 提示,您可以尝试验证这是否是问题),

标签: sql sql-server oracle


【解决方案1】:

我不清楚你为什么收到ORA-01795。您的子查询只选择一个最大值,它应该是一个值。此外,1000 值限制仅适用于文字列表,不适用于子查询。在任何情况下,您都可以使用连接而不是 WHERE IN 来改写此查询:

SELECT 
    b.MESSAGE,
    b.ITEMID
FROM a
INNER JOIN b
    ON b.aid = a.aid AND b.ITEMTYPE = 'XYZ'
INNER JOIN
(
    SELECT
        b1.itemid,
        MAX(receive_date) AS max_receive_date
    FROM a a1
    INNER JOIN b b1
        ON b1.aid = a1.aid   
    GROUP BY b1.itemid
) t
    ON b.itemid = t.itemid
WHERE a.receive_date = t.max_receive_date

【讨论】:

    【解决方案2】:

    EXISTSIN 往往可以互换,而EXISTS 在某些引擎中表现更好(不确定Oracle),因为它在第一次匹配时返回true,而不是生成一个子集并检查反对。我不熟悉 Oracle,但我想您可以使用以下内容来规避 IN 的 1000 行限制:

    SELECT 
        b.MESSAGE, b.ITEMID
    from a
    inner join b on b.aid = a.aid AND b.ITEMTYPE = 'XYZ'
    where exists (
        SELECT 1
        from a a1
        inner join b b1 on b1.aid = a1.aid   
        where b1.itemid = b.itemid
        having MAX(a1.receive_date) = a.receive_date
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-27
      • 1970-01-01
      • 1970-01-01
      • 2020-08-09
      • 1970-01-01
      • 2022-01-03
      • 1970-01-01
      • 2011-12-07
      相关资源
      最近更新 更多