我试图找到返回结果集的最简单方法,该结果集指示表中是否存在某些值.考虑一下这个表:
id ------ 1 2 3 7 23
我将收到一个ID列表,我需要回复相同的列表,指出表中存在哪些.如果我得到的列表如下:'1','2','3','4','8','23',我需要生成一个如下所示的结果集:
id | status ------------- 1 | present 2 | present 3 | present 4 | missing 8 | missing 23 | present
到目前为止,我已经设法使用以下方法UNPIVOT:
select id, 'present' as status
from my_table
where id in ('1','2','3')
union
select subq.v as id, 'missing' as status
from (
select v
from
(
(
select '1' v1, '2' v2, '3' v3 from dual
)
unpivot
(
v
for x in (v1,v2,v3)
)
)
) subq
where subq.v not in
(
select id
from my_table
where id in ('1','2','3')
);
Run Code Online (Sandbox Code Playgroud)
它看起来有点奇怪,但确实有效.这个问题的select '1' v1, '2' v2, '3' v3 from dual部分是:我不知道如何使用JDBC预处理语句填充它.ID列表不是固定的,因此对使用此查询的函数的每次调用都可以传递不同的ID列表.
有没有其他方法来完成这项工作?我想我错过了一些明显的东西,但我不确定......
(使用Oracle 11)
从SQL端,您可以定义表类型并使用它来连接到您的真实数据,例如:
create type my_array_type as table of number
/
create or replace function f42 (in_array my_array_type)
return sys_refcursor as
rc sys_refcursor;
begin
open rc for
select a.column_value as id,
case when t.id is null then 'missing'
else 'present' end as status
from table(in_array) a
left join t42 t on t.id = a.column_value
order by id;
return rc;
end f42;
/
Run Code Online (Sandbox Code Playgroud)
带有包装函数的SQL Fiddle演示,因此您可以直接查询它,它给出:
ID STATUS
---------- --------------------
1 present
2 present
3 present
4 missing
8 missing
23 present
Run Code Online (Sandbox Code Playgroud)
从Java中,您可以ARRAY根据表类型定义,从Java数组填充,并直接调用该函数; 你的单个参数绑定变量是ARRAY,你得到一个你可以正常迭代的结果集.
作为Java方面的概述:
int[] ids = { 1, 2, 3, 4, 8, 23 };
ArrayDescriptor aDesc = ArrayDescriptor.createDescriptor("MY_ARRAY_TYPE",
conn);
oracle.sql.ARRAY ora_ids = new oracle.sql.ARRAY(aDesc, conn, ids);
cStmt = (OracleCallableStatement) conn.prepareCall("{ call ? := f42(?) }");
cStmt.registerOutParameter(1, OracleTypes.CURSOR);
cStmt.setArray(2, ora_ids);
cStmt.execute();
rSet = (OracleResultSet) cStmt.getCursor(1);
while (rSet.next())
{
System.out.println("id " + rSet.getInt(1) + ": " + rSet.getString(2));
}
Run Code Online (Sandbox Code Playgroud)
这使:
id 1: present
id 2: present
id 3: present
id 4: missing
id 8: missing
id 23: present
Run Code Online (Sandbox Code Playgroud)
正如Maheswaran Ravisankar所提到的,这允许通过任意数量的元素; 你不需要知道在编译时有多少元素(或处理理论上的最大值),你不受限于一个IN或多个分隔字符串长度允许的最大表达式数,并且你不必撰写和分解字符串来传递多个值.
正如ThinkJet指出的那样,如果您不想创建自己的表类型,可以使用预定义的集合,在此处演示 ; 除了参数声明之外,main函数是相同的:
create or replace function f42 (in_array sys.odcinumberlist)
return sys_refcursor as
...
Run Code Online (Sandbox Code Playgroud)
包装器函数以稍微不同的方式填充数组,但在Java端,您只需要更改此行:
ArrayDescriptor aDesc =
ArrayDescriptor.createDescriptor("SYS.ODCINUMBERLIST", conn );
Run Code Online (Sandbox Code Playgroud)
使用它也意味着(正如ThinkJet也指出的那样!)您可以在不定义函数的情况下运行原始独立查询:
select a.column_value as id,
case when t.id is null then 'missing'
else 'present' end as status
from table(sys.odcinumberlist(1, 2, 3, 4, 8, 23)) a
left join t42 t on t.id = a.column_value
order by id;
Run Code Online (Sandbox Code Playgroud)
(SQL小提琴).
这意味着您可以直接从Java调用查询:
int[] ids = { 1, 2, 3, 4, 8, 23 };
ArrayDescriptor aDesc = ArrayDescriptor.createDescriptor("SYS.ODCINUMBERLIST", conn );
oracle.sql.ARRAY ora_ids = new oracle.sql.ARRAY(aDesc, conn, ids);
sql = "select a.column_value as id, "
+ "case when t.id is null then 'missing' "
+ "else 'present' end as status "
+ "from table(?) a "
+ "left join t42 t on t.id = a.column_value "
+ "order by id";
pStmt = (OraclePreparedStatement) conn.prepareStatement(sql);
pStmt.setArray(1, ora_ids);
rSet = (OracleResultSet) pStmt.executeQuery();
while (rSet.next())
{
System.out.println("id " + rSet.getInt(1) + ": " + rSet.getString(2));
}
Run Code Online (Sandbox Code Playgroud)
...你可能更喜欢.
还有一个预定义的ODCIVARCHAR2LIST类型,如果你实际上正在传递字符串 - 你的原始代码似乎正在使用字符串,即使它们包含数字,所以不确定你真正需要的是什么.
因为这些类型被定义为VARRAY(32767)限制为32k值,所以定义自己的表会删除该限制; 但显然,只有你传递了很多价值观才有意义.
| 归档时间: |
|
| 查看次数: |
531 次 |
| 最近记录: |