How to get last inserted id on ms sql server with FireDac component? - sql

with FireDac, How to get last inserted id on ms sql server?
thanks

Make the that id to a identity column and then get it by Using
SELECT SCOPE_IDENTITY()
after the insert statement
Please refer the following links
http://msdn.microsoft.com/en-us/library/ms190315.aspx

Use auto-incremented field type
http://www.da-soft.com/anydac/docu/Auto-Incremental_Fields.html
This would provide for code like
DataSet.Insert;
....
DataSet.Post;
id := DataSet.FieldByName('ID').AsInteger;
Another approach might be crafting proper SQL statements like described at
http://en.wikipedia.org/wiki/Insert_(SQL)#Retrieving_the_key
SQL Server - Return value after INSERT
Best way to get identity of inserted row?
AnyDAC author also suggests a special method to fetch DBMS-specific toolings via http://docs.embarcadero.com/products/rad_studio/firedac/uADCompClient_TADCustomConnection_GetLastAutoGenValue#String.html
But all those post-factum requests with SELECT ##identity or SELECT SCOPE_IDENTITY are fragile and dangerous. When you insert data into table A, its triggers may insert data into related tables B and C, and identity would recall C's autoinc, rather than table where you started inserting at.

Related

Is SQL injection or any other attack possible while copying data from table to another table

I have 2 tables, TableA and TableB. TableA contains unreliable data and user can enter what ever data they want into this table. I want to copy the data from TableA to TableB using:
Insert into tableB(col1,col2)
select col1,col2
from TableA
where find_in_set('someStaticText',replace(col3,';',',')
Is it possible for SQL injection or any other attack to happen while copying this data from TableA?
I have tried the standard SQL injection examples but it doesn't seem to be a problem and since my SQL query is static " insert into tableB select from tableA" I don't see any problem either.
But since we are dealing with completely unreliable data from TableA, is there anyway to be sure that there will not be any issue while copying the data.
SQL injection attack is when a user-submitted string (or rather, any input that is not created in your code, which you yourself guarantee to be safe) is injected into an executable SQL code before it is sent to the database.
The classic example is immortalised in XKCD; user input Robert'); DROP TABLE Students; -- is presumably injected into something like INSERT INTO Students VALUES ('$name'), creating the following series of statements:
INSERT INTO Students VALUES ('Robert');
DROP TABLE Students;
--');
Note that if the statement was written correctly, either as a prepared statement (INSERT INTO Students VALUES (?)) or if the string was first correctly escaped (which would transform Robert'); DROP TABLE Students; -- into Robert''); DROP TABLE Students; --), it would have been inserted correctly; once it is in the database, it is just data, with no special superpowers.
Crucially, the dangerous bit is where the SQL statement text is created, in your application code, not in the database. Since your SQL statement is a static string, nothing can be injected, and there can be no SQL injection attack.

SELECT the last ID after INSERT in Oracle

I'm aware of using RETURNING in an INSERT statement but need a way to either have it returned as a result of the INSERT statement (or enclosing transaction) or be able to retrieve that value using SELECT. Is there a way to do this? I cannot use DBMS_OUTPUT. Thanks!
RETURNING clause is the easiest way to guarantee getting the value of the ID generated by an INSERT statement. Querying for max(id) is unreliable in a multi-user environment, especially if you're using RAC.
If the ID is populated from a sequence you can get the current value of the sequence by running this in the same session as the INSERT:
select your_sequence.currval from dual;
This means you need to know the name of the sequence, which isn't always obvious, even more so if you're using 12c Identity columns.
Basically, if you want the ID use RETURNING.

Firebird trigger translated to MS SQL Server

I am converting a Firebird database to MS SQl Server. As there are multiple applications accessing the database, I really want to have the MS SQL Server act in as similar way as possible as to the Firebird database.
In Firebird it is declared as
CREATE TRIGGER CUSTOMER_BI FOR CUSTOMER
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.cust_id is null) then
new.cust_id = gen_id(gen_cust_id,1);
end
So I have a Sequence (Generator in FB) called gen_cust_id
and my main objective is to fill the field cust_id with the nextvalue from the Sequence.
I am very much aware that the SQL Server offers me an autoinc field. This is not really what I am looking for here, as the frontend application(s) do this in various manners. Some of them get a sequence number first and may or may not commit the record. I do in this case just discard the generated sequence number.
Any help is highly appreciated.
Thanks in advance
Since the ANSI sequence was not implemented until SQL 2012, you should check out this article. I've used these suggestions to make use of sequences in SQL 2005 - 2008 for a while with great results.
http://blogs.msdn.com/b/sqlcat/archive/2006/04/10/sql-server-sequence-number.aspx
So, using option 2 (my preferred), you might have a trigger looking like below.
Note: this only works on a single row insert. If you want more than 1, you need to modify the example code in the link to give you ranges and do a set-based solution to address each null id row in the inserted "table".
CREATE TRIGGER dbo.CUSTOMER_BI
ON dbo.CUSTOMER INSTEAD OF INSERT
AS
BEGIN
DECLARE #sequence_id INT;
IF EXISTS(SELECT * FROM INSERTED WHERE cust_id IS NULL)
BEGIN
EXEC #sequence_id = dbo.GetNewSeqVal_Customer;
END
INSERT INTO CUSTOMER
(
cust_id,
<col list>
)
SELECT
ISNULL(cust_id, #sequence_id),
<col list>
FROM INSERTED;
END
the position 0 only matters if there is more than one trigger on the table and if there is the mssql side can merge them into 1

Very simple SQL query on varchar fields with sqlite

I created a table with this schema using sqlite3:
CREATE TABLE monitored_files (file_id INTEGER PRIMARY KEY,file_name VARCHAR(32767),original_relative_dir_path VARCHAR(32767),backupped_relative_dir_path VARCHAR(32767),directory_id INTEGER);
now, I would like to get all the records where original_relative_dir_path is exactly equal to '.', without 's. What I did is this:
select * from monitored_files where original_relative_dir_path='.';
The result is no records even if in the table I have just this record:
1|'P9040479.JPG'|'.'|'.'|1
I read on the web and I see no mistakes in my syntax... I also tried using LIKE '.', but still no results. I'm not an expert of SQL so maybe you can see something wrong?
Thanks!
I see no problem with the statement.
I created the table that you described.
Did an INSERT with the same values that you provided.
And did the query, and also queried without a where clause.
No problems encountered, so I suspect that when you execute your selection, you may not be connected to the correct database.

informix check if table exists and then read the value

I have a table in informix (Version 11.50.UC4) called NextRecordID with just one column called id and it will have one row. What I want to do is copy this value into another table. But don't want my query to fail if this table does not exist. Something like
if table NextRecordID exists
then insert into sometable values ('NextRecordID', (select id from NextRecordID))
else insert into sometable values ('NextRecordID', 1)
I ended up using the below SQL query. Its not ANSI SQL but works the informix server I am using.
insert into sometable values ('NextRecordID',
select case (select 1 from systables where tabname='nextrecordid')
when 1 then (select nextid from nextrecordid)
else (select 1 from systables where tabname='systables') end
from systables where tabname='systables');
What is happening here is within insert query I get the value to be inserted by using select query. Now that select query is interesting. It uses case statement of Informix. I have written a select query to check if the table nextrecordid exists in systables and return 1 if it exists. If this query returns 1, I query the table nextrecordid for the value or else I wrote a query to return the default value 1. This work for me.
You should be able to do this by checking the systables table.
Thank you for including server version information - it makes answering your question easier.
You've not indicated which language(s) you are using.
Normally, though, you design a program to expect a certain schema (certain tables to be present), and then fail - preferably under control - if those tables are not present. Also, it is not clear whether you would get into problems because of repeated execution of the second INSERT statement. Nor is it clear when the NextRecordID table is updated - presumably, once the value has been used, it must be updated.
You should look at SERIAL (BIGSERIAL) and see whether that is appropriate for you.
You should also look at whether a SEQUENCE would be appropriate to use here - it certainly looks rather like it might be applicable.
As Adam Hughes points out, if you want to check whether the NextRecordID table is present in the database, you would look in the systables table. Be aware, though, that your search will need to be against an all lower-case name (nextrecordid).
Also, MODE ANSI databases complicate life - you have to worry about the table's owner (because there could be multiple tables called nextrecordid in a MODE ANSI database). Most likely, you don't have to worry about that - any more than you are likely to have to worry about delimited identifiers for table "someone"."NextRecordID" (which is a different table from someone.NextRecordID).