For weeks I am trying to get an inner Join between 2 tables to work. One table is called Stories and contains story information and the other table is called Characters and contains character information, this table has a field the refers to the ID field in the Stories table. The goal is after selecting a Story title in the Stories listbox, only see the Characters that belong to that story in the Characters Listbox.
SELECT * FROM characters INNER JOIN Stories on Stories.ID = Characters.FKStory WHERE stories.Story_title = 'A Christmas Carol'
The results are correct, only the characters belonging to the story title that I added at the end (‘A Christmas Carol’) are shown.
I cannot get this in Xojo to work though. I placed this code in the ListBoxCharacters. Running the app shows me ALL the characters from ALL the stories in the database, not only from '‘A Christmas Carol’.
Of course that last part should be changed; I don’t want to add the Story title in the code, but select a story from the StoriesListbox instead. But I figured I want to get this part to work first.
So why is this code working correctly in the DB Browser for Sqlite program, but not in Xojo?
When a story is selected, you need to update the characters list box. You’ll need to do this with some Xojo code, probably in the SelectionChanged event of the stories list box. Xojo generally doesn’t automatically update controls.
If this doesn’t help, we might need more information to help you.
Yes, that is where the code is placed: rs = app.DB.SelectSQL("SELECT * FROM characters INNER JOIN Stories on Stories.ID = Characters.FKStory WHERE Characters.ID = ?", ListBoxCharacters.RowTagAt(ListBoxCharacters.SelectedRowIndex).StringValue)
If you’re looking for a story and all the characters associated with it, this simplified example might help illustrate:
var db as new SQLiteDatabase
var rs as rowset
var sql, x as string
call db.Connect
sql = "create table stories(id integer, story_name text)"
db.ExecuteSQL(sql)
sql = "create table characters(id integer, fkstory integer, character_name text)"
db.ExecuteSQL(sql)
sql = "insert into stories(id, story_name) values (?, ?)"
db.ExecuteSQL(sql, 1, "A Christmas Carol")
db.ExecuteSQL(sql, 2, "A Halloween Tale")
db.ExecuteSQL(sql, 3, "An Easter Fable")
sql = "insert into characters(id, fkstory, character_name) values (?, ?, ?)"
db.ExecuteSQL(sql, 1, 1, "Scrooge")
db.ExecuteSQL(sql, 2, 1, "TIny Tim")
db.ExecuteSQL(sql, 3, 2, "Dracula")
db.ExecuteSQL(sql, 4, 3, "Easter Bunny")
'select story and associated characters if the story name is A Christmas Carol
sql = "select * from " +_
"stories a " +_
"inner join characters b on b.fkstory = a.id " +_
"where a.story_name = ?"
rs = db.SelectSQL(sql, "A Christmas Carol")
while not rs.AfterLastRow
x = x + "story: " + rs.Column("story_name").StringValue + " character: " + rs.Column("character_name").StringValue + EndOfLine
rs.MoveToNextRow
wend
MessageBox(x)
Edit: I originally used left join out of habit. Both return the same results in this example.
You don’t need an inner join. Give Stories a column like STORY_ID which is unique and Characters have a foreign key STORY_ID. SQL ‘select * from CHARACTERS where CHARACTERS.STORY_ID = STORY.STORY_ID’
Every selected STORY.STORY_ID will give you the related characters IF the foreign key points to the correct Story. This is simple master/slave table.
Maybe you have it figured out now. If not, your code also needs to clear the characters list box and add rows to the list box from each database row in the updated query.
Yers, it is doing this with a RefreshCharacterlist Method which rebuilds the Listbox.
Update:
Actually, I didn’t change the code here and now it only shows the correct story characters. This is great progress Now I have something to work with. Thanks for the hint.