【问题标题】:java.sql.SQLException: ORA-00917: missing commajava.sql.SQLException: ORA-00917: 缺少逗号
【发布时间】:2013-10-07 00:11:37
【问题描述】:

我正在努力寻找下面的 SqlExcpetion 的原因。我正在使用 Oracle Database 11g Express 和 SqlDeveloper。我浏览了其他帖子,但到目前为止没有任何帮助。

java.sql.SQLException: ORA-00917: missing comma

at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:447)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:951)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:513)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:227)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:195)
at oracle.jdbc.driver.T4CStatement.executeForRows(T4CStatement.java:1029)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1336)
at oracle.jdbc.driver.OracleStatement.executeQuery(OracleStatement.java:1498)
at oracle.jdbc.driver.OracleStatementWrapper.executeQuery(OracleStatementWrapper.java:406)
at com.ets.hr.dao.EmployeeDAO.createEmployee(EmployeeDAO.java:30)
at Test.main(Test.java:62)

方法如下:

public void createEmployee(Employee e){
    try{
        Class.forName(oracleClass);
        Connection conn = DriverManager.getConnection(oracleUrl, "hr", "hr");
        Statement s = conn.createStatement();
        String query = "INSERT INTO employees VALUES(" +
                       e.getEmployeeId() + ", '" +
                       e.getFirstName() + "', '" +
                       e.getLastName() + "', '" +
                       e.getEmail() + "', '" +
                       e.getPhoneNumber() + "', " +
                       e.getHireDate() + ", '" +
                       e.getJobId() + "', " +
                       e.getSalary() + ", " +
                       e.getCommissionPct() + ", " +
                       e.getManagerId() + ", " +
                       e.getDepartmentId() + ")";

        s.executeQuery(query);//LINE 30 - SqlException Here
        System.out.println("Query Executed: Create Employee");
    }
    catch(SQLException se){
        se.printStackTrace();
    }
    catch(ClassNotFoundException ce){
        ce.printStackTrace();
    }
}

员工类:

package com.ets.hr.dto;

import java.util.Date;

public class Employee {

//CONSTRUCTORS
public Employee(){}

public Employee(long eId, 
                String firstName, 
                String lastName, 
                String email, 
                String phoneNumber, 
                Date hireDate, 
                String jobId, 
                double salary, 
                double commissionPct,
                long managerId,
                long departmentId){
    this.firstName = firstName;
    this.lastName = lastName;
    this.email = email;
    this.phoneNumber = phoneNumber;
    this.hireDate = hireDate;
    this.jobId = jobId;
    this.salary = salary;
    this.commissionPct = commissionPct;
    this.managerId = managerId;
    this.departmentId = departmentId;
}

//instance variables (from HR.EMPLOYEE table)
private long employeeId;
private String firstName;
private String lastName;
private String email;
private String phoneNumber;
private Date hireDate;
private String jobId;
private double salary;
private double commissionPct;
private long managerId;
private long departmentId;

//GETTERS
public long getEmployeeId(){
    return this.employeeId;
}
public String getFirstName(){
    return this.firstName;
}
public String getLastName(){
    return this.lastName;
}
public String getEmail(){
    return this.email;
}
public String getPhoneNumber(){
    return this.phoneNumber;
}
public Date getHireDate(){
    return this.hireDate;
}
public String getJobId(){
    return this.jobId;
}
public double getSalary(){
    return this.salary;
}
public double getCommissionPct(){
    return this.commissionPct;
}
public long getManagerId(){
    return this.managerId;
}
public long getDepartmentId(){
    return this.departmentId;
}

//SETTERS
public void setEmployeeId(long employeeId){
    this.employeeId = employeeId;
}
public void setFirstName(String firstName){
    this.firstName = firstName;
}
public void setLastName(String lastName){
    this.lastName = lastName;
}
public void setEmail(String email){
    this.email = email;
}
public void setPhoneNumber(String phoneNumber){
    this.phoneNumber = phoneNumber;
}
public void setHireDate(Date hireDate){
    this.hireDate = hireDate;
}
public void setJobId(String jobId){
    this.jobId = jobId;
}
public void setSalary(double salary){
    this.salary = salary;
}
public void setCommissionPct(double commissionPct){
    this.commissionPct = commissionPct;
}
public void setManagerId(long managerId){
    this.managerId = managerId;
}
public void setDepartmentId(long departmentId){
    this.departmentId = departmentId;
}

public void printEmployee(){
    System.out.println("Employee ID: " + this.getEmployeeId());
    System.out.println("Employee Name: " + this.getFirstName() + this.getLastName());
    System.out.println("Employee Email: " + this.getEmail());
    System.out.println("Employee Phone: " + this.getPhoneNumber());
    System.out.println("Employee Hire Date: " + this.getHireDate());
    System.out.println("Employee Job ID: " + this.getJobId());
    System.out.println("Employee Salary: " + this.getSalary());
    System.out.println("Employee Commission Pct: " + this.getCommissionPct());
    System.out.println("Employee Manager ID: " + this.getManagerId());
    System.out.println("Employee Department ID: " + this.getDepartmentId());
}

}

【问题讨论】:

  • 在执行查询之前,您是否尝试过查看query 字符串的外观?
  • 连同查询字符串,发布 CREATE TABLE sql 会很有帮助。
  • 首先,你真的不应该在你的 SQL 语句中嵌入文字。这不好的原因有很多。这就是参数的用途。可以进行一次性测试,但不要在生产代码中这样做。您的某个字段中可能有一些与语法相关的字符。
  • Vache,你到底是什么意思?
  • Kevin,我没有 CREATE TABLE 代码 - 我正在使用 SqlDeveloper 附带的示例表。

标签: java sql jdbc oracle11g


【解决方案1】:

您不应该尝试构建自己的 SQL 字符串,因为您必须处理引用和转义(这让您很受困扰)。

改为使用PreparedStatement 并让 JDBC API 转义、引用和格式化(例如日期)您的值您:

String query = "INSERT INTO employees VALUES (?,?,?,?,?,?,?,?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(query);
ps.setInt(e.getEmployeeId(), 1);
ps.setString(e.getFirstName(), 2);
ps.setDate(e.getHireDate(), 6);
// etc - there is a setter for each basic datatype
ps.execute();
ps.close();

编码更容易,可读性也大大提高。

【讨论】:

    【解决方案2】:

    正如 OldProgrammer 提到的,而不是像这样嵌入值

    Statement s = conn.createStatement();
    String query = "INSERT INTO employees VALUES(" +
                       e.getEmployeeId() + ", '" +
                       e.getFirstName() + "', '" +
                       e.getLastName() + "', '" +
                       e.getEmail() + "', '" +
                       e.getPhoneNumber() + "', " +
                       e.getHireDate() + ", '" +
                       e.getJobId() + "', " +
                       e.getSalary() + ", " +
                       e.getCommissionPct() + ", " +
                       e.getManagerId() + ", " +
                       e.getDepartmentId() + ")";
    
    s.executeQuery(query);
    

    您可以使用PreparedStatement,然后在输入值时任何特殊的 SQL 语法都将被忽略/转义。尝试这样做

    String query = "INSERT INTO employees VALUES(?,?,?,?,?,?,?,?,?,?,?)";
    PreparedStatement ps = conn.prepareStatement(query);
    ps.setInt(1, e.getEmployeeId());
    ps.setString(2, e.getFirstName());
    //.... etc for the rest of your parameters
    

    【讨论】:

      【解决方案3】:

      看起来以下方法之一正在生成数据库期望被引用/转义的值(可能它本身包含逗号,或另一个数据库特殊字符):

      e.getEmployeeId()
      e.getHireDate()
      e.getSalary()
      e.getCommissionPct()
      e.getManagerId()
      e.getDepartmentId()
      

      我建议查看 PreparedStatement 类以帮助解决此类错误(以及防范基于 SQL 的安全漏洞)。

      【讨论】:

      • 我刚刚在Employee类中添加了代码(包括你引用的方法)。还有其他想法吗?
      • 是的 - 根据您发布的方法签名,hireDatejobId 可能会生成格式错误的String,无法在数据库中使用(尽管如果没有则很难判断)访问表定义;理论上它可能是另一种方法)。为了帮助您调试,我建议上面提到的 Vache - 在您致电 s.executeQuery() 之前致电 System.out.println(query),这样您就可以准确查看 d/b 中的内容。在您的错误之前打印出来的那行应该向您指出错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-21
      • 1970-01-01
      • 2016-01-30
      • 2019-09-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多