>>>>> Igor Tandetnik writes:

[…]

 > Note that ending up in the IGNORE branch of INSERT OR IGNORE
 > statement doesn't constitute failure, but normal execution.  The same
 > is true for INSERT ... SELECT statement where SELECT returns zero
 > rows so nothing is actually inserted.

        Thus was my question: how do I ensure that a SELECT … INSERT
        statement results in exactly one row being inserted?
        (Additional constraint: it should be possible to use the code in
        a trigger.)  The best thing I was able to imagine is to replace:

INSERT INTO "bar" ("foo")
    SELECT          f."rowid" FROM "foo" f WHERE f."foo" = ?1;

        with:

INSERT INTO "bar" ("foo")
    VALUES ((SELECT f."rowid" FROM "foo" f WHERE f."foo" = ?1));

        … The task I'm solving seems unlike an unusual one.  Suppose
        that, e. g., I'm recording a history of clients.  Each client
        has a name, and is served an arbitrary (but positive) number of
        times, at particular dates.  Or, for the 0'th approximation:

CREATE TABLE "history" (
    "client-name"       TEXT    NOT NULL,
    -- as in: CAST (strftime ('%s', 'now') AS INTEGER), or now ()
    "timestamp"         INTEGER NOT NULL
);

        The redundancy of the schema above could, however, be reduced as
        follows:

CREATE TABLE "client" (
    "name"              TEXT    NOT NULL
);

CREATE UNIQUE INDEX "client-unique"
    ON "client" ("name");

CREATE TABLE "history-1" (
    "client"            INTEGER NOT NULL  REFERENCES "client",
    "timestamp"         INTEGER NOT NULL
);

        Now, I wish to preserve the simplicity of access of the first
        variant.  Thus, I create a VIEW:

CREATE VIEW "history"
    AS  SELECT  c."name" AS "client-name",
                h."timestamp"
            FROM "history-1" h
                INNER JOIN "client" c
                    ON (c."rowid" = h."client");

        … and a TRIGGER:

CREATE TRIGGER "history-insert"
    INSTEAD OF INSERT ON "history" FOR EACH ROW BEGIN
        INSERT OR IGNORE INTO "client" ("name")
            VALUES (new."client-name");
        INSERT INTO "history-1" ("client", "timestamp")
            VALUES ((SELECT c."rowid"
                         FROM "client".c
                         WHERE c."name" = new."client-name"),
                    new."timestamp");
    END;

        This way, an application can SELECT from and INSERT into this
        new "history" VIEW with just the same simplicity as was possible
        with the former "history" TABLE.  Naturally, this trigger
        requires that a single INSERT to the "history" VIEW results in
        exactly a single INSERT to the underlying "history-1" TABLE.
        (Which is what brought my question above.)

        To note is that, with little CASE trickery, it's possible to
        support “hybrid” (id, value) views (c."rowid" AS "client-id" in
        the VIEW above), and NULL non-constraints, just as well.

-- 
FSF associate member #7257      np. ml_hygm.xm

_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to