SQL 结果在 Servlet 中显示不同
SQL result not shown as the same in Servlet
全部。
我得到 SQL 查询,该查询对 query.xml 文件中的给定数据进行排序。
当我在 SQLD(Oracle) 上进行测试时,它会按预期返回排序后的数据。
<entry key="ascUserList">
SELECT
CLASS
, ID
, NAME
, USER_NICK
, EMAIL
, PHONE
, AREA_NAME
, USER_GRADE
, USER_POINT
, GRADE_START
, GRADE_END
FROM
COM_INFO
JOIN
USER_INFO ON (ID = USER_ID)
JOIN
AREA USING(USER_AREA)
WHERE
CLASS LIKE '%' || '일반' || '%'
AND USER_SIGNUP LIKE '%' || 'Y' || '%'
ORDER BY ? ASC
</entry>
然后这个Servlet从上面的代码中取出排序后的数据。
我希望将排序后的数据添加到 ArrayList 中,但是,我得到的结果是未排序的数据。
public ArrayList<UserInfo> ascUserList(Connection conn, String sort) {
ArrayList<UserInfo> list = new ArrayList<>();
PreparedStatement pstmt = null;
ResultSet rset = null;
String sql = prop.getProperty("ascUserList");
System.out.println(sort.equals("이름"));
try {
pstmt = conn.prepareStatement(sql);
switch(sort) {
case "정렬기준": pstmt.setString(1, "ID"); break;
case "아이디": pstmt.setString(1, "ID"); break;
case "이름": pstmt.setString(1, "NAME"); break;
case "닉네임": pstmt.setString(1, "USER_NICK"); break;
case "지역": pstmt.setString(1, "AREA_NAME"); break;
case "등급": pstmt.setString(1, "USER_GRADE"); break;
}
rset = pstmt.executeQuery();
while(rset.next()) {
list.add(new UserInfo(rset.getString(2),
rset.getString(1),
rset.getString(5),
rset.getString(3),
rset.getString(6),
rset.getString(4),
rset.getString(7),
rset.getString(8),
rset.getDate(10),
rset.getDate(11),
Integer.parseInt(rset.getString(9))));
System.out.println(list);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rset);
close(pstmt);
}
return list;
}
非常感谢您的建议!
这是因为?
指定了一个占位符值,所以你总是按常量排序。
Oracle 区分常量 int(通过 ?
传递)和列的整数位置,当您执行 select * from ... order by 1
时放置。对于后者,1 是语法的一部分,就像标识符一样。您可以使用以下代码进行检查。
如您所见,第一个查询将 1 视为列位置并按第一列排序,而第二个查询实际上按第二列排序。
with a as (
select 1 as s1, 10 as s2 from dual union all
select 3, 20 from dual union all
select 2, 30 from dual
)
select *
from a
order by 1, 2
S1 | S2
-: | -:
1 | 10
2 | 30
3 | 20
with a as (
select 1 as s1, 10 as s2 from dual union all
select 3, 20 from dual union all
select 2, 30 from dual
)
select *
from a
order by cast('1' as number), 2
S1 | S2
-: | -:
1 | 10
3 | 20
2 | 30
db<>fiddle here
UPD:
如果您有预定义的列数但不是很多,您可以使用 CASE
(或 Oracle 中的 DECODE
)来选择要排序的列,但您需要注意数据类型:相同的数据类型应该在相同的 CASE
语句中。而且很难维护这样的代码。例如:
with a as (
select
'A' as COL1_VARCHAR,
'B' as COL2_VARCHAR,
sysdate as COL3_DATE,
sysdate as COL4_DATE,
1 as COL5_NUMBER,
2 as COL6_NUMBER,
3 as COL7_NUMBER
from dual
)
select *
from a
order by
/*varchar*/
decode(?,
1, COL1_VARCHAR,
2, COL2_VARCHAR
) asc,
/*date*/
decode(?,
3, COL3_DATE,
4, COL4_DATE
) asc,
/*number*/
decode(?,
5, COL5_NUMBER,
6, COL6_NUMBER,
7, COL7_NUMBER
) asc
或更灵活的方式 - 在应用程序端编写动态 SQL 查询并将其传递给数据库。但要注意 SQL 注入,将元数据与应用程序代码一起排序,而不是来自某些用户输入(如输入字段)。或者根据 DBMS 字典检查输入,例如:
select count(1)
from all_tab_cols
where table_name = 'YOUR_TABLE_NAME_IN_FROM'
and column_name = ? --user input with column name
全部。
我得到 SQL 查询,该查询对 query.xml 文件中的给定数据进行排序。
当我在 SQLD(Oracle) 上进行测试时,它会按预期返回排序后的数据。
<entry key="ascUserList">
SELECT
CLASS
, ID
, NAME
, USER_NICK
, EMAIL
, PHONE
, AREA_NAME
, USER_GRADE
, USER_POINT
, GRADE_START
, GRADE_END
FROM
COM_INFO
JOIN
USER_INFO ON (ID = USER_ID)
JOIN
AREA USING(USER_AREA)
WHERE
CLASS LIKE '%' || '일반' || '%'
AND USER_SIGNUP LIKE '%' || 'Y' || '%'
ORDER BY ? ASC
</entry>
然后这个Servlet从上面的代码中取出排序后的数据。
我希望将排序后的数据添加到 ArrayList 中,但是,我得到的结果是未排序的数据。
public ArrayList<UserInfo> ascUserList(Connection conn, String sort) {
ArrayList<UserInfo> list = new ArrayList<>();
PreparedStatement pstmt = null;
ResultSet rset = null;
String sql = prop.getProperty("ascUserList");
System.out.println(sort.equals("이름"));
try {
pstmt = conn.prepareStatement(sql);
switch(sort) {
case "정렬기준": pstmt.setString(1, "ID"); break;
case "아이디": pstmt.setString(1, "ID"); break;
case "이름": pstmt.setString(1, "NAME"); break;
case "닉네임": pstmt.setString(1, "USER_NICK"); break;
case "지역": pstmt.setString(1, "AREA_NAME"); break;
case "등급": pstmt.setString(1, "USER_GRADE"); break;
}
rset = pstmt.executeQuery();
while(rset.next()) {
list.add(new UserInfo(rset.getString(2),
rset.getString(1),
rset.getString(5),
rset.getString(3),
rset.getString(6),
rset.getString(4),
rset.getString(7),
rset.getString(8),
rset.getDate(10),
rset.getDate(11),
Integer.parseInt(rset.getString(9))));
System.out.println(list);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rset);
close(pstmt);
}
return list;
}
非常感谢您的建议!
这是因为?
指定了一个占位符值,所以你总是按常量排序。
Oracle 区分常量 int(通过 ?
传递)和列的整数位置,当您执行 select * from ... order by 1
时放置。对于后者,1 是语法的一部分,就像标识符一样。您可以使用以下代码进行检查。
如您所见,第一个查询将 1 视为列位置并按第一列排序,而第二个查询实际上按第二列排序。
with a as ( select 1 as s1, 10 as s2 from dual union all select 3, 20 from dual union all select 2, 30 from dual ) select * from a order by 1, 2
S1 | S2 -: | -: 1 | 10 2 | 30 3 | 20
with a as ( select 1 as s1, 10 as s2 from dual union all select 3, 20 from dual union all select 2, 30 from dual ) select * from a order by cast('1' as number), 2
S1 | S2 -: | -: 1 | 10 3 | 20 2 | 30
db<>fiddle here
UPD:
如果您有预定义的列数但不是很多,您可以使用 CASE
(或 Oracle 中的 DECODE
)来选择要排序的列,但您需要注意数据类型:相同的数据类型应该在相同的 CASE
语句中。而且很难维护这样的代码。例如:
with a as (
select
'A' as COL1_VARCHAR,
'B' as COL2_VARCHAR,
sysdate as COL3_DATE,
sysdate as COL4_DATE,
1 as COL5_NUMBER,
2 as COL6_NUMBER,
3 as COL7_NUMBER
from dual
)
select *
from a
order by
/*varchar*/
decode(?,
1, COL1_VARCHAR,
2, COL2_VARCHAR
) asc,
/*date*/
decode(?,
3, COL3_DATE,
4, COL4_DATE
) asc,
/*number*/
decode(?,
5, COL5_NUMBER,
6, COL6_NUMBER,
7, COL7_NUMBER
) asc
或更灵活的方式 - 在应用程序端编写动态 SQL 查询并将其传递给数据库。但要注意 SQL 注入,将元数据与应用程序代码一起排序,而不是来自某些用户输入(如输入字段)。或者根据 DBMS 字典检查输入,例如:
select count(1)
from all_tab_cols
where table_name = 'YOUR_TABLE_NAME_IN_FROM'
and column_name = ? --user input with column name