Help:Extension - Cargo
From Dragon Mania Legends (DML) Wiki
The information may be incorrect or incomplete, and may change without warning.
Helpful Resources
Important notes
- Where possible, avoid
LIKE
with%
at the start of the pattern, which does a full table scan. - Avoid the use of
LIKE
inHOLDS
.
Creating Tables & Storing Data
See the documentation above for fulsome details on how to use Cargo, this just gives a super brief reminder!
Using Cargo |
---|
Declaring/Creating DB tableThe declaration to create the Cargo table, must go between <noinclude></noinclude> tags in the template that is used on pages you desire to query. The following tells Cargo to create a table in the database named "Events," with the Events template parameters as column names (note these names can be whatever is desired, in later steps Cargo is told what actual parameter names get stored in them). Note: SQL terms like "update" cannot be used as parameters/column names, so instead the first letter of the table name was used; e.g., for the "DragonInfos" table, "dupdate" was used instead of "update". {{#cargo_declare: _table = EventInfos |started = Wikitext |duration = Wikitext |type = Wikitext |prize = Wikitext |vip = Wikitext |dragon = Wikitext |reward = Wikitext |ended = Wikitext |ticket = Wikitext |ticketType = Wikitext }} Storing Data in Cargo tablesNow we tell Cargo what to store in each column by assigning template parameters. This must go between <includeonly></includeonly> tags. And, the lines must the lines above to prevent errors, (as of v2.8 leaving one on/off causes a bug (duplicate lines in tables). {{#cargo_store: _table = EventInfos |started = {{{started|}}} |duration = {{{duration|}}} |type = {{{type|}}} |prize = {{{prize|}}} |vip = {{{vip|}}} |dragon = {{{dragon|}}} |reward = {{{reward|}}} |ended = {{{ended|}}} }}
Creating and Populating the TableCargo table creation/re-creation is not automatic, rather after adding the code to the relevant template to create a Cargo table for, revisit the template page (viewing) and use page actions to select "Create/Recreate table/data". Some tables cannot be created/recreated from the interface (such as _pageData or _fileData tables) if the number of pages to create for is too large (in the thousands), in which case, there are command line scripts in the Cargo/maintenance directory. Table population takes place via the job queue and may take a while to fully populate. |
Cargo Tables on this Wiki
Cargo tables on this wiki are found at Special:CargoTables. At this time, only the cargo-admin user group can create, recreate, delete, or switch-in Cargo tables.
Query Reference
Once a Cargo table is made and populated, it can be queried. Note: Unlike SQL, when using Cargo, table selection comes first, followed by column(s) (referred to as "field(s)") selection.
Allowed functions
Math functions | COUNT , FLOOR , CEIL , ROUND , MAX , MIN , AVG , SUM , POWER , LN , LOG
|
---|---|
String functions | CONCAT , IF , LOWER , LCASE , UPPER , UCASE , SUBSTRING , TRIM , FORMAT
|
Date functions | NOW , DATE , YEAR , MONTH , DAYOFMONTH , DATE_FORMAT , DATE_ADD , DATE_SUB , DATEDIFF
|
Auto-created Table Columns
Field | Description |
---|---|
_pageName
|
The page name for this row of values. |
_pageTitle
|
The page title (without namespace) for this row of values. |
_pageNamespace
|
The numerical ID for the page's namespace (for the row of values). |
_pageID
|
The MediaWiki ID for the page (for the row of values). |
_ID
|
The unique ID for the row. |
SELECT & FROM
SELECT
- Selects the columns by column name to include in (or make available for) the output.- The Cargo name for this is
tables
- The Cargo name for this is
FROM
- Specifies which Cargo table to select the items from.- The Cargo name for this is
fields
- The Cargo name for this is
Note LIMIT
is being used here (though explained below) to limit the result count to prevent excessive result numbers.
SQL:
SELECT _pageName, type FROM DragonInfos LIMIT 2;
Cargo:
{{#cargo_query: tables=DragonInfos |fields=_pageName, type |limit=2 }}
DISTINCT/group by
DISTINCT does not work in Cargo (except within a function like COUNT()), use "group by" to eliminate duplicates instead.
AS/Alias
AS
- Sets a column label alias (or table header alias) on the result set only.- Important: when
format=template
is used, parameter values are retried by the alias set. So iftype=Type
then{{{Type|}}}
is used to retrieve the value. This also allows compound query values with the same name to be set as different parameter names for template use.
SQL:
SELECT _pageName AS 'Dragon', type AS 'Type' FROM DragonInfos LIMIT = 2;
Cargo:
{{#cargo_query: tables=DragonInfos |fields=_pageName=Dragon, type=Type |limit=2 }}
Conditions
WHERE
Where syntax is displayed directly below, and the sections following that also gives examples for:
- WHERE + AND, to look for rows where ALL conditions are met.
- WHERE + OR, to look for rows where ANY conditions are met.
- WHERE + IN, is a list-based shorthand for OR, to look for rows where ANY conditions are met (when there are multiple conditions).
- WHERE + NOT IN, to look for rows that DON'T meet ANY of a list of multiple conditions.
- WHERE + NOT, to look for rows NOT matching a condition.
WHERE using numbers
WHERE
- Sets conditions/criteria for selection
SQL:
SELECT _pageName, cost FROM ObtainingInfos WHERE cost > 100 LIMIT 2;
Cargo:
{{#cargo_query: tables = ObtainingInfos |fields = _pageName, cost |where = cost > 100 |limit = 2 }}
WHERE using text
SQL:
SELECT _pageName AS Dragon, type AS Type FROM DragonInfos WHERE type = 'Epic';
Cargo:
{{#cargo_query: tables= DragonInfos |fields = _pageName=Dragon, type=Type |where = type = 'Epic' |limit = 2 }}
WHERE + AND
- WHERE + AND, looks for rows where ALL conditions are met.
SQL:
SELECT _pageName=Dragon, type=Type, base=Base FROM DragonInfos WHERE type = 'Epic' AND base = 'Fire' LIMIT 2;
Cargo:
{{#cargo_query: tables = DragonInfos |fields = _pageName=Dragon, type=Type, base=Base |where = type = 'Epic' AND base ='Fire' |limit = 2 }}
WHERE + OR
- WHERE + OR, looks for rows where ANY conditions are met.
SQL:
SELECT pageName=Dragon, type=Type, base=Base FROM DragonInfos WHERE type = 'Tyrant' OR type = 'Ancient'
Cargo:
{{#cargo_query: tables = DragonInfos |fields =_pageName=Dragon, type=Type, base=Base |where = type = 'Tyrant' OR type = 'Ancient' |limit = 2 }}
WHERE + IN
- WHERE + IN - Is a list-based shorthand for OR, to look for rows where ANY conditions are met (when there are multiple conditions).
- Data can be filtered based on a list instead of chaining together multiple unwieldy OR statements.
{{#cargo_query: tables = DragonInfos |fields = _pageName, type, base |where = type IN ('Ancient', 'Tyrant', 'Divine', 'Primal') |limit = 10 }}
WHERE + NOT IN
- WHERE + NOT IN, to look for rows that DON'T meet ANY of a list of conditions.
{{#cargo_query: tables = DragonInfos |fields = _pageName, type, base |where = type NOT IN ('Ancient', 'Tyrant', 'Divine', 'Primal') |limit = 10 }}
WHERE + NOT
- WHERE + NOT, to look for rows NOT matching a condition.
{{#cargo_query: tables = DragonInfos |fields = _pageName, type, base |where = NOT type = 'Ancient' |limit = 10 }}
LIKE/Wildcards
_
- Underscore is wildcard for single character%
- Percent is wildcard for any number of characters.
LIKE example using _
(underscore)
SQL:
SELECT _pageName, type, base FROM DragonInfos WHERE _pageName LIKE 'Di_e Dragon' LIMIT 2;
Cargo: The following returns both Dice and Dile Dragon's name, rarity/type, and base element.
{{#cargo_query: tables = DragonInfos |fields = _pageName, type, base |where = _pageName LIKE 'Di_e Dragon' |limit = 2 }}
LIKE example using %
(percent)
SQL:
SELECT _pageName, type, base FROM DragonInfos WHERE _pageName LIKE 'Fairy%' LIMIT 2;
Cargo: The following returns both Fairy and Fairy Dust Dragon's name, rarity/type, and base element.
{{#cargo_query: tables = DragonInfos |fields = _pageName, type, base |where = _pageName LIKE 'Fairy%' |limit = 2 }}
Between
Between accepts two values that are either numbers, text, or dates.
BETWEEN example using numbers
SQL:
SELECT _pageName, cost FROM ObtainingInfos WHERE cost BETWEEN 700 AND 900
Cargo:
{{#cargo_query: tables = ObtainingInfos |fields = _pageName, cost |where = cost BETWEEN 700 AND 900 |limit = 2 }}
BETWEEN example using letters
SQL:
SELECT _pageName, cost FROM ObtainingInfos WHERE _pageName BETWEEN 'M' AND 'N';
Cargo:
{{#cargo_query: tables = ObtainingInfos |fields = _pageName, cost |where = _pageName BETWEEN 'M' AND 'N' |limit = 2 }}
IS/IS NOT - NULL
Unknown values are indicated by NULL. It's not possible to test for NULL values using comparison operators, (e.g., =
and !=
) which is why IS/NOT NULL is useful.
IS NOT NULL example
SQL:
SELECT _pageName, base FROM DragonInfos WHERE base IS NOT NULL LIMIT 2;
Cargo: This example returns Dragons that are not Clan Dragons, whose 'base' is NULL.
{{#cargo_query: tables = DragonInfos |fields = _pageName, base |where = base IS NOT NULL |limit = 2 }}
IS NULL example
SQL:
SELECT _pageName, base FROM DragonInfos WHERE base IS NULL LIMIT 2;
Cargo: This example returns only Clan Dragons, whose 'base' is NULL.
{{#cargo_query: tables = DragonInfos |fields = _pageName, base |where = base IS NULL |limit = 2 }}
Order & Volume
Limit
SQL:
SELECT name FROM dragons LIMIT 2;
Cargo:
{{#cargo_query: tables = DragonInfos |fields = _pageName, type |limit = 2 }}
ORDER BY
ASC
- Sort results in ascending order (default, needs not be specified).DESC
- Sort results in descending order.
SQL:
SELECT _pageName, type FROM DragonInfos LIMIT 2 ORDER BY _pageName DESC;
Cargo: The following sorts from Z to A:
{{#cargo_query: tables = DragonInfos |fields = _pageName, type |limit = 2 |order by = _pageName DESC }}
Aggregate Functions
Aggregate functions perform a calculation on a set of values and return a single value:
Column References
SQL:
SELECT COUNT(*) AS 'Total Dragons', type AS 'Type' FROM DragonInfos GROUP BY 2 ORDER BY 1 LIMIT 2;
Cargo: This example creates a new column (not in the DragonInfos Cargo database table) named "Total Dragons" and populates it with the grouped (by type) count of each type/rarity. The table is then ordered by Note: Unnamed, and only numbered, columns return a Cargo error and must always be specified by name per the error message received.
{{#cargo_query: tables = DragonInfos |fields = COUNT(*)=Total Dragons, type=Type |group by = type |order by = Total Dragons |limit = 10 }}
COUNT
SELECT type, COUNT(*) FROM DragonInfos WHERE type = 'Epic'
Cargo:
{{#cargo_query: tables = DragonInfos |fields = COUNT(*) |where = type = 'Epic' }}
SUM
SQL:
SELECT SUM(cost) FROM ObtainingInfos;
Cargo: The name of a column is used as an argument in which SUM returns the sum of all values in that column of the results set (in this case, the total cost of all dragons, which is a bit misleading as they represent multiple currency types).
{{#cargo_query: tables = ObtainingInfos |fields = SUM(cost) }}
MAX
Note: Will not work on mixed data fields, such as cost, which contains wikitext. SQL:
SELECT MAX(health3) FROM DragonInfos;
Cargo: The name of a column is used as an argument in which MAX returns the the largest value in that column of the results set (in this case, the total cost of all dragons, which is a bit misleading as they represent multiple currency types).
{{#cargo_query: tables = DragonInfos |fields = MAX(health3) }}
GROUP BY
Groups records in a result set by identical values in one (or more) columns and is often used with aggregate functions to query the information in similar records.
SQL:
SELECT type, COUNT(*) FROM DragonInfos GROUP BY type LIMIT 2;
Cargo:
{{#cargo_query: tables = DragonInfos |fields = type, COUNT(*) |group by = type |limit = 2 }}
MIN
Note: Will not work on mixed data fields, such as cost, which contains wikitext. SQL:
SELECT MIN(health3) FROM DragonInfos;
Cargo:
{{#cargo_query: tables = DragonInfos |fields = MIN(health3) }}
AVG
Note: Will not work on mixed data fields, such as cost, which contains wikitext. SQL:
SELECT AVG(health3) FROM DragonInfos;
Cargo:
{{#cargo_query: tables = DragonInfos |fields = AVG(health3) }}
HAVING
Used to with GROUP BY
to further filter the result groups provided. Must be declared after a GROUP BY clause but before ORDER BY or LIMIT clauses.
SQL:
SELECT type, COUNT(*) FROM dragons GROUP BY type HAVING COUNT(*) > 50;
Cargo: Shows only the rarities/types of dragons that have greater than 50 results.
{{#cargo_query: tables = DragonInfos |fields = type, COUNT(*) |group by = type |having = COUNT(*) > 50 }}
ROUND
SQL:
SELECT health3 ROUND(AVG(health3), 2) FROM DragonInfos;
Cargo:
{{#cargo_query: tables = DragonInfos |fields = ROUND(AVG(health3),2) }}
CONCAT
{{#cargo_query: tables = DragonInfos |fields =_pageName, CONCAT(base, " ",second, " ", third) = Elements |where=type = 'Epic' |limit = 5 }}
Note: If any concatenated fields are empty, none display. Better to send the raw elements to a template, and in that template use something like {{forEach|{{{base|}}},{{{second|}}},{{{third|}}}|ei}}
.
- Date concatenation example
CONCAT(DATE_FORMAT(startDate,'%d.%m.%Y'), DATE_FORMAT(startDate, ' %H:%i:%s'))
Multiple Tables
The information may be incorrect or incomplete, and may change without warning.
Outer Join (join on)
Specifies how to connect a/each pair of tables and corresponds to LEFT OUTER JOIN...ON clauses in SQL, though pairs of tables are separated by commas rather than "AND".
SQL:
SELECT EventInfos._pageName, EventInfos.prize, _pageData._numRevisions FROM EventInfos LEFT JOIN _pageData ON EventInfos._pageName = pageData._pageName; LIMIT 5;
Cargo:
{{#cargo_query: tables = EventInfos, _pageData |join on = EventInfos._pageID = _pageData._pageID |fields = EventInfos._pageName, EventInfos.prize, _pageData._numRevisions |limit = 5 }}
Note: Always best to join on _pageID
which is the MediaWiki ID for a page, since there is occasionally a duplicate row issue in Cargo, though they get different IDs. Joining this way prevents any duplicates from interfering with the query.
Format using CONCAT:
{{#cargo_query: tables = EventInfos, _pageData |join on = EventInfos._pageID = _pageData._pageID |fields = CONCAT( '[[', EventInfos._pageName, ']]' )=Event, CONCAT( '{{di|', EventInfos.prize, '|2}}' )=Dragon Prize, _numRevisions |limit = 5 }}
Cargo-Specific Commands
HOLDS variations
The information may be incorrect or incomplete, and may change without warning.
All HOLDS
-related commands are exclusively used for fields that contain a list of values (includes HOLDS
, HOLDS NOT
, HOLDS LIKE
). This is essentially a shortcut for simple queries to find a value against a list.
The HOLDS
command allows AND
but does not allow OR
. So, If you need anything more complex, like OR
, IN
, or NOT IN
you should query the full (child) table of the "list-type" field instead. Also, avoid using LIKE
with HOLDS
(thanks to the river.me blog for some details paraphrased here).
Important Notes:
- List-type fields are not really lists, they are actually a field like
cargocats__FULL
of typeString
with all values concatenated together by its declaration delimiter:|cargocats = List (,) of Wikitext string
. - SQL does not support a list type, instead Cargo actually stores these in the field noted above and creates a child table to store its values.
- So if the
DragonInfos
table has a "list-type" field calledcargocats
, Cargo creates a child table called:DragonInfos__cargocats
. To query this table, it must be included intables
, then have its parent cell ID joined to the matching child table row ID.
Joining parent to child:
{{#cargo_query: tables = DragonInfos, DragonInfos__cargocats |join on=DragonInfos._ID = DragonInfos__cargocats._rowID }}
_ID
is the parent table's primary key._rowID
is the child table's foreign key, the matching parent row ID.
List tables (that are no coordinates) have 3 columns:
_rowID
_value
(the value to query)_position
(1-indexed)
To query on a child table value:
{{#cargo_query: tables = DragonInfos, DragonInfos__cargocats |join on = DragonInfos._ID = DragonInfos__cargocats._rowID |fields = _pageName, DragonInfos.cargocats |where = DragonInfos__cargocats._value="Category:Event Dragons" |format = table |limit = 5 }}
Notes:
- In the
fields
list, omit__FULL
(the extension adds it, unless you're usingHOLDS
in thewhere
clause, where it gives the._value
of the child table). - Query on the child table name (e.g.,
DragonInfos__cargocats
), against its value._value
fields. - It's possible to join on a
_value
.
HOLDS
TBD
- Remember, you cannot use
OR
withHOLDS
, should not useLIKE
, though can useAND
. For this reason, it is probably better to query the__FULL
field as noted above.
HOLDS LIKE
TBD
- Using this is not the best idea, see above.
HOLDS NOT
TBD
HOLDS NOT LIKE
TBD
- Using this is not the best idea, see above.
WITHIN
Applies to hierarchy fields that hold a single value, allowing matching against not only a value, but all of its children's values as defined in that hierarchy. TBD
HOLDS WITHIN
Works on hierarchy fields that hold not a single value but a list of values. TBD
NEAR
Used for coordinates.
MATCHES (fulltext search)
Used on columns that have the "Searchtext" type, where a standard text search can be done on the column's contents (e.g., similar to MATCH ... AGAINST in MySQL, which is why it only works on MySQL). By default this displays result output similar to MediaWiki's standard search functionality.
Generally, the only "Searchtext" type field is the _pageData._fullText field (see Storing page data).
Note: The following also works: |where=_pageData._fullText LIKE "%searchterm%"
Query:
{{#cargo_query: tables = _pageData |fields = _pageName=Page, _fullText=Search results |where = _categories HOLDS 'Base Dragons' AND _fullText MATCHES 'underbelly' |limit = 5 }}
Note: It's important to know that MediaWiki does not update categories right away, so this method of category selection is unreliable. Instead, to force category update on page save, a "cargocats" column has been added to cause pages to those categories to be logged on page save.
Multiple matches and special characters:
{{#cargo_query: tables = EventInfos, _pageData |join on = EventInfos._pageID = _pageData._pageID |fields = EventInfos.type=Type, EventInfos._pageName=Event Name, EventInfos.started=Started, EventInfos.duration=Duration, EventInfos.ended=Ended |where = _pageData._fullText MATCHES '"dragon{{=}}Sunrise" "prize{{=}}Sunrise" "dungeonoffer{{=}}Sunrise" "di{{!}}Sunrise{{!}}2"' |order by = EventInfos.started DESC |limit = 5 }}
Notes:
- See w3Schools Joins.
- Example of viewing the full text content of a page via the API, after pressing make request.
- For MATCHES, which functions like SQL MATCH AGAINST, see Boolean Full-Text Searches.
- LEFT JOIN (equivalent to Cargo
join on
): Returns all results/records from left table, and matched records from right table.
- LEFT JOIN (equivalent to Cargo
Other Examples
Example:
{{#cargo_query: tables = EventInfos |fields = _pageTitle=Title, type, started, duration, prize, vip, reward, ended |where = _pageTitle LIKE '%(21/%' |limit = 5 |offset = 0 |named args = yes |default = No Events to display |more results text = <!-- no more results text --> }}
Cargo Issues/Bugs
There are a few bugs with Cargo on version 3.2. To create tables, headers must be set in |intro=
, and footers set in |outro=
. However, Cargo's "Modify Query" function (that appears automatically on paginated result sets) doesn't respect |intro=
or |outro=
, and unchecks namedargs=yes
(which is equivalent to the checkbox) by default, meaning that formatting and values are dropped if a user modifies the query using this utility. For this reason, it has been disabled on this wiki to prevent issues.
Other Bugs
See the following for other potential bugs: