How to fetch generated sequence ID using JdbcTemplate on SQL Server 2012+ - sql-server

I have a table in SQL Server 2012 that uses a Sequence to generate the primary key using a default constraint.
CREATE TABLE [vfm].[ChangeEvent](
[ChangeEventId] [int] NOT NULL,
[Description] [varchar](100) NOT NULL,
[LegalEffectiveDate] [date] NOT NULL,
[StatusCode] [char](1) NOT NULL,
CONSTRAINT [PK_ChangeEvent] PRIMARY KEY CLUSTERED
(
[ChangeEventId] ASC
)
ALTER TABLE [vfm].[ChangeEvent] ADD CONSTRAINT [DF_ChangeEvent_1] DEFAULT
(NEXT VALUE FOR [vfm].[SEQ_ChangeEventId]) FOR [ChangeEventId]
I'm using NamedParameterJdbcTemplate in Spring 5.x to insert a new record into the table.
StringBuilder sql = new StringBuilder()
.append("insert into vfm.ChangeEvent(Description, LegalEffectiveDate, StatusCode)")
.append(" values (:description, :legalEffectiveDate, :status)");
SqlParameterSource parameters = new MapSqlParameterSource()
.addValue("description", changeEvent.getDescription())
.addValue("legalEffectiveDate", changeEvent.getLegalEffectiveDate())
.addValue("status", "S");
KeyHolder keyHolder = new GeneratedKeyHolder();
namedParameterJdbcTemplate.update(sql.toString(), parameters, keyHolder, new String[] { "ChangeEventId" });
From what I've seen so far, my KeyHolder comes back empty, GENERATED_KEYS = null. Is it possible to configure the .update call to retrieve the generated ChangeEventId? Or am I stuck because the table is using a sequence object?
I believe this is possible with Oracle, but I haven't seen any answers for SQL Server. The SQL Server questions I've seen have used identity columns, not sequences.

Here's what ended up working for me.
Use output insert.<id> in the SQL query to return the inserted value
Use queryForObject instead of update on NamedParameterJdbcTemplate
Make sure the sequence is set up as the column default
StringBuilder sql = new StringBuilder()
.append("insert into vfm.ChangeEvent(Description, LegalEffectiveDate, StatusCode)")
.append(" output inserted.ChangeEventId")
.append(" values (:description, :legalEffectiveDate, :status)");
SqlParameterSource parameters = new MapSqlParameterSource()
.addValue("description", changeEvent.getDescription())
.addValue("legalEffectiveDate", changeEvent.getLegalEffectiveDate())
.addValue("status", "S");
Integer changeEventId = namedParameterJdbcTemplate.queryForObject(sql.toString(), parameters, Integer.class);

Related

INSERT and SELECT in a single query. ADODB throws "Operation is not allowed when the object is closed"

I have 2 queries, both work fine in SQL Studio:
Query 1:
SELECT [id],[fullname] FROM persons WHERE [id] IN (5802824683954111059,1615647673927737)
Query 2:
IF OBJECT_ID('tempdb..#temp_table_1') IS NOT NULL
TRUNCATE TABLE #temp_table_1
ELSE
CREATE TABLE #temp_table_1 ( [key] bigint primary key );
INSERT INTO #temp_table_1 ([key]) VALUES (5802824683954111059),(1615647673927737);
SELECT [id],[fullname] FROM persons WHERE [id] IN (SELECT [key] FROM #temp_table_1)
But when I execute these queries using ADODB.Recordset.Open() method, only the first query returns valid result.
For the second query Recordset.EOF property throws "Operation is not allowed when the object is closed" error.
What is wrong with the second query? Does ADODB support multiple statements in a query?
The sample code demonstrating the problem:
conn = new ActiveXObject( 'ADODB.Connection' );
conn.Open( 'Provider=SQLOLEDB;Integrated Security=SSPI;Server=mt;Database=test;Integrated Security=SSPI' );
rs = new ActiveXObject( 'ADODB.Recordset' );
//sqlQuery = "SELECT [id],[fullname] FROM persons WHERE [id] IN (5802824683954111059,1615647673927737)";
sqlQuery = "IF OBJECT_ID('tempdb..#temp_table_1') IS NOT NULL\r\n\
TRUNCATE TABLE #temp_table_1\r\n\
ELSE\r\n\
CREATE TABLE #temp_table_1 ( [key] bigint primary key );\r\n\
INSERT INTO #temp_table_1 ([key]) VALUES (5802824683954111059),(1615647673927737);\r\n\
SELECT [id],[fullname] FROM persons WHERE [id] IN (SELECT [key] FROM #temp_table_1)";
rs.Open( sqlQuery, conn );
while ( ! rs.EOF )
{
alert( rs.Fields( 'fullname' ) );
rs.MoveNext();
}
Try either adding SET NOCOUNT ON to your T-SQL batch or invoke the Recordset.NextResult method after processing the results of the SELECT query.
SET NOCOUNT ON instructs SQL Server suppress DONE_IN_PROC TDS protocol messages (row counts), which classic ADO has the nasty habit of returning as closed empty recordsets with no columns. Failure to consume these with NextResult will prevent the entire T-SQL batch from running to completion.
It's a good practice to invoke NextResult until the method returns False as that will ensure the entire batch runs to completion regardless of the SET NOCOUNT session setting. Note that this technique also applies to other client APIs (ADO.NET, JDBC, etc), although the exact method to consume results differ as well as the symptoms (partial result sets, undetected exceptions).

SQL Server 2016 SSIS get cursor from stored procedure

I am using SQL Server 2016.
I have a stored procedure GET_RECORDS that takes input parameters for filter and outputs a CURSOR parameter
I want to get this cursor in my SSIS package
I had created data flow task, OleDb source and variables for parameter values. Then mapped parameters
Params mapping screen
but when I wanted to save the component - I got an error
error screen
I tried to add clause WITH RESULT SETS with some dummy columns, but my procedure doesn't return any result set
What am I doing wrong?
Any advices will be helpful.
Thank you.
With regards, Yuriy.
The source component is trying to determine what columns and types will be returned. Because you are using dynamic SQL the metadata can change each time you run it.
With result sets allows you to define the data being returned but should only be used if you are guaranteed to have those results every time you execute.
EDIT:
I create a connection and run the command so that it populates a data table. Then I put the column headers into a string array. There are plenty of examples out there.
Then I use the following function to create a destination table. Finally I create a datareader and pass that to the .Net SqlBulkCopy. Hope this helps.
private void CreateTable(string TableName, string[] Fields)
{
if (TableExists(TableName) && Overwrite)
{
SqlCommand = new SqlCommand($"Drop Table [{TableName}]", SqlConnection);
SqlCommand.ExecuteNonQuery();
}
string Sql = $"Create Table [{TableName}] (";
int ColumnNumber = 1;
foreach (string Field in Fields)
{
string FieldValue = Field;
if (! HasHeaders)
{
FieldValue = "Column" + ColumnNumber;
ColumnNumber++;
}
Sql += $"[{FieldValue}] Varchar(8000),";
}
Sql = Sql + "ImportFileID Int, ID Int Identity(1,1) Not Null, Constraint [PK_" + TableName + "] Primary Key Clustered ([ID] Asc))";
SqlCommand = new SqlCommand(Sql, SqlConnection);
SqlCommand.ExecuteNonQuery();
}
Use ado.net source instead of oledb source, define a simple select and get the columns you wish to return. Now you can define expresión in the dataflow properties.
Search ado.net source dynamic sql
:)
try to return the records and use foreach in ETL instead of cursor
https://www.simple-talk.com/sql/ssis/implementing-foreach-looping-logic-in-ssis/
I think you can do it from a simple way, but I don't know what you are you doing, exactly...

Check for duplicate records in sql database using vb.net

Assuming my table consist of two columns ID and Name.
And assume I have my stored procedure working on vb.net that inserts rows into the database.
But my system needs to check if an ID entered in a textbox already exists in the database when ADD button is click.
CREATE PROCEDURE AddOfficeEquipmentProfile
(
#OE_ID varchar(11),
#OE_Category char(3) =NULL,
#OE_SubCategory char(3)= NULL,
#OE_Name varchar(35)=NULL,
#OE_User varchar(35)=NULL,
#OE_Brand varchar(15)=NULL,
#OE_Model varchar(35)=NULL,
#OE_Specs varchar(1000)=NULL,
#OE_SerialNo varchar(35)=NULL,
#OE_PropertyNo varchar(35)=NULL,
#OE_MacAddress varchar(100)=NULL,
#OE_Static_IP varchar(15)=NULL,
#OE_Vendor varchar(35)=NULL,
#OE_PurchaseDate smalldatetime,
#OE_WarrantyInclusiveYear int=NULL,
#OE_WarrantyStatus char(2)= NULL,
#OE_Status varchar(15)=NULL,
#OE_Dept_Code char(3)= NULL,
#OE_Location_Code char(8)= NULL,
#OE_Remarks varchar(1000)= NULL
)
AS
INSERT INTO tblOfficeEquipmentProfile (OE_ID, OE_Category, OE_SubCategory, OE_Name, OE_User, OE_Brand, OE_Model, OE_Specs, OE_SerialNo,
OE_PropertyNo, OE_MacAddress, OE_Static_IP, OE_Vendor, OE_PurchaseDate, OE_WarrantyInclusiveYear, OE_WarrantyStatus, OE_Status, OE_Dept_Code,
OE_Location_Code, OE_Remarks )
VALUES (#OE_ID, #OE_Category, #OE_SubCategory, #OE_Name, #OE_User, #OE_Brand, #OE_Model,
#OE_Specs, #OE_SerialNo, #OE_PropertyNo, #OE_MacAddress, #OE_Static_IP, #OE_Vendor, #OE_PurchaseDate, #OE_WarrantyInclusiveYear, #OE_WarrantyStatus,
#OE_Status, #OE_Dept_Code, #OE_Location_Code, #OE_Remarks)
GO
few things you can do
make ID column as primary key, when insert you will get exception if duplicated
You can use auto increment ID, then you don't need to check ID exit or not. database will handle that
If you can't do above, run select statement or stored procedure to check whether id exist or not.
If this is for SQL Server and you're using a stored procedure - just try something like this:
CREATE PROCEDURE AddOfficeEquipmentProfile
(
#OE_ID varchar(11),
..... all your other parameters here.....
)
AS
IF NOT EXISTS (SELECT * FROM dbo.tblOfficeEquipmentProfile WHERE OE_ID = #OE_ID)
INSERT INTO dbo.tblOfficeEquipmentProfile(.... list of columns.....)
VALUES (......list of values................)
Assuming that OE_ID is your primary key and will be unique. Just check if that #OE_ID doesn't exist yet, and if it doesn't - insert the data. If it exists - don't do anything.
Building on the answer from #marc_s. In order to show a message to the user in case there already is a row in the database with the same id, you can check the number of affected rows from the query execution result.
This assumes that the stored procedure only inserts the row if the id is not present and does not emit any errors/exceptions.
Using ADO.NET (with an existing command executing the stored procedure):
Dim affectedRows as Integer = command.ExecuteNonQuery()
If affectedRows = 0 Then
'Handle the error here
MessageBox.Show("There is already a Profile with the supplied id")
Else
'Insert was made
End If
Check the following article to create a SP finding duplicate rows in any table:
http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server

How do I query SQLite Database in Android?

I successfully created the Database and inserted a row however I cannot Query it for some reason. My Droid crashes everytime.
// Create a new row of values to insert.
ContentValues newValues = new ContentValues();
// Assign values for each row.
newValues.put("value", "kunjan");
// Insert the row into your table
myDatabase.insert(DATABASE_TABLE, null, newValues);
String[] result_columns = new String[] { "value" };
// I GET AN EXCEPTION HERE
Cursor allRows = myDatabase.query(true, DATABASE_TABLE, result_columns, null, null,
null, null, null, null);
if (allRows.moveToFirst()) {
String value = allRows.getString(0);
TextView foo = (TextView) findViewById(R.id.TextView01);
foo.setText(value);
}
allRows.close();
myDatabase.close();
I get this exception
no such column: value: , while compiling: SELECT DISTINCT value FROM mainTable
I think you are creating table with only one column(value) and you are trying to read the column-1 instead of column-0 from the cursor. If that still not helps, please add try-catch block and capture the logs
String value = allRows.getString(0);
Some of the problems with the original post
Creating a table that has already been created. I wrote "if not exists" in the "create table" instruction.
Not handling Exceptions properly. I got a lot of exceptions in the creation of the table, quering it etc. I sorrounded all these operations with try-catch
Using hard coded values for Column names - This made it harder to verify if I was querying the column that I had created.

NHibernate bug sql generator

i have class named Group
i tried to test configuration:
var cfg = new Configuration();
cfg.Configure();
cfg.AddAssembly(typeof (Group).Assembly);
new SchemaExport(cfg).Execute(true, true, false);
when i debug this, im getting following sql:
create table Group (
ID INT IDENTITY NOT NULL,
Name NVARCHAR(255) null,
CreatedDate DATETIME null,
primary key (ID)
)
so like i remember, Group key reserved for Group By
so why NHibernate does not uses quotes like Group for table names?
BTW, I'm using Sql Server 2005 and NHibernate 2.1
If you are using a reserved keyword as your object name you should mark it with a DBMS specific sign. For example if you are using SQL Server you should put it in [] and use ` for MySql.
In this example you should write (assuming that you are using SQL server) :
<class name="Group" table="[Group]">

Resources