Search code examples
javasql-servert-sqljdbcmssql-jdbc

How to invoke TSQL statement with params?


How can I use params in tsql or alternatively re-use the values in a merge statement without having to pass the values multiple times? What am I doing wrong?

Running TSQL with params throws exception below

The variable name '@p1' has already been declared. Variable names must be unique within a query batch or stored procedure."

Using table def as example:

dbo.Test
(
[key]      VarChar(50),
[value]    VarChar(50)
)

Sample Java code:

try (PreparedStatement s = conn.prepareStatement("DECLARE @p1 VarChar(50) DECLARE @p2 VarChar(50) SET @p1 = ? SET @p2 = ? INSERT dbo.Test ([key], [value]) values(@p1, @p2)"))
{
    s.setString(1,"Hello");
    s.setString(2,"World");
    s.execute();
}

Also tried below with same results

DECLARE @p1 VarChar(50) = ?
DECLARE @p2 VarChar(50) = ?

EDIT: The code above is just a sample, I need/want to use param so I don't have to set the same values multiple times for use in a Merge Statement

A merge statement for dbo.Test would look like this:

DECLARE @key    VarChar(50)
DECLARE @val    VarChar(50)

MERGE dbo.Test t
USING (SELECT @key [k]) s
    ON t.[key] = s.k
WHEN MATCHED THEN
    UPDATE
    SET t.[value] = @val
WHEN NOT MATCHED THEN
    INSERT ([key], [value])
    VALUES (@key, @val);

I'd rather not have to set the same value again and again


Solution

  • Don't use TSQL variables, just insert the values directly.

    String sql = "INSERT INTO dbo.Test ([key], [value]) VALUES (?, ?)";
    try (PreparedStatement stmt = conn.prepareStatement(sql)) {
        stmt.setString(1, "Hello");
        stmt.setString(2, "World");
        stmt.executeUpdate();
    }
    

    UPDATE for question edit using MERGE:

    The code above is just a sample, I need/want to use param so I don't have to set the same values multiple times for use in a Merge Statement

    If you follow the example shown in that link, you'll see that the variables are only used once each, so there is no reason to require variables at all when executed from Java.

    Example A from link:

    MERGE Production.UnitMeasure AS target  
    USING (SELECT @UnitMeasureCode, @Name) AS source (UnitMeasureCode, Name)  
    ON (target.UnitMeasureCode = source.UnitMeasureCode)  
    WHEN MATCHED THEN
        UPDATE SET Name = source.Name  
    WHEN NOT MATCHED THEN  
        INSERT (UnitMeasureCode, Name)  
        VALUES (source.UnitMeasureCode, source.Name)  
    OUTPUT deleted.*, $action, inserted.* INTO #MyTempTable;  
    

    As applied to the question's statement:

    String sql = "MERGE dbo.Test AS t" +
                " USING (SELECT ?, ?) AS s (k, v)" +
                   " ON t.[key] = s.k" +
                 " WHEN MATCHED THEN" +
                     " UPDATE SET [value] = s.v" +
                 " WHEN NOT MATCHED THEN" +
                     " INSERT ([key], [value])" +
                     " VALUES (s.k, s.v)";
    try (PreparedStatement stmt = conn.prepareStatement(sql)) {
        stmt.setString(1, "Hello"); // s.k
        stmt.setString(2, "World"); // s.v
        stmt.executeUpdate();
    }