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