isau
Deity
- Joined
- Jan 15, 2007
- Messages
- 3,071
This tutorial introduces the concept of writing reports in SQLite Studio. This tutorial is current as of the Rise and Fall expansion.
What You Will Learn:
Prior to reading this tutorial:
What is a Report?
A "report" in this case will refer simply to a view of the data in the Civ 6 database. Reports allow us to see data by association. Below is a sample image of a simple report, which displays information contained in the Eras table:
(NOTE: If the above SELECT statement is outside your current skill level with SQL, it is recommended you view my starter tutorial on modding with SQLite Studio before proceeding with this lesson.)
Compared to some tools out there, SQLiteStudio's report writing features are limited. But the tool is free, and we will still be able to generate some very useful views from it, so it is the tool this tutorial will focus on.
Table Connections: Understanding JOINS
The report above is useful, perhaps, but it is limited to showing data from a single table (the Eras table). To really unlock reports, it is important to understand the concept of the JOIN statement.
JOIN is an instruction to cross-reference data from one table to data in another. In most cases, this means taking data from a column in one table then doing a look up using the primary key of that table.
For example, in our report above, we see a list of all of the Eras. EraType is the PrimaryKey of this table; it is the unique way to find any particular record.
Other tables contain references to the EraType in the Eras table. For example, consider the Technologies table:
As we can see, the Technologies table also contains a field called EraType. This is a reference to the PrimaryKey of the Eras table. As such, we can use it to perform a JOIN so that we can see data from both tables in a single report.
The syntax for writing a JOIN is as follows:
HINT: Don't worry too much about LEFT versus INNER JOIN. 99% of the time when writing reports for Civ 6 what you're looking for is a LEFT JOIN. It may be worth reading some online resources about the differences though if you find this confusing.
Here are the results of running that query:
As we can see, the report is now "wider," with much more scrolling to the right available. That's because the report contains the data from the Technologies table and the Eras table.
Limiting Results We Get Back
We don't have to stick to a wide table for the results. We can control which columns are displayed by replacing the * with the fields we want to see.
You can simply reference fields by name. As a good coding practice, it's also recommended you include the name of the table from which the field is being referenced. For example:
Now we see just 3 columns of data.
Using WHERE Statements
Just like we learned in the previous tutorial on working with SQL, you can include WHERE statements to limit the rows returned. Let's say we only want to see Technologies where the GreatPersonCost is less than 100:
One thing to watch out for when including multiple tables in a query is that you explicitly declare which table a field is coming from if both tables have a field with the same name. For example, both Eras and Technologies have a field called EraType. If we forget to include the table name when referring to the field, SQLite will throw an error:
You fix this by making the table declaration explicit:
Practical Queries: The Modifiers Tables
Now that we have the basics out of the way, we can talk about some of the more practical queries you will use over and over. Perhaps the most common one you will be using will be reports that refer to the various Modifiers tables throughout the database.
Modifiers are objects that change aspects of the game. Modifiers generally involve at least 2 components at a minimum:
There are additional aspects of Modifiers, but we will talk about them when we get to them.
Writing a Report that Links Modifiers
Because the Modifier system is so consistent, we can find the linkage between a Modifier and how it is applied by performing a simple LEFT JOIN.
This gives us a report showing all of the Modifiers that are attached to each Policy.
Now, a lot of the time the reason you are writing a report like this is you want to see not just which Modifiers are set up, but also how they are configured. Modifiers are supported by a table called ModifierArguments, that contains all the variables that go along with each Modifier. If we want to see them listed, we can just add ModifierArguments to the join, as so:
This will generate a report listing every Policy, followed by each attached Modifier, followed by each ModifierArgument attached to that Modifier.
[Note: I've run out of the ability to attach images. More in the follow up to come.]
What You Will Learn:
- How to write simple queries against the Civ 6 database
- How to read a report after creating it
- How to limit data returned to make it useful
Prior to reading this tutorial:
- You should have a basic understanding of modding with SQLiteStudio, as described here: https://forums.civfanatics.com/threads/tutorial-modding-with-sqllite-studio-pc.608352/
What is a Report?
A "report" in this case will refer simply to a view of the data in the Civ 6 database. Reports allow us to see data by association. Below is a sample image of a simple report, which displays information contained in the Eras table:
(NOTE: If the above SELECT statement is outside your current skill level with SQL, it is recommended you view my starter tutorial on modding with SQLite Studio before proceeding with this lesson.)
Compared to some tools out there, SQLiteStudio's report writing features are limited. But the tool is free, and we will still be able to generate some very useful views from it, so it is the tool this tutorial will focus on.
Table Connections: Understanding JOINS
The report above is useful, perhaps, but it is limited to showing data from a single table (the Eras table). To really unlock reports, it is important to understand the concept of the JOIN statement.
JOIN is an instruction to cross-reference data from one table to data in another. In most cases, this means taking data from a column in one table then doing a look up using the primary key of that table.
For example, in our report above, we see a list of all of the Eras. EraType is the PrimaryKey of this table; it is the unique way to find any particular record.
Other tables contain references to the EraType in the Eras table. For example, consider the Technologies table:
As we can see, the Technologies table also contains a field called EraType. This is a reference to the PrimaryKey of the Eras table. As such, we can use it to perform a JOIN so that we can see data from both tables in a single report.
The syntax for writing a JOIN is as follows:
Code:
SELECT * FROM Technologies
LEFT JOIN Eras ON Technologies.EraType = Eras.EraType ;
- You write the first part of the SELECT statement as normal. This is the first table to include in your selection (in this case, Technologies).
- To associate a second table, add your JOIN statement. JOIN will be preceeded by one of two terms:
- LEFT JOIN: Will find all records where there is a connection, but also not hide any records in Technologies with no match.
- INNER JOIN: Will only display records where there is a match between Technologies and EraType
HINT: Don't worry too much about LEFT versus INNER JOIN. 99% of the time when writing reports for Civ 6 what you're looking for is a LEFT JOIN. It may be worth reading some online resources about the differences though if you find this confusing.
- You will use the portion of the code that follows the ON statement to demonstrate the link between the tables. For example, above, we are telling the query that Technologies.EraType is a match to Eras.EraType. Using that information, SQLiteStudio is able to match those records up when we run our query.
Here are the results of running that query:
As we can see, the report is now "wider," with much more scrolling to the right available. That's because the report contains the data from the Technologies table and the Eras table.
Limiting Results We Get Back
We don't have to stick to a wide table for the results. We can control which columns are displayed by replacing the * with the fields we want to see.
You can simply reference fields by name. As a good coding practice, it's also recommended you include the name of the table from which the field is being referenced. For example:
Code:
SELECT Technologies.TechnologyType, Eras.EraType, Eras.GreatPersonBaseCost FROM Technologies
LEFT JOIN Eras ON Technologies.EraType = Eras.EraType ;
Now we see just 3 columns of data.
Using WHERE Statements
Just like we learned in the previous tutorial on working with SQL, you can include WHERE statements to limit the rows returned. Let's say we only want to see Technologies where the GreatPersonCost is less than 100:
Code:
SELECT Technologies.TechnologyType, Eras.EraType, Eras.GreatPersonBaseCost FROM Technologies
LEFT JOIN Eras ON Technologies.EraType = Eras.EraType
WHERE Eras.GreatPersonBaseCost < 100 ;
One thing to watch out for when including multiple tables in a query is that you explicitly declare which table a field is coming from if both tables have a field with the same name. For example, both Eras and Technologies have a field called EraType. If we forget to include the table name when referring to the field, SQLite will throw an error:
Code:
SELECT Technologies.TechnologyType, Eras.EraType, Eras.GreatPersonBaseCost FROM Technologies
LEFT JOIN Eras ON Technologies.EraType = Eras.EraType
WHERE EraType = 'ERA_MEDIEVAL' ;
You fix this by making the table declaration explicit:
Practical Queries: The Modifiers Tables
Now that we have the basics out of the way, we can talk about some of the more practical queries you will use over and over. Perhaps the most common one you will be using will be reports that refer to the various Modifiers tables throughout the database.
Modifiers are objects that change aspects of the game. Modifiers generally involve at least 2 components at a minimum:
- The Modifier itself, contained in a table called Modifiers
- The linkage of the Modifier, which defines how the Modifier is applied. This is usually in a table with a name that ends in "Modifiers." E.g. "PolicyModifiers" is the table that links Policies and Modifiers. "GovernmentModifiers" is the table that links Governments and Modifiers. "BeliefModifiers" links Beliefs and Modifiers. And so on.
There are additional aspects of Modifiers, but we will talk about them when we get to them.
Writing a Report that Links Modifiers
Because the Modifier system is so consistent, we can find the linkage between a Modifier and how it is applied by performing a simple LEFT JOIN.
Code:
SELECT * FROM PolicyModifiers
LEFT JOIN Modifiers on Modifiers.ModifierId = PolicyModifiers.ModifierId
This gives us a report showing all of the Modifiers that are attached to each Policy.
Now, a lot of the time the reason you are writing a report like this is you want to see not just which Modifiers are set up, but also how they are configured. Modifiers are supported by a table called ModifierArguments, that contains all the variables that go along with each Modifier. If we want to see them listed, we can just add ModifierArguments to the join, as so:
Code:
SELECT * FROM PolicyModifiers
LEFT JOIN Modifiers on Modifiers.ModifierId = PolicyModifiers.ModifierId
LEFT JOIN ModifierArguments on ModifierArguments.ModifierId = Modifiers.ModifierId
This will generate a report listing every Policy, followed by each attached Modifier, followed by each ModifierArgument attached to that Modifier.
[Note: I've run out of the ability to attach images. More in the follow up to come.]