mirror of
https://github.com/github/codeql.git
synced 2026-04-26 01:05:15 +02:00
81 lines
5.0 KiB
ReStructuredText
81 lines
5.0 KiB
ReStructuredText
Find the thief: More advanced queries
|
|
=====================================
|
|
|
|
What if you want to find the oldest, youngest, tallest, or shortest person in the village? As mentioned in the previous topic, you can do this using ``exists``. However, there is also a more efficient way to do this in QL using functions like ``max`` and ``min``. These are examples of `aggregates <https://help.semmle.com/QL/ql-handbook/expressions.html#aggregations>`__.
|
|
|
|
In general, an aggregate is a function that performs an operation on multiple pieces of data and returns a single value as its output. Common aggregates are ``count``, ``max``, ``min``, ``avg`` (average) and ``sum``. The general way to use an aggregate is:
|
|
|
|
.. code-block:: ql
|
|
|
|
<aggregate>(<variable declarations> | <logical formula> | <expression>)
|
|
|
|
For example, you can use the ``max`` aggregate to find the age of the oldest person in the village:
|
|
|
|
.. code-block:: ql
|
|
|
|
max(int i | exists(Person p | p.getAge() = i) | i)
|
|
|
|
This aggregate considers all integers ``i``, limits ``i`` to values that match the ages of people in the village, and then returns the largest matching integer.
|
|
|
|
But how can you use this in an actual query?
|
|
|
|
If the thief is the oldest person in the village, then you know that the thief's age is equal to the maximum age of the villagers:
|
|
|
|
.. code-block:: ql
|
|
|
|
from Person t
|
|
where t.getAge() = max(int i | exists(Person p | p.getAge() = i) | i)
|
|
select t
|
|
|
|
This general aggregate syntax is quite long and inconvenient. In most cases, you can omit certain parts of the aggregate. A particularly helpful QL feature is *ordered aggregation*. This allows you to order the expression using ``order by``.
|
|
|
|
For example, selecting the oldest villager becomes much simpler if you use an ordered aggregate.
|
|
|
|
.. code-block:: ql
|
|
|
|
select max(Person p | | p order by p.getAge())
|
|
|
|
The ordered aggregate considers every person ``p`` and selects the person with the maximum age. In this case, there are no restrictions on what people to consider, so the ``<logical formula>`` clause is empty. Note that if there are several people with the same maximum age, the query lists all of them.
|
|
|
|
Here are some more examples of aggregates:
|
|
|
|
+-------------------------------------------------------------------------+---------------------------------------------------+
|
|
| Example | Result |
|
|
+=========================================================================+===================================================+
|
|
| ``min(Person p | p.getLocation() = "east" | p order by p.getHeight())`` | shortest person in the east of the village |
|
|
+-------------------------------------------------------------------------+---------------------------------------------------+
|
|
| ``count(Person p | p.getLocation() = "south" | p)`` | number of people in the south of the village |
|
|
+-------------------------------------------------------------------------+---------------------------------------------------+
|
|
| ``avg(Person p | | p.getHeight())`` | average height of the villagers |
|
|
+-------------------------------------------------------------------------+---------------------------------------------------+
|
|
| ``sum(Person p | p.getHairColor() = "brown" | p.getAge())`` | combined age of all the villagers with brown hair |
|
|
+-------------------------------------------------------------------------+---------------------------------------------------+
|
|
|
|
Capture the culprit
|
|
-------------------
|
|
|
|
You can now translate the remaining questions into QL:
|
|
|
|
+-----+--------------------------------------------------------------------+--------+
|
|
| | Question | Answer |
|
|
+=====+====================================================================+========+
|
|
| ... | ... | ... |
|
|
+-----+--------------------------------------------------------------------+--------+
|
|
| 9 | Is the thief the tallest person in the village? | no |
|
|
+-----+--------------------------------------------------------------------+--------+
|
|
| 10 | Is the thief shorter than the average villager? | yes |
|
|
+-----+--------------------------------------------------------------------+--------+
|
|
| 11 | Is the thief the oldest person in the eastern part of the village? | yes |
|
|
+-----+--------------------------------------------------------------------+--------+
|
|
|
|
Have you found the thief?
|
|
|
|
➤ `See the answer in the query console <https://lgtm.com/query/1505744186085/>`__
|
|
|
|
What next?
|
|
----------
|
|
|
|
- Help the villagers track down another criminal in the :doc:`next tutorial <fire-1>`.
|
|
- Find out more about the concepts you discovered in this tutorial in the `QL language handbook <https://help.semmle.com/QL/ql-handbook/index.html>`__.
|
|
- Explore the libraries that help you get data about code in :doc:`Learning QL <../../index>`.
|