Re: Create multiple sqlite tables, many-to-many design

2019-08-15 Thread Peter Otten
Chris Angelico wrote:

> On Thu, Aug 15, 2019 at 7:41 PM Gregory Ewing
>  wrote:
>>
>> Chris Angelico wrote:
>> > I prefer to say "Trails" for the table, and "Trail" would then refer
>> > to a single row from that table.
>>
>> That makes sense for a data structure in your program that contains a
>> collection of rows. But I've come to the view that SQL tends to read
>> better if the names of the database tables are singular, because in SQL
>> you're writing assertions about individual rows, not the tables in
>> their entirety.
>>
>> So I would write something like
>>
>> select T.name, T.id from Trail T
>>
>> but I would assign the resulting list of rows to a variable named
>> "trails" in my program.
>>
> 
> You're selecting from a collection of trails. I don't see a conflict
> here. It's the same as taking a list of values and then filtering it -
> even though assertions are made about individuals, you are filtering
> the entire list:
> 
> early_things = [thing for thing in things if thing.name < 'M']

If list comprehensions were like sql queries then the above would be

early_things = [things.* from things where things.name < "M"]

That doesn't read well as the condition works on one thing at a time.
However, I'm so used to

select things.* from things where things.name < "M"

in the sql context that I still prefer it. Also, in simple queries you can 
omit the table name.


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-15 Thread Chris Angelico
On Thu, Aug 15, 2019 at 7:41 PM Gregory Ewing
 wrote:
>
> Chris Angelico wrote:
> > I prefer to say "Trails" for the table, and "Trail" would then refer
> > to a single row from that table.
>
> That makes sense for a data structure in your program that contains a
> collection of rows. But I've come to the view that SQL tends to read
> better if the names of the database tables are singular, because in SQL
> you're writing assertions about individual rows, not the tables in
> their entirety.
>
> So I would write something like
>
> select T.name, T.id from Trail T
>
> but I would assign the resulting list of rows to a variable named
> "trails" in my program.
>

You're selecting from a collection of trails. I don't see a conflict
here. It's the same as taking a list of values and then filtering it -
even though assertions are made about individuals, you are filtering
the entire list:

early_things = [thing for thing in things if thing.name < 'M']

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-15 Thread Gregory Ewing

Chris Angelico wrote:

I prefer to say "Trails" for the table, and "Trail" would then refer
to a single row from that table.


That makes sense for a data structure in your program that contains a
collection of rows. But I've come to the view that SQL tends to read
better if the names of the database tables are singular, because in SQL
you're writing assertions about individual rows, not the tables in
their entirety.

So I would write something like

   select T.name, T.id from Trail T

but I would assign the resulting list of rows to a variable named
"trails" in my program.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-14 Thread Rich Shepard

On Wed, 14 Aug 2019, Chris Angelico wrote:


I prefer to say "Trails" for the table, and "Trail" would then refer to a
single row from that table.


+1

Rich
--
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-14 Thread Chris Angelico
On Wed, Aug 14, 2019 at 9:06 PM Gregory Ewing
 wrote:
>
> MRAB wrote:
> > Another thing you might want to avoid is naming something with what it
> > is, e.g. "Trails_Table" (why not just "Trails").
>
> Or possibly just "Trail", since any table potentially contains
> multiple rows, so making all your table names plural doesn't
> add any information.
>

I prefer to say "Trails" for the table, and "Trail" would then refer
to a single row from that table.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-14 Thread Gregory Ewing

MRAB wrote:
Another thing you might want to avoid is naming something with what it 
is, e.g. "Trails_Table" (why not just "Trails").


Or possibly just "Trail", since any table potentially contains
multiple rows, so making all your table names plural doesn't
add any information.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-13 Thread Rich Shepard

On Wed, 14 Aug 2019, MRAB wrote:


The actual code is different. htbl, ttbl, jtbl, etc. Too short?


Definitely! :-)

Another thing you might want to avoid is naming something with what it is, 
e.g. "Trails_Table" (why not just "Trails").


Another reason to read Celko's 'SQL Programming Style.'

In the 1970s I was writing FORTRAN ecosystem models punched on 80-column
Hollerith cards using an IBM 029 keypunch. Everything was as short as
possible, especially variable names. There were two valuable lessons I
learned (in addition to marking a Sharpie pen line diagonally across the
card deck to make it easier to put back in sequence when the box was
dropped):

1. Make variable names fully descriptive.

2. Write many comments to explain what things are and why you're doing
things the way you are.

The reason is that within 6 months (or less) you will look at your schema
and code and have no idea what's going on or why you wrote it like that.

Table names are commonly written with initial uppercase letters; variables
in all lowercase. Leave CamelCase in the desert. Use underscores between
words, e.g., hike_id, trail_nbr, not hyphens.

And, you might not be the only person looking at the schema and code needing
to understand what's going on.

Rich
--
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-13 Thread MRAB

On 2019-08-13 22:11, Dave via Python-list wrote:

On 8/13/19 4:45 PM, MRAB wrote:

On 2019-08-13 19:59, Chris Angelico wrote:

On Wed, Aug 14, 2019 at 4:50 AM Dave via Python-list
 wrote:

Some of the tables are related.  For example:

Hiking_Table Trails_Table    Joining_Table
-        -
hike_id PK   trail_id  PK    hike_id   FK
hike_date  TEXT  trail_name  TEXT    trail_id   FK
hike_destination TEXT    trail_rating REAL
hike_rating  REAL    trail_comments TEXT
hike_comments  TEXT


[snip]
Might I also suggest dropping unnecessary prefixes from the field names. 
For example, "hike_comments" in "Hiking_Table" can be called just 
"comments" because it's clear from the context that a field called 
"comments" in the hiking table will contain comments about hiking, if 
you see what I mean.


I do indeed.  I did that so it was easy for everyone to follow.  Having
started with assm. and C, I have to remind myself to be more explanatory
in naming.  Guess I over-did it.  The actual code is different. htbl,
ttbl, jtbl, etc.  Too short?


Definitely! :-)

Another thing you might want to avoid is naming something with what it 
is, e.g. "Trails_Table" (why not just "Trails").

--
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-13 Thread Dave via Python-list

On 8/13/19 5:46 PM, Rich Shepard wrote:

On Tue, 13 Aug 2019, Rich Shepard wrote:


Read Joe Celko's books, starting with his SQL Programming Guide, then SQL


That should be SQL Programming Style

Rich


Rich,

On my next trip to BN I'll see if they have them.  That is long term 
though.  Right now I just need to know how to populate the join table 
and anything else that has escaped me.


SQL is cool.  SQL + Python (or C or C++ or Java) is more cool.  Lot 
easier to understand than pointer math in C.


Dave,
--
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-13 Thread Rich Shepard

On Tue, 13 Aug 2019, Rich Shepard wrote:


Read Joe Celko's books, starting with his SQL Programming Guide, then SQL


That should be SQL Programming Style

Rich
--
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-13 Thread Chris Angelico
On Wed, Aug 14, 2019 at 7:26 AM Dave via Python-list
 wrote:
> Thanks for the note.  I get the theory of MTM and the join table.  It is
> the implementation I don't get.  Let me see if I can demonstrate my
> confusion using pseudo code.
>
> def dbDataInsert():
>
>  sql_HikeInsert = """ INSERT INTO hike (
>   hike_date,
>   hike_destination,
>   hike_rating,
>   hike_comments )
>   VALUES (
>   hdate,
>   hdestination,
>   hrating,
>   hcomments ) """
>
>  sql_TrailInsert = """ NSERT INTO trail (
>   trail_name,
>   trail_rating,
>   trail_comment )
>VALUES (
>   tname1,
>   trating1,
>   tcomments1 ) """
>
>  sql_TrailInsert = """ NSERT INTO trail (
>   trail_name,
>   trail_rating,
>   trail_comment )
>VALUES (
>   tname2,
>   trating2,
>   tcomments2 ) """
>
>  """ ---> Now what?  I need to populate the join (hike_trail) table.
>   Do I query the tables to get the id's?  Is there another
>   way?  This is the part I really don't get.  """
>

Gotcha!

Some database engines (including PostgreSQL) allow you to add a
RETURNING clause to your INSERT statement, which will then turn it
into a combined "insert, then select from the newly-inserted rows".
SQLite3 does not have this, but there is a special attribute on the
cursor (which you haven't shown in the cut-down example here, but I
presume you know what I'm talking about) to retrieve the ID of the
newly-inserted row:

https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.lastrowid

So after inserting into the hike table, you can grab the ID of that
row off the cursor, and then same after the trail. Then you just
insert into the join table using those IDs.

A proper RETURNING clause is far more flexible (it can handle multiple
rows, it can be chained into other queries, etc), but this should be
sufficient for what you're doing here.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-13 Thread Rich Shepard

On Tue, 13 Aug 2019, Dave via Python-list wrote:


I do indeed. I did that so it was easy for everyone to follow. Having
started with assm. and C, I have to remind myself to be more explanatory
in naming. Guess I over-did it. The actual code is different. htbl, ttbl,
jtbl, etc. Too short?


Dave,

I encourage you to step back and approach your project from a different
side. Databases, especially relational ones using SQL, are a very different
world from Assembly, C, Python, and other procedural/functional/whatever
languages.

Read Joe Celko's books, starting with his SQL Programming Guide, then SQL
for Smarties. A book on relational database design (other than these) would
help. One I've used is Van der Laans' 'Introductory SQL'.

SQL is a set language and thinking in sets is different from thinking in
step-wise procedures. With SQL to tell the engine what you want, not how to
do it. The engine decides the optimal way of getting the results you want
from the tables.

There are three components of SQL; most of us use only two of them: DDL
(Data Definition Language) to define tables and relationships and DML (Data
Manipulation Language) which we use to write queries.

When you get your head around all this consider using Python and SQLAlchemy
with SQLite3, postgresql, or whatever you want for the database back end.

Good luck!

Rich
--
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-13 Thread Dave via Python-list

On 8/13/19 2:59 PM, Chris Angelico wrote:

On Wed, Aug 14, 2019 at 4:50 AM Dave via Python-list
 wrote:

Some of the tables are related.  For example:

Hiking_Table Trails_TableJoining_Table
--
hike_id PK   trail_id  PKhike_id   FK
hike_date  TEXT  trail_name  TEXTtrail_id   FK
hike_destination TEXTtrail_rating REAL
hike_rating  REALtrail_comments TEXT
hike_comments  TEXT

So far, so good.  I know how to create the tables.  What I am struggling
with is how do I insert data into the joining table or don"t I?  If so,
do I need to query the other two tables to get the auto-number ID's?
Some things I have read suggest that the joining table just contains
references, so there is no actual insert.  A pointer to information how
to do this would be appreciated.  As for queries, I think I use joins,
but a pointer on how to do this would also be appreciated.


The joining table is a real thing, and will have real inserts. It
might be easier to think of this as two separate one-to-many
relationships; for the sake of demonstration, I'm going to add another
column to your joining table.

hike_sections ==> hike_id references hikes, trail_id references
trails, companion_name

You've decided to have someone with you for some sections of your
hike. As such, what we have is a number of "mini-hikes" that make up a
single hike (that's a one-to-many relationship between hikes and
sections), and also a single trail can be a section of any number of
hikes (so, another one-to-many relationship between trails and
sections). For any given section, there is exactly one companion.

Does this make the many-to-many relationship a bit easier to
understand? It'll work exactly the same way even if you have no
ancillary information in that joining table.

ChrisA


Chris,

Thanks for the note.  I get the theory of MTM and the join table.  It is 
the implementation I don't get.  Let me see if I can demonstrate my 
confusion using pseudo code.


def dbTables_create (dbpath):

sql_HikeTable = """ CREATE TABLE IF NOT EXISTS hike (
hike_id INTEGER AUTO_INCREMENT PRIMARY KEY,
hike_date TEXT,
hike_destination TEXT,
hike_rating REAL,
hike_comments TEXT ) """

sql_TrailTable = """ CREATE TABLE IF NOT EXISTS trail (
trail_id INTEGER AUTO_INCREMENT PRIMARY KEY,
trail_name TEXT,
trail_rating REAL,
trail_comment TEXT ) """

sql_JoiningTable = """ CREATE TABLE IF NOT EXISTS hike_trail (
hike_id INTEGER
trail_id INTEGER ) """

# Some more code to open connection, create cursor, execute SQL.

def getUserInput ():
# Code to get the user input.
# The user input is:
hdate = "2019-05-28"
hdestination = "Top of White Face Mountain, NY."
hrating = 5.0   # Rating scale 1.0 (bad) to 5.0 (perfect).
hcomments "Got to do again.  Better shoes needed."
tname1 = "Brookside"
trating1 = 4.5
tcomments1 = "Easy"
tname2 = "Wilmington Trail"
trating2 = 4.9
tcomments2 = "Awesome!!"

def dbDataInsert():

sql_HikeInsert = """ INSERT INTO hike (
 hike_date,
 hike_destination,
 hike_rating,
 hike_comments )
 VALUES (
 hdate,
 hdestination,
 hrating,
 hcomments ) """

sql_TrailInsert = """ NSERT INTO trail (
 trail_name,
 trail_rating,
 trail_comment )
  VALUES (
 tname1,
 trating1,
 tcomments1 ) """

sql_TrailInsert = """ NSERT INTO trail (
 trail_name,
 trail_rating,
 trail_comment )
  VALUES (
 tname2,
 trating2,
 tcomments2 ) """

""" ---> Now what?  I need to populate the join (hike_trail) table.
 Do I query the tables to get the id's?  Is there another
 way?  This is the part I really don't get.  """

Dave,


--
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-13 Thread Dave via Python-list

On 8/13/19 4:45 PM, MRAB wrote:

On 2019-08-13 19:59, Chris Angelico wrote:

On Wed, Aug 14, 2019 at 4:50 AM Dave via Python-list
 wrote:

Some of the tables are related.  For example:

Hiking_Table Trails_Table    Joining_Table
-        -
hike_id PK   trail_id  PK    hike_id   FK
hike_date  TEXT  trail_name  TEXT    trail_id   FK
hike_destination TEXT    trail_rating REAL
hike_rating  REAL    trail_comments TEXT
hike_comments  TEXT

So far, so good.  I know how to create the tables.  What I am struggling
with is how do I insert data into the joining table or don"t I?  If so,
do I need to query the other two tables to get the auto-number ID's?
Some things I have read suggest that the joining table just contains
references, so there is no actual insert.  A pointer to information how
to do this would be appreciated.  As for queries, I think I use joins,
but a pointer on how to do this would also be appreciated.


The joining table is a real thing, and will have real inserts. It
might be easier to think of this as two separate one-to-many
relationships; for the sake of demonstration, I'm going to add another
column to your joining table.

hike_sections ==> hike_id references hikes, trail_id references
trails, companion_name

You've decided to have someone with you for some sections of your
hike. As such, what we have is a number of "mini-hikes" that make up a
single hike (that's a one-to-many relationship between hikes and
sections), and also a single trail can be a section of any number of
hikes (so, another one-to-many relationship between trails and
sections). For any given section, there is exactly one companion.

Does this make the many-to-many relationship a bit easier to
understand? It'll work exactly the same way even if you have no
ancillary information in that joining table.

Might I also suggest dropping unnecessary prefixes from the field names. 
For example, "hike_comments" in "Hiking_Table" can be called just 
"comments" because it's clear from the context that a field called 
"comments" in the hiking table will contain comments about hiking, if 
you see what I mean.


I do indeed.  I did that so it was easy for everyone to follow.  Having 
started with assm. and C, I have to remind myself to be more explanatory 
in naming.  Guess I over-did it.  The actual code is different. htbl, 
ttbl, jtbl, etc.  Too short?


Dave,
--
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-13 Thread MRAB

On 2019-08-13 19:59, Chris Angelico wrote:

On Wed, Aug 14, 2019 at 4:50 AM Dave via Python-list
 wrote:

Some of the tables are related.  For example:

Hiking_Table Trails_TableJoining_Table
--
hike_id PK   trail_id  PKhike_id   FK
hike_date  TEXT  trail_name  TEXTtrail_id   FK
hike_destination TEXTtrail_rating REAL
hike_rating  REALtrail_comments TEXT
hike_comments  TEXT

So far, so good.  I know how to create the tables.  What I am struggling
with is how do I insert data into the joining table or don"t I?  If so,
do I need to query the other two tables to get the auto-number ID's?
Some things I have read suggest that the joining table just contains
references, so there is no actual insert.  A pointer to information how
to do this would be appreciated.  As for queries, I think I use joins,
but a pointer on how to do this would also be appreciated.


The joining table is a real thing, and will have real inserts. It
might be easier to think of this as two separate one-to-many
relationships; for the sake of demonstration, I'm going to add another
column to your joining table.

hike_sections ==> hike_id references hikes, trail_id references
trails, companion_name

You've decided to have someone with you for some sections of your
hike. As such, what we have is a number of "mini-hikes" that make up a
single hike (that's a one-to-many relationship between hikes and
sections), and also a single trail can be a section of any number of
hikes (so, another one-to-many relationship between trails and
sections). For any given section, there is exactly one companion.

Does this make the many-to-many relationship a bit easier to
understand? It'll work exactly the same way even if you have no
ancillary information in that joining table.

Might I also suggest dropping unnecessary prefixes from the field names. 
For example, "hike_comments" in "Hiking_Table" can be called just 
"comments" because it's clear from the context that a field called 
"comments" in the hiking table will contain comments about hiking, if 
you see what I mean.

--
https://mail.python.org/mailman/listinfo/python-list


Re: Create multiple sqlite tables, many-to-many design

2019-08-13 Thread Chris Angelico
On Wed, Aug 14, 2019 at 4:50 AM Dave via Python-list
 wrote:
> Some of the tables are related.  For example:
>
> Hiking_Table Trails_TableJoining_Table
> --
> hike_id PK   trail_id  PKhike_id   FK
> hike_date  TEXT  trail_name  TEXTtrail_id   FK
> hike_destination TEXTtrail_rating REAL
> hike_rating  REALtrail_comments TEXT
> hike_comments  TEXT
>
> So far, so good.  I know how to create the tables.  What I am struggling
> with is how do I insert data into the joining table or don"t I?  If so,
> do I need to query the other two tables to get the auto-number ID's?
> Some things I have read suggest that the joining table just contains
> references, so there is no actual insert.  A pointer to information how
> to do this would be appreciated.  As for queries, I think I use joins,
> but a pointer on how to do this would also be appreciated.

The joining table is a real thing, and will have real inserts. It
might be easier to think of this as two separate one-to-many
relationships; for the sake of demonstration, I'm going to add another
column to your joining table.

hike_sections ==> hike_id references hikes, trail_id references
trails, companion_name

You've decided to have someone with you for some sections of your
hike. As such, what we have is a number of "mini-hikes" that make up a
single hike (that's a one-to-many relationship between hikes and
sections), and also a single trail can be a section of any number of
hikes (so, another one-to-many relationship between trails and
sections). For any given section, there is exactly one companion.

Does this make the many-to-many relationship a bit easier to
understand? It'll work exactly the same way even if you have no
ancillary information in that joining table.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list