在列表较大的sql查询中绑定列表

时间:2019-07-08 19:38:26

标签: python sql oracle cx-oracle

使用https://blogs.oracle.com/oraclemagazine/on-cursors-sql-and-analytics, 我创建了一种将数组绑定到SQL语句的方法,尽管可能不是最好的方法。

初始:

cursor.execute("Select * from table where column in (:id)",{"id":('A','B')})

我按照上面的说明将其更改为:

cursor.execute(with data as (select trim(substr(txt, instr(txt, ',', 1, level  ) + 1,
                                    instr (txt, ',', 1, level+1) - instr (txt, ',', 1, level) -1 ) ) as token
                               from (select ','||:txt||',' txt from dual) 
                                       connect by level <= length(:txt)-length(replace(:txt,',',''))+1)
               Select *
                 from table
                 where column in (select * from data)",{"txt":"A,B"})

现在我遇到一个问题,如果列表大于1000,则字符串参数越过4000字节标记,无法再处理它。

我如何使其工作?

[我只有“选择”权限,不能创建临时表]

1 个答案:

答案 0 :(得分:1)

将大量id作为参数传递的整个想法是错误的方法。如果您出于“教育”目的而这样做,那么可以-做到这一点。对于生产环境,这是一个盲区。从我的经验可以看出,这可能会导致严重的问题。您仅需要解析查询就需要巨大的内存。我见过Django应用程序,开发人员在该数据库中向Oracle DB查询一些ID,然后根据这些ID发送另一个查询以查询其他数据,这些ID作为列表传递-就像您的查询一样:

import React, { Component } from 'react';
import './App.css';
import { random } from 'lodash';
import Button from './components/Button';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      quotes: [],
      randomQuoteIndex: null,
      isDoneFetching: false
    }
  }

  componentDidMount() {
    fetch('https://gist.githubusercontent.com/nataliecardot/0ca0878d2f0c4210e2ed87a5f6947ec7/raw/1802a693d02ea086817e46a42413c0df4c077e3b/quotes.json')
      // Takes a JSON response string and parses it into JS object
      .then(response => response.json())
      // state is set to quotes: quotes due to destructuring
      // Using setState callback since setState is asynchronous and need to make sure quotes is loaded before setting the randomQuoteIndex state since it depends on it
      .then(quotes => this.setState({ quotes }, () => {
        this.setState({
          randomQuoteIndex: this.randomQuoteIndex(),
          isDoneFetching: true
        })
      }))
  }

  get randomQuote() {
    return this.state.quotes[this.state.randomQuoteIndex];
  }

  randomQuoteIndex() {
    return random(0, this.state.quotes.length - 1);
  }

  render() {
    return (
      <div className="App" id="quote-box">
        {this.state.isDoneFetching ? this.randomQuote.quote : 'Loading...'}
        <Button
          buttonDisplayName="Next"
          clickHandler={this.blah}
        />
      </div>
    );
  }
}

export default App;

问题在于,在某些情况下,该列表确实很大(大约400KB的数据,我已经看到在查询中放置了约57000个id的跟踪)。整个查询的大小为433KB!太疯狂了!最荒谬的事实是,与执行查询(几秒钟)相比,解析花费了更长的时间(约15分钟!)。

我认为通过巨大的查询(大小)是一个可怕的主意,您应该重新设计代码。

您可以做什么:

  1. 创建一个临时表或仅一个表(对于后者,您必须处理多个会话)并在其中放置查询所需要的ID(询问授权或如果您不能自己做则创建表);
  2. 将您的任务分成几部分(也许您可以要求一部分id,然后再要求另一部分,最后在应用程序级别加入结果?);
  3. 也许您的“ id”是另一个查询的结果-然后将该查询放在where子句中。

很难说对最终目标一无所知。

如果您仅出于教育目的而这样做,则(对于当前查询)请尝试使用CLOB类型(或在cx_oracle中为表示CLOB的对象)作为包含ID的字符串的存储。

编辑(2019-07-09)

示例(只是基于cx_oracle中示例的简单草稿):

select a,b,c
  from table
  where table.d in (<here was the list of all ids>)
;