I'm a newbie to databases and db's in Delphi, learning about both via online instructional materials. I'm struggling with a difference between real-life and the examples I'm finding. To be concrete, consider the common Books and Authors many-to-many relationship. Assume you've got a Book table (book_id, book_title, etc.), an Author table (author_id, author_name, etc.), and an AuthorBook join table. All three tables would have unique ID's, auto-generated, as primary keys.
The examples always begin with Author and Book information already inserted in their respective tables. In real-life, though, I think you'd be trying to insert records into both tables simultaneously, i.e., users would see a form or grid with places to enter a book's title and its author(s). How would something like that be coded in Delphi, assuming data-aware controls, an underlying Access database (or something else alterable via SQL)?
The T-SQL function OUTPUT, which was introduced in 2005, can be used to insert multiple values into multiple tables in a single statement. The output values of each row that was part of an INSERT, UPDATE or DELETE operation are returned by the OUTPUT clause.
Insert can only operate on one table at a time.
Relational algebra is the most common way of writing a query and also the most natural way to do so. The code is clean, easy to troubleshoot, and unsurprisingly, it is also the most efficient way to join two tables.
If you started with tables like these . . .
create table books (
book_id integer primary key,
book_title varchar(15) not null
);
create table authors (
author_id integer primary key,
author_name varchar(15) not null
);
create table book_authors (
book_id integer not null references books (book_id),
author_id integer not null references authors (author_id),
primary key (book_id, author_id)
);
. . . and if you need to insert a new book and a new author at the same time, you might execute a SQL transaction like this.
begin transaction;
insert into books values (1, 'First book');
insert into authors values (1, 'First author');
insert into book_authors (book_id, author_id) values (1, 1);
commit;
Using a single transaction guarantees that either all three inserts are written to the database, or that none of them are. Alternatives are
If you were adding a new book for an existing author, you'd execute a slightly different transaction.
begin transaction;
insert into books values (2, 'Second book');
insert into book_authors (book_id, author_id) values (2, 1);
commit;
I imagine Delphi is like any other client-side language here. Instead of literal integers, you'd reference some property of the data-aware controls, perhaps a "value" or "text" property. And you'd execute the transaction in a button's "click" event.
If Delphi is sufficiently "data aware"--using controls that are bound to columns and rows in a database, like Access's native controls are--you might not need to execute any SQL or do anything special to save any automatic ID number the dbms generates; it will be accessible through one of the control's properties. (Access's forms and controls are highly data aware; that's how they work.) But if you have to, and you're using Microsoft's OLEDB provider for Access, you can use select @@identity
to get the last id number used through your connection.
If using SQL, do something like this (pseudocode)
startTransaction;
INSERT INTO Book VALUES('Book1');
bookID:=SELECT LastAutoInc FROM #Dummy;
INSERT INTO Author VALUES('Author1');
authorID:=SELECT LastAutoInc FROM #Dummy;
INSERT INTO BookAuthor VALUES(bookID, autherID);
commit;
The key is the use of the LastAutoInc
function (or the equivalent in your database) inside a transaction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With