Re: [sqlite] Write to a View

2012-11-11 Thread BareFeetWare
Hi Marco,

I know we've been discussing this directly, but since you've also mentioned it 
here on this list, I thought a response here could also facilitate greater 
discussion.

An updatable view is a view that will accept insert, delete and update 
commands, propagating changes back to the underlying tables. I believe that 
some SQL database engines (not SQLite) facilitate updatable views 
automatically, if the view uses just one table or is a simple join of tables, 
showing only some of their columns (no calculations). However, any view 
(including all views in SQLite) can be explicitly designed to be updatable by 
using instead of triggers.

Here's a very simple single table example:

create table Person
(   ID integer primary key not null
,   Name First text collate nocase
,   Name Last text collate nocase
,   unique (Name First, Name Last)
)
;
create view Person Sorted
as
select
ID
,   Name First
,   Name Last
from Person
order by Name Last, Name First
;

If I want to make the Person Sorted view updatable, I need to consider which 
of update, insert and delete I want to facilitate, and create an instead of 
trigger for each:

create trigger Person Sorted delete
instead of delete
on Person Sorted
begin
delete from Person where ID = old.ID
;
end
;
create trigger Person Sorted insert
instead of insert
on Person Sorted
begin
insert into Person (ID, Name First, Name Last)
select new.ID, new.Name First, new.Name Last
;
end
;
create trigger Person Sorted update
instead of update
on Person Sorted
begin
update Person
set ID = new.ID, Name First = new.Name First, Name Last = 
new.Name Last
where ID = old.ID
;
end
;

So, now, if the user opens the view Person Sorted, they can insert, delete or 
update directly in that view, and the triggers will propagate those changes to 
the underlying table. It appears to behave just like a table.

For instance, they can do any of the following:

insert into Person Sorted (Name First, Name Last) values ('Tom', 
'Brodhurst-Hill')
;
delete from Person Sorted where ID = 4
;
delete from Person Sorted where Name Last = 'Brodhurst-Hill'
;
update Person Sorted set Name First = 'Thomas' where Name First = 'Tom' 
and Name Last = 'Brodhurst-Hill'
;

Of course, the above example shows a view that is basically a mirror of a 
single table, so isn't very useful. It was just for illustration. Let's look at 
something more complex. Let's add the following tables so we can associate with 
each person a company, a job title and many (or one or none) email addresses. 
We can specify whether each email address is for work, home or another purpose:

create table Company
(   ID integer primary key not null
,   Name text collate nocase not null unique
)
;
create table Person Company
(   ID integer primary key not null references Person (ID) on delete 
cascade on update cascade
,   Company integer not null references Company (ID) on delete cascade 
on update cascade
)
;
create table Job Title
(   ID integer primary key not null
,   Name text collate nocase not null unique
)
;
create table Person Job Title
(   ID integer primary key not null references Person (ID) on delete 
cascade on update cascade
,   Job Title integer not null references Job Title (ID) on delete 
cascade on update cascade
)
;
create table Purpose
(   ID integer primary key not null
,   Name text collate nocase not null unique
)
;
insert into Purpose (Name) select 'Home' union select 'Work' union select 
'School'
;
create table Person Email
(   ID integer primary key not null
,   Person integer not null references Person (ID) on delete cascade on 
update cascade
,   Email text collate nocase not null
,   Purpose integer references Purpose (ID) on delete restrict on 
update cascade
,   unique (Person, Purpose)
)
;

The above structure is a fairly well normalised store of the data. In this 
example, I've restricted the database to allowing just one email address for 
each purpose. So each person can have only one work email address.

So, imagine the human resources department has populated these tables with all 
the people in our company. They want to distribute a list of all employees, 
only showing their name, company and work email address, something like this:

create view Person Work
as
select
Person.ID as ID
,   Name First
,   Name Last
,   Company.Name as Company
,   Job Title.Name as Job Title
,   (   select Email from Person Email join Purpose on 
Purpose.ID = Purpose
where Person = Person.ID and Purpose.Name = 'Work'
) as Email
from Person
left join Person Company on Person Company.ID = Person.ID
left join Company on Company.ID = Company
left join Person Job Title on Person Job Title.ID = Person.ID
left join Job Title on Job Title.ID = Job Title
order by Name Last, Name 

Re: [sqlite] Bug: Inconsistency wrt. indirectly defined columns

2012-11-11 Thread stahlhut

Quoting Igor Tandetnik itandet...@mvps.org:

stahl...@dbs.uni-hannover.de wrote:

Consider these two tables:

CREATE TABLE tab1 (x INTEGER PRIMARY KEY);
CREATE TABLE tab2 (x PRIMARY KEY REFERENCES tab1);

Assuming they contain the same rows, I expect any query against 'tab1' to
return the same rows as against 'tab2'.


Why would you expect that? You keep saying this, but I don't  
understand the basis of your expectations - unless it's just the  
good old wishful thinking.


I base my expectations on two things.

First (and probably more importantly):
Column 'x' of table 'tab2' is defined as a foreign key referencing the primary
key 'x' of table 'tab1'.
I expect that a foreign key column is in no way different than the primary key
column it points to - unless I explicitly specify it to be different.

(This has nothing to do with SQLite, but with the definition of functional
dependencies in relational databases: A foreign key *is* a primary key from
a foreign table.)

So this means the schema definitions of 'tab1' and 'tab2' must effectively be
the same and thus my assumption above should hold.

As SQLite let me leave out the column type, I thought Great! SQLite is smart
enough to infer the column type for FKs! Just like Oracle!.
Which leads to my second reason: The Oracle DBMS does what I expect.

So yes, I admit that this *is* wishful thinking on my part.
I do think, however, that my wishes are reasonable.


(I don't know what the SQL Standard has to say about this situation


I'm pretty sure the second CREATE TABLE statement is syntactically  
invalid, per the standard. The column type is mandatory, if I recall  
correctly.


Ah! I think that explains the situation somewhat:
SQLite and Oracle expand the standard in the same way by allowing to leave
out the column type for FKs.
Oracle infers the column type from the PK, but SQLite always uses the default
column type BLOB (or 'NONE'..?).
(PostgreSQL rejects the definition for 'tab2' as mentioned earlier.)

SQLite's behavior makes sense, because *every* column type may be left out.
However, I think that in the case of FK-definitions (like the one in 'tab2')
assigning the default type is not the right thing to do.


but I do think that most users would share my expectation.)


I'm not sure what you base this belief on, either. I don't seem to  
see your argument enjoying widespread support on this thread.


Yes, you are obviously right there.
I discussed the problem earlier with colleagues (mostly Oracle users), but
obviously this list is a different world. :-)


However with SQLite there are queries which yield incoherent results:


Define incoherent. As far as I can tell, you use this term to mean  
results you personally dislike. The results SQLite produces are in  
agreement - in other words, in coherence - with the product  
documentation.


I just meant 'incoherent' wrt. The same query returns different results for
the same data. as per my example.

You seem to hold this truth to be self-evident, but I honestly don't  
understand why. Could you explain your reasoning to me?


I hope the explanations above make my point at least understandable?


Also I don't really care *how* this is fixed


As best I can tell, so far there's no agreement that it's broken, so  
discussing how to fix it seems a bit premature.


Agreed there's no agreement. :-)

As I said earlier: I'm fine now that I know that I should explicitly specify
the column type (even better if that's standard compliant!).

I still think that SQLite could be made better by inferring FK column types.
But I won't pursue this matter any further if there is no agreement on this.

Thank you for your answer!
Kind regards,
Christian


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


Re: [sqlite] Bug: Inconsistency wrt. indirectly defined columns

2012-11-11 Thread stahlhut

Quoting Simon Slavin slav...@bigfraud.org:

On 10 Nov 2012, at 7:21pm, stahl...@dbs.uni-hannover.de wrote:


Consider these two tables:

CREATE TABLE tab1 (x INTEGER PRIMARY KEY);
CREATE TABLE tab2 (x PRIMARY KEY REFERENCES tab1);

Assuming they contain the same rows, I expect any query against 'tab1' to
return the same rows as against 'tab2'.


Sorry, but you are too optimistic.


Yeah, I notice that now. :-)

I would expect a schema design tool -- the sort where you move  
rectangles and pointers around -- to warn you when you put a pointer  
in from tab2 to tab1, that the affinities should match.  But in a  
language where you specifically declare schema using text, I expect  
the programmer to have to do this him- or herself.


Fair enough.

Although I would (optimistically) hope that SQL schema definitions
(and thus schema design tools) were portable between DBSes.
But this can't happen with the impact SQLite's unique concept of
'type affinities' has on schemas.

Thanks for your help tough.
Christian


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


Re: [sqlite] Bug: Inconsistency wrt. indirectly defined columns

2012-11-11 Thread Igor Tandetnik
stahl...@dbs.uni-hannover.de wrote:
 Quoting Igor Tandetnik itandet...@mvps.org:
 stahl...@dbs.uni-hannover.de wrote:
 Consider these two tables:
 
 CREATE TABLE tab1 (x INTEGER PRIMARY KEY);
 CREATE TABLE tab2 (x PRIMARY KEY REFERENCES tab1);
 
 Assuming they contain the same rows, I expect any query against 'tab1' to
 return the same rows as against 'tab2'.
 
 Why would you expect that? You keep saying this, but I don't
 understand the basis of your expectations - unless it's just the
 good old wishful thinking.
 
 I base my expectations on two things.
 
 First (and probably more importantly):
 Column 'x' of table 'tab2' is defined as a foreign key referencing the primary
 key 'x' of table 'tab1'.
 I expect that a foreign key column is in no way different than the primary key
 column it points to - unless I explicitly specify it to be different.

But you did. I can't help but notice that the two column definitions are indeed 
different: one specifies the type and the other doesn't. That effectively means 
that the two columns use different collations. Consider this example, which 
illustrates the situation more explicitly:

create table a(t text collate nocase unique);
create table b(t text collate binary references a(t));
insert into a values ('X');
insert into b values ('X');

select * from a where t='x';  -- returns one row
select * from b where t='x';  -- returns no rows

 (This has nothing to do with SQLite, but with the definition of functional
 dependencies in relational databases: A foreign key *is* a primary key from
 a foreign table.)

Depends on what the meaning of is is. SQL-92 requres that foreign key columns 
match referenced columns according to MATCH predicate:

 8.10  match predicate
 Function
 Specify a test for matching rows.

 Format
 match predicate ::=
  row value constructor MATCH [ UNIQUE ] [ PARTIAL | FULL ] 
table subquery

 Syntax Rules
 1) The row value constructor shall be of the same degree as the
table subquery.
 2) The data types of the values of the row value constructor
shall be respectively comparable to those of the corresponding
columns of the table subquery.
 3) The collating sequence for each pair of respective values in the
match predicate is determined in the same manner as described
in Subclause 8.2, comparison predicate.

Basically, the columns don't have to be of the same type, and the notion of 
matching is the usual comparison, with collations and everything.

 So this means the schema definitions of 'tab1' and 'tab2' must effectively be
 the same and thus my assumption above should hold.

Which part of which normative document requires this?

 As SQLite let me leave out the column type, I thought Great! SQLite is smart
 enough to infer the column type for FKs! Just like Oracle!.

This is, of course, a perfect example of wishful thinking.

 Which leads to my second reason: The Oracle DBMS does what I expect.

So your definition of correctness is always do what Oracle does, then? In 
this case, I suggest you only ever use Oracle, to escape disappointment. By 
this definition, it's the only correctly implemented DBMS in the world.

 So yes, I admit that this *is* wishful thinking on my part.
 I do think, however, that my wishes are reasonable.

You are, naturally, entitled to your optinion, while other people are entitled 
to theirs. In this case, the balance of opinion doesn't appear to be in your 
favor.

 SQLite's behavior makes sense, because *every* column type may be left out.
 However, I think that in the case of FK-definitions (like the one in 'tab2')
 assigning the default type is not the right thing to do.

Why should one clause in the syntax behave differently depending on the 
presence or absence of another, unrelated clause? Sounds like an arbitrary 
special case to me.

 However with SQLite there are queries which yield incoherent results:
 
 Define incoherent. As far as I can tell, you use this term to mean
 results you personally dislike. The results SQLite produces are in
 agreement - in other words, in coherence - with the product
 documentation.
 
 I just meant 'incoherent' wrt. The same query returns different results for
 the same data. as per my example.

As I've shown earlier, this is perfectly normal when two table definitions 
differ in a way that results in different collation rules being applied. This 
would be true even for a (largely hypothetical) strictly SQL-92 compliant DBMS.
-- 
Igor Tandetnik

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


[sqlite] Confusion on 'foreign key mismatch' errors

2012-11-11 Thread Darren Spruell
I'm stuck on some errors related to my use of foreign key constraints
in my application. The following illustrates:

$ sqlite3
SQLite version 3.7.9 --SOURCE-ID--
Enter .help for instructions
Enter SQL statements terminated with a ;
sqlite PRAGMA foreign_keys = ON;
sqlite CREATE VIRTUAL TABLE comment USING fts4();
sqlite CREATE TABLE ip (
   ... id INTEGER PRIMARY KEY, date_added DEFAULT CURRENT_DATE,
   ... ip VARCHAR(15) NOT NULL UNIQUE, comment INTEGER NOT NULL,
   ... FOREIGN KEY(comment) REFERENCES comment);
sqlite CREATE INDEX ipcommentindex ON ip(comment);
sqlite INSERT INTO comment VALUES ('this is a comment.');
sqlite SELECT rowid,content FROM comment;
1|this is a comment.
sqlite SELECT last_insert_rowid();
1
sqlite INSERT INTO ip (ip,comment) VALUES ('10.0.1.1',last_insert_rowid());
Error: foreign key mismatch
sqlite INSERT INTO ip (ip,comment) VALUES ('10.0.1.1',1);
Error: foreign key mismatch


Thinking I understand the requirements for foreign key constraints, I
don't know why my INSERT into ip table returns 'foreign key mismatch'
error.

When I leave foreign key constraints off, things work as I would expect:


sqlite CREATE VIRTUAL TABLE comment USING fts4();
sqlite CREATE TABLE ip (
   ... id INTEGER PRIMARY KEY, date_added DEFAULT CURRENT_DATE,
   ... ip VARCHAR(15) NOT NULL UNIQUE, comment INTEGER NOT NULL,
   ... FOREIGN KEY(comment) REFERENCES comment);
sqlite CREATE INDEX ipcommentindex ON ip(comment);
sqlite INSERT INTO comment VALUES ('this is a comment.');
sqlite SELECT rowid,content FROM comment;
1|this is a comment.
sqlite SELECT last_insert_rowid();
1
sqlite INSERT INTO ip (ip,comment) VALUES ('10.0.1.1',last_insert_rowid());
sqlite SELECT * FROM ip;
1|2012-11-12|10.0.1.1|1


I suspect the issue might stem from trying to use the rowid in the
comment table as the parent key in the foreign key on the ip table,
reading:

# http://www.sqlite.org/foreignkeys.html
The parent key is the column or set of columns in the parent table
that the foreign key constraint refers to. This is normally, but not
always, the primary key of the parent table. The parent key must be a
named column or columns in the parent table, not the rowid.

...but then this kind of reads like it's supported:

# http://answers.oreilly.com/topic/1955-how-to-use-full-text-search-in-sqlite/
Unlike traditional tables, the ROWID of an FTS table is stable through
a vacuum (VACUUM in Appendix C), so it can be reliably referenced
through a foreign key.


I'm struggling to find a clear way to achieve a foreign key
constrained relation between these tables if a.) the FTS table can't
define an INTEGER PRIMARY KEY column to function as the parent key for
a child table, or b.) child tables can't reference the rowid on an FTS
parent table as the parent key.

Clue bat appreciated.

-- 
Darren Spruell
phatbuck...@gmail.com
___
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users


Re: [sqlite] Confusion on 'foreign key mismatch' errors

2012-11-11 Thread Pavel Ivanov
 # http://answers.oreilly.com/topic/1955-how-to-use-full-text-search-in-sqlite/
 Unlike traditional tables, the ROWID of an FTS table is stable through
 a vacuum (VACUUM in Appendix C), so it can be reliably referenced
 through a foreign key.

I'm not sure who wrote that but this page
http://www.sqlite.org/lang_createtable.html states explicitly (at the
very end): The parent key of a foreign key constraint is not allowed
to use the rowid.


Pavel


On Sun, Nov 11, 2012 at 9:49 PM, Darren Spruell phatbuck...@gmail.com wrote:

 I'm stuck on some errors related to my use of foreign key constraints
 in my application. The following illustrates:

 $ sqlite3
 SQLite version 3.7.9 --SOURCE-ID--
 Enter .help for instructions
 Enter SQL statements terminated with a ;
 sqlite PRAGMA foreign_keys = ON;
 sqlite CREATE VIRTUAL TABLE comment USING fts4();
 sqlite CREATE TABLE ip (
... id INTEGER PRIMARY KEY, date_added DEFAULT CURRENT_DATE,
... ip VARCHAR(15) NOT NULL UNIQUE, comment INTEGER NOT NULL,
... FOREIGN KEY(comment) REFERENCES comment);
 sqlite CREATE INDEX ipcommentindex ON ip(comment);
 sqlite INSERT INTO comment VALUES ('this is a comment.');
 sqlite SELECT rowid,content FROM comment;
 1|this is a comment.
 sqlite SELECT last_insert_rowid();
 1
 sqlite INSERT INTO ip (ip,comment) VALUES ('10.0.1.1',last_insert_rowid());
 Error: foreign key mismatch
 sqlite INSERT INTO ip (ip,comment) VALUES ('10.0.1.1',1);
 Error: foreign key mismatch


 Thinking I understand the requirements for foreign key constraints, I
 don't know why my INSERT into ip table returns 'foreign key mismatch'
 error.

 When I leave foreign key constraints off, things work as I would expect:


 sqlite CREATE VIRTUAL TABLE comment USING fts4();
 sqlite CREATE TABLE ip (
... id INTEGER PRIMARY KEY, date_added DEFAULT CURRENT_DATE,
... ip VARCHAR(15) NOT NULL UNIQUE, comment INTEGER NOT NULL,
... FOREIGN KEY(comment) REFERENCES comment);
 sqlite CREATE INDEX ipcommentindex ON ip(comment);
 sqlite INSERT INTO comment VALUES ('this is a comment.');
 sqlite SELECT rowid,content FROM comment;
 1|this is a comment.
 sqlite SELECT last_insert_rowid();
 1
 sqlite INSERT INTO ip (ip,comment) VALUES ('10.0.1.1',last_insert_rowid());
 sqlite SELECT * FROM ip;
 1|2012-11-12|10.0.1.1|1


 I suspect the issue might stem from trying to use the rowid in the
 comment table as the parent key in the foreign key on the ip table,
 reading:

 # http://www.sqlite.org/foreignkeys.html
 The parent key is the column or set of columns in the parent table
 that the foreign key constraint refers to. This is normally, but not
 always, the primary key of the parent table. The parent key must be a
 named column or columns in the parent table, not the rowid.

 ...but then this kind of reads like it's supported:

 # http://answers.oreilly.com/topic/1955-how-to-use-full-text-search-in-sqlite/
 Unlike traditional tables, the ROWID of an FTS table is stable through
 a vacuum (VACUUM in Appendix C), so it can be reliably referenced
 through a foreign key.


 I'm struggling to find a clear way to achieve a foreign key
 constrained relation between these tables if a.) the FTS table can't
 define an INTEGER PRIMARY KEY column to function as the parent key for
 a child table, or b.) child tables can't reference the rowid on an FTS
 parent table as the parent key.

 Clue bat appreciated.

 --
 Darren Spruell
 phatbuck...@gmail.com
 ___
 sqlite-users mailing list
 sqlite-users@sqlite.org
 http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users
___
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users


Re: [sqlite] Confusion on 'foreign key mismatch' errors

2012-11-11 Thread Simon Slavin

On 12 Nov 2012, at 5:49am, Darren Spruell phatbuck...@gmail.com wrote:

 sqlite CREATE TABLE ip (
   ... id INTEGER PRIMARY KEY, date_added DEFAULT CURRENT_DATE,
   ... ip VARCHAR(15) NOT NULL UNIQUE, comment INTEGER NOT NULL,
   ... FOREIGN KEY(comment) REFERENCES comment);
 sqlite CREATE INDEX ipcommentindex ON ip(comment);
 sqlite INSERT INTO comment VALUES ('this is a comment.');
 sqlite SELECT rowid,content FROM comment;
 1|this is a comment.
 sqlite SELECT last_insert_rowid();
 1
 sqlite INSERT INTO ip (ip,comment) VALUES ('10.0.1.1',last_insert_rowid());
 Error: foreign key mismatch

You slipped up in the FOREIGN KEY definition.  You're relating it to the text 
field of the comment table.  You should be relating it to the 'rowid' field,  
possibly something like.

  ... FOREIGN KEY(comment) REFERENCES comment(rowid));

However, you cannot relate to rowid, because it's not a properly defined field. 
 So define an 'id' field for the comment table, then make sure you refer to it 
in your FOREIGN KEY definition.

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


Re: [sqlite] Confusion on 'foreign key mismatch' errors

2012-11-11 Thread Darren Spruell
On Sun, Nov 11, 2012 at 11:16 PM, Simon Slavin slav...@bigfraud.org wrote:

 On 12 Nov 2012, at 5:49am, Darren Spruell phatbuck...@gmail.com wrote:

 sqlite CREATE TABLE ip (
   ... id INTEGER PRIMARY KEY, date_added DEFAULT CURRENT_DATE,
   ... ip VARCHAR(15) NOT NULL UNIQUE, comment INTEGER NOT NULL,
   ... FOREIGN KEY(comment) REFERENCES comment);
 sqlite CREATE INDEX ipcommentindex ON ip(comment);
 sqlite INSERT INTO comment VALUES ('this is a comment.');
 sqlite SELECT rowid,content FROM comment;
 1|this is a comment.
 sqlite SELECT last_insert_rowid();
 1
 sqlite INSERT INTO ip (ip,comment) VALUES ('10.0.1.1',last_insert_rowid());
 Error: foreign key mismatch

 You slipped up in the FOREIGN KEY definition.  You're relating it to the text 
 field of the comment table.  You should be relating it to the 'rowid' field,  
 possibly something like.

   ... FOREIGN KEY(comment) REFERENCES comment(rowid));

 However, you cannot relate to rowid, because it's not a properly defined 
 field.  So define an 'id' field for the comment table, then make sure you 
 refer to it in your FOREIGN KEY definition.

If I'm not mistaken, that's a problem too, as type definitions are
ignored on FTS columns:

# http://www.sqlite.org/fts3.html
If column names are explicitly provided for the FTS table as part of
the CREATE VIRTUAL TABLE statement, then a datatype name may be
optionally specified for each column. This is pure syntactic sugar,
the supplied typenames are not used by FTS or the SQLite core for any
purpose. The same applies to any constraints specified along with an
FTS column name - they are parsed but not used or recorded by the
system in any way.

I would want my 'id' field to behave as an autoincrementing integer
field (i.e. INTEGER PRIMARY KEY) to work properly.

So I think I might be at an impasse with this plan. Maybe I'll drop
the foreign key and restructure around it.

Thx!

-- 
Darren Spruell
phatbuck...@gmail.com
___
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users