简体   繁体   English

SQL JDBC JAVA:如果不存在(SELECT…)INSERT INTO(…)后的getGeneratedKeys()

[英]SQL JDBC JAVA: getGeneratedKeys() after IF NOT EXISTS ( SELECT …) INSERT INTO (…)

I am now searching for a while not finding a solution for my problem. 我正在寻找一段时间,但没有找到解决我问题的方法。 I would like to insert a new row into a table if it currently not exists. 如果当前不存在新行,我想在表中插入新行。 I need the auto-incremented key of that new entry or the existing key of the existing entry. 我需要新条目的自动递增键或现有条目的现有键。

Also I'm not clear about the idea of the return-value of my INSERT, what if one column is inserted, value = 1, and what if the row exists? 另外,我不清楚INSERT的返回值的概念,如果插入一列,值= 1,该行存在怎么办? value = 0 or NULL or ?! 值= 0或NULL或?!

If possible I do NOT want to "BATCH-INSERT", I must use these two return-values for the next INSERT as foreign keys... or has anyone an idea how to do this all with batch inserts? 如果可能的话,我不想“ BATCH-INSERT”,那么必须将下一个INSERT的这两个返回值用作外键...还是有人知道如何对批处理插入执行全部操作?

Thanks to everybody who can help!! 感谢所有可以提供帮助的人!

System: MS SQL 2012 standard database, JAVA SE 1.6, sqljdbc4 系统:MS SQL 2012标准数据库,JAVA SE 1.6,sqljdbc4

This is my code, that gives me a SQLException: 这是我的代码,给我一个SQLException:

    public long executeUpdateActionStatement(String sqlStatement, int autoGeneratedKeys) {

    ResultSet rs = null;
    Statement stmt = null;
    int rowCount = 0;
    try {
        connect();
        stmt = connect.createStatement();

        rowCount = stmt.executeUpdate(sqlStatement, autoGeneratedKeys);


        // if no new row is inserted, later I do a select to get the key
        if (rowCount < 1) 
            return -1;

        stmt.getGeneratedKeys();    /* This step throws the exception ! */
        if (rs.next()) {
            long id = rs.getLong(1);
            System.out.println(" !! ==---> ID: " + id + " | : " + sqlStatement);
            return id;
        }


    } catch (SQLFeatureNotSupportedException feature) {
        feature.printStackTrace();
        System.out.println("|| ---->>> Fehler: SQLFeatureNotSupportedException: " + sqlStatement);

    } catch (SQLServerException sqlse) {
        sqlse.printStackTrace();
        System.out.println("|| ---->>> Fehler: SQLServerException: " + sqlStatement);
    } catch (SQLException e) {
        e.printStackTrace();
        System.out.println("|| ---->>> Fehler: SQLException: " + sqlStatement);
    }

    finally {

        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }

    return -1;

}

The SQLException I get: 我得到的SQLException:

    com.microsoft.sqlserver.jdbc.SQLServerException: Die Anweisung muss ausgeführt werden, bevor Ergebnisse abgerufen werden können.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:190)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.getGeneratedKeys(SQLServerStatement.java:2040)

in english: 用英语:

    The statement must be executed before any results can be obtained.

The SQL Statements: SQL语句:

    executeUpdateActionStatement("IF NOT EXISTS (SELECT GeoLocationId FROM GeoLocationCoordinates WHERE Longitude = " + longitude + 
    " AND Latitude = " + latitude + ") INSERT INTO GeoLocationCoordinates VALUES (" + longitude + ", " + latitude + ")", Statement.RETURN_GENERATED_KEYS); //Statement.RETURN_GENERATED_KEYS);

AND

    executeUpdateActionStatement("IF NOT EXISTS (SELECT PlaceId FROM Places WHERE TwitterPlaceId = \'" + p.getId() + "\') INSERT INTO Places VALUES (" + 
            placeData + ")", Statement.RETURN_GENERATED_KEYS);

The database-tables: 数据库表:

    /****** Object:  Table [dbo].[GeoLocationCoordinates]    Script Date: 16.08.2013 17:55:04 **************************************************************************/
    SET ANSI_NULLS ON
    GO

    SET QUOTED_IDENTIFIER ON
    GO

    CREATE TABLE [dbo].[GeoLocationCoordinates](
        [GeoLocationId] [bigint] IDENTITY(1,1) NOT NULL,
        [Longitude] [float] NOT NULL,
        [Latitude] [float] NOT NULL, CONSTRAINT [PK_GeoLocationCoordinates] PRIMARY KEY CLUSTERED (  [GeoLocationId] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    GO

and

    /****** Object:  Table [dbo].[Places]    Script Date: 16.08.2013 17:57:16 **************************************************************************/
    SET ANSI_NULLS ON
    GO

    SET QUOTED_IDENTIFIER ON
    GO

    CREATE TABLE [dbo].[Places](
      [PlaceId] [bigint] IDENTITY(1,1) NOT NULL,
      [TwitterPlaceId] [nvarchar](255) NULL,
      [PlaceName] [nvarchar](255) NULL,
      [PlaceFullName] [nvarchar](255) NULL,
      [StreetAdress] [nvarchar](255) NULL,
      [Country] [nvarchar](255) NULL,
      [PlaceType] [nvarchar](255) NULL,
      [PlaceUrl] [nvarchar](255) NULL,
      [BoundingBoxType] [nvarchar](255) NULL,
      [CountryTwoLetterCode] [nchar](2) NULL,
     CONSTRAINT [PK_Places] PRIMARY KEY CLUSTERED 
    (
  [PlaceId] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    GO

This is not syntactically correct, but gives an idea, just use scope identity in a transaction to get the new key and use it on child tables..The scrope in the transaction gives you hback the number you want. 这在语法上不是正确的,但是给出了一个主意,只是在事务中使用作用域标识来获取新键并在子表上使用它。事务中的暂存为您提供了所需的数字。 You'd just need to store the number of the found value in other code, if it exists. 您只需将找到的值的编号存储在其他代码中(如果存在)。 Could probably do it in the same proc, ideally. 理想情况下,可以在同一过程中完成此操作。

declare @returnvalue int


BEGIN TRANSACTION
INSERT INTO GeoLocationCoordinates(longitude,latitude)
values (@lat,@long)

SELECT @returnvalue = SCOPE_IDENTITY()

INSERT INTO childtable (field1,field2,parentkey)
VALUES (@field1,@field2,@returnvalue)
COMMIT TRANSACTION

executeUpdate returns either 0, if no rows were affected, or the number of rows that were affected. 如果没有受影响的行,executeUpdate返回0,或者返回受影响的行数。

What step in your code is throwing the exception? 您的代码中哪一步引发了异常?

EDIT 2: Okay, looks like the merge will work. 编辑2:好的,看起来合并将工作。

PreparedStatement stmt = connection.prepareStatement(
        "merge table_1 t1 " +
        "using (select 'testvalue' as col1) t2 " +
        " on t1.col1 = t2.col1 " +
        " when not matched by target then " + 
        " insert (col1) values('testvalue'); "  
        ,Statement.RETURN_GENERATED_KEYS);

int out = stmt.executeUpdate();
System.out.println("Return:  " + out);  
ResultSet rs = stmt.getGeneratedKeys();
if (rs.next()) {
    System.out.println("value:  " + rs.getLong(1));
}

If the value 'testvalue' doesn't exist in the destination table, it will be inserted. 如果目标表中不存在值“ testvalue”,则将其插入。 If it's inserted, the return value will be 1, and getGeneratedKeys will return the new row's identity column value. 如果已插入,则返回值为1,而getGeneratedKeys将返回新行的标识列值。 If it does exist, both methods will return 0. 如果确实存在,则两个方法都将返回0。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM