The insert sequence does not work in all cases. This fixes one particular
problem of duplicate or changed linkage to parent in Alpha:Charlie ...
create trigger trg_summary_insert
instead of insert on summary
for each row
begin
insert or ignore into Alpha (a_attribute) values (new.a_attribute);
insert or ignore into Beta (b_attribute) values (new.b_attribute);
select raise(ABORT,'c_attribute has different a_attribute parent')
from Charlie
where c_attribute == new.c_attribute
and a_id != (select id from Alpha where a_attribute == new.a_attribute);
insert or ignore into Charlie (c_attribute, a_id) values (new.c_attribute,
(select id from Alpha where a_attribute == new.a_attribute));
insert or abort into AlphaBeta values ((select id from Alpha where a_attribute
== new.a_attribute),
(select id from Beta where b_attribute
== new.b_attribute));
end;
That is, you need to throw an error if c_attribute is already linked to a
different a_attribute, otherwise you can insert or ignore into Charlie.
---
The fact that there's a Highway to Hell but only a Stairway to Heaven says a
lot about anticipated traffic volume.
>-----Original Message-----
>From: sqlite-users [mailto:sqlite-users-
>[email protected]] On Behalf Of Keith Medcalf
>Sent: Wednesday, 20 February, 2019 09:44
>To: SQLite Users ([email protected])
>Subject: Re: [sqlite] What is the recommended way to write to views?
>
>
>Or as a trigger of course:
>
>create table Alpha
>(
> id integer primary key,
> a_attribute text not null collate nocase unique
>);
>
>create table Beta
>(
> id integer primary key,
> b_attribute text not null collate nocase unique
>);
>
>create table Charlie
>(
> id integer primary key,
> c_attribute text not null collate nocase unique,
> a_id integer not null references Alpha
>);
>create index Charlie_a_id on Charlie (a_id);
>
>create table AlphaBeta
>(
> a_id integer not null references Alpha,
> b_id integer not null references Beta,
> unique(a_id, b_id),
> unique(b_id, a_id)
>);
>
>create view Summary (a_attribute, b_attribute, c_attribute)
>as select a_attribute,
> b_attribute,
> c_attribute
> from Alpha, Beta, Charlie, AlphaBeta
> where Alpha.id == Charlie.a_id
> and Alpha.id == AlphaBeta.a_id
> and Beta.id == AlphaBeta.b_id
>;
>
>create trigger trg_summary_insert
>instead of insert on summary
>for each row
>begin
>insert or ignore into Alpha (a_attribute) values (new.a_attribute);
>insert or ignore into Beta (b_attribute) values (new.b_attribute);
>insert into Charlie (c_attribute, a_id) values (new.c_attribute,
>(select id from Alpha where a_attribute == new.a_attribute));
>insert into AlphaBeta values ((select id from Alpha where a_attribute
>== new.a_attribute),
> (select id from Beta where b_attribute
>== new.b_attribute));
>end;
>
>Note that I fixed the subselects when I originally wrote them I
>followed the rule that "columns containing the same data should have
>the same name" yet did not follow that rule when creating the schema.
>Sorry bout that.
>
>Nonetheless, you probably want to use source programming to maintain
>the database properly rather than relying on triggers, unless you
>plan to write a "whole set of them" (update, delete) so you can
>"pretend" that a complicated relational data structure is "just a
>table".
>
>However the instead of trigger does have the advantage of being one
>compiled as a single plan, and does get around the daftness of some
>database interfaces.
>
>---
>The fact that there's a Highway to Hell but only a Stairway to Heaven
>says a lot about anticipated traffic volume.
>
>
>>-----Original Message-----
>>From: Keith Medcalf [mailto:[email protected]]
>>Sent: Wednesday, 20 February, 2019 09:24
>>To: 'SQLite mailing list'
>>Subject: RE: [sqlite] What is the recommended way to write to views?
>>
>>
>>Your constraints are logically inconsistent and incompletely
>>specified.
>>
>>>Alpha has-many Beta,and
>>>Beta has-many Alpha
>>>Alpha has-many Charlie, while
>>>Charlie has one Alpha
>>
>>Implies that:
>>
>>Alpha:Beta is N:M and Beta:Alpha is N:M. Fine.
>>but you did not say whether the instant relationships are unique.
>>(That is, whether one specific Alpha may have only one Beta as a
>>child, or it may have multiple instances of the same Beta as a
>>child). We will assume that the set is unique and enforce that.
>>
>>Alpha:Charlie is 1:N and Charlie:Alpha is N:1. Fine.
>>
>>You also did not specify how to handle NULL attributes. Since how
>>you do this makes significant changes to the processing and
>integrity
>>of the database, we will assume that you simply forgot about the
>>possibility of null values and thus assume that attributes will not
>>be null. Further we assume that the attribute comprises an entire
>>candidate key and therefore is unique in each set.
>>
>>(where do you get such silly column names from for the foreign key
>>linkage fields, it looks like some idiotic "lets put a bunch o'junk
>>as prefixes on a variable name to embed the context into the name,
>>just cuz we can and that is our (albeit foolish) standard. Mutatis
>>mutandis the N:M join table. And why are you using AUTOINCREMENT
>...
>>are you overloading some meaning onto the id's rather than just
>using
>>it for linkage?)
>>
>>
>>create table Alpha
>>(
>> id integer primary key,
>> a_attribute text not null collate nocase unique
>>);
>>
>>create table Beta
>>(
>> id integer primary key,
>> b_attribute text not null collate nocase unique
>>);
>>
>>create table Charlie
>>(
>> id integer primary key,
>> c_attribute text not null collate nocase unique,
>> a_id integer not null references Alpha
>>);
>>create index Charlie_a_id on Charlie (a_id);
>>
>>create table AlphaBeta
>>(
>> a_id integer not null references Alpha,
>> b_id integer not null references Beta,
>> unique(a_id, b_id),
>> unique(b_id, a_id)
>>);
>>
>>create view Summary (a_attribute, b_attribute, c_attribute)
>>as select a_attribute,
>> b_attribute,
>> c_attribute
>> from Alpha, Beta, Charlie, AlphaBeta
>> where Alpha.id == Charlie.a_id
>> and Alpha.id == AlphaBeta.a_id
>> and Beta.id == AlphaBeta.b_id
>>;
>>
>>To add a record you need to do the following in your programming
>>language:
>>
>>begin immediate;
>>insert or ignore into Alpha (a_attribute) values (?); -- where
>you
>>bind a_attribute
>>select id from Alpha where a_attribute == ?; -- where
>you
>>bind a_attribute and save the a_id returned
>>insert or ignore into Beta (b_attribute) values (?); -- where
>you
>>bind b_attribute
>>select id from Beta where b_attribute == ?; -- where
>you
>>bind b_attribute and save the b_id returned
>>insert into Charlie (c_attribute, a_id) values (?, ?); -- where
>you
>>bind c_attribute and the saved a_id
>>insert into AlphaBeta values (a_id, b_id) values (?, ?); -- where
>you
>>bind the a_id and b_id
>>commit;
>>
>>If an error is thrown at any step (anywhere in the sequence) then
>>your insert data is inconsistent and you must rollback the
>>transaction.
>>
>>
>>Alternatively, you may do something like the following:
>>
>>begin immediate;
>>insert or ignore into Alpha (a_attribute) values (:a_attribute);
>>insert or ignore into Beta (b_attribute) values (:b_attribute);
>>insert into Charlie (c_attribute, a_id) values (:c_attribute,
>(select
>>a_id from Alpha where a_attribute == :a_attribute));
>>insert into AlphaBeta values ((select a_id from Alpha where
>>a_attribute == :a_attribute),
>> (select b_id from Beta where
>>b_attribute == :b_attribute));
>>commit;
>>
>>depending on the capabilities of your source language interface. I
>>would use the second because my source language interface knows how
>>to run "batches" of statements and how to bind from a named
>>dictionary (plus it only requires caching 4 statement plans as
>>opposed to 6), though in the grand scheme of things the performance
>>is about the same.
>>
>>If you were inserting a bunch of data (as in from parsing a CSV
>file,
>>for example) then you might want to only begin one transaction for
>>the whole mess and use savepoints around each row, then commit the
>>single transaction as a whole. For performance you know, since
>>spinning rust is limited in how many transactions it can perform per
>>second and the I/O rate.
>>
>>---
>>The fact that there's a Highway to Hell but only a Stairway to
>Heaven
>>says a lot about anticipated traffic volume.
>>
>>>-----Original Message-----
>>>From: sqlite-users [mailto:sqlite-users-
>>>[email protected]] On Behalf Of Rocky Ji
>>>Sent: Wednesday, 20 February, 2019 04:14
>>>To: SQLite mailing list
>>>Subject: [sqlite] What is the recommended way to write to views?
>>>
>>>Hi everyone,
>>>
>>>I know the simple answer to be `instead of insert ...`. But
>consider
>>>a
>>>situation where:
>>>
>>>Alpha has-many Beta,and
>>>Beta has-many Alpha
>>>Alpha has-many Charlie, while
>>>Charlie has one Alpha
>>>
>>>So if my SQL looks like:
>>>-- PRAGMA fk ON;
>>>create table Alpha (
>>> a_id integer primary key autoincrement,
>>> a_attribute text
>>>);
>>>
>>>create table Beta (
>>> b_id integer primary key autoincrement,
>>> b_attribute real
>>>);
>>>
>>>create table Charlie (
>>> c_id integer primary key autoincrement,
>>> c_attribute text,
>>> FK_C_a_id integer,
>>> constraint abc foreign key (FK_C_a_id) references Alpha (a_id)
>>>);
>>>
>>>create table m2mAlphaBeta (
>>> _id integer primary key autoincrement,
>>> FK_a_id integer,
>>> FK_b_id integer,
>>> constraint def foreign key (FK_a_id) references Alpha (a_id),
>>> constraint ghi foreign key (FK_b_id) references Beta (b_id)
>>>);
>>>
>>>
>>>create view summary
>>>as
>>> select
>>> a.a_attribute,
>>> b.b_attribute,
>>> c.c_attribute
>>> from
>>> m2mAlphaBeta m
>>> inner join Alpha a on a.a_id = m.FK_a_id
>>> inner join Beta b on b.b_id = m.FK_b_id
>>> inner join Charlie c on c.FK_C_a_id = a.a_id
>>>;
>>>
>>>
>>>And assuming all incoming data (say from CSV read) is correct. How
>>do
>>>I
>>>write a record to `summary`?
>>>
>>>Like how do I get ROWID of the "just inserted" record in A to
>insert
>>>into C
>>>properly. I am thinking "should I make transactions, but we don't
>>>have
>>>variables"... and going round-and-round without solution.
>>>
>>>Please recommend the canonical way to write to such views.
>>>
>>>Good day.
>>>_______________________________________________
>>>sqlite-users mailing list
>>>[email protected]
>>>http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-
>users
>
>
>
>_______________________________________________
>sqlite-users mailing list
>[email protected]
>http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
_______________________________________________
sqlite-users mailing list
[email protected]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users