Написание неправильного синтаксиса SQL не так уж и плохо, потому что вы сразу узнаете, исправите то, что упустили, и вуаля, поскольку ничего не произошло. Что действительно очень плохо, так это когда код запускается и выдает результаты, но это неправильные результаты (также не сумасшедшие ошибки, иначе вы могли бы заметить).

Чтобы продемонстрировать это, представьте, что у вас есть две таблицы, первая содержит клиентов вашего веб-сайта, а вторая содержит заказы, сделанные на веб-сайте.

customers table:
+-------------+---------------+-------------+
| customer_id | customer_name | visit_count |
+-------------+---------------+-------------+
|      1      |   John Doe    |      5      |
|      2      |  Jane Smith   |      8      |
|      3      | Mike Johnson  |      3      |
+-------------+---------------+-------------+
orders table:
+----------+-------------+------------+--------------+
| order_id | customer_id | order_date | total_amount |
+----------+-------------+------------+--------------+
|    1     |      1      | 2023-07-10 |    50.00     |
|    2     |      1      | 2023-07-12 |    75.00     |
|    3     |      2      | 2023-07-11 |   120.50     |
|    4     |      3      | 2023-07-15 |    25.75     |
+----------+-------------+------------+--------------+

Большую часть времени мы работаем не со столами сами по себе, а после их объединения. Вышеупомянутые таблицы могут быть объединены в столбце customer_id.

Теперь, если мы хотим вычислить что-то столь же простое, как общее количество посещений веб-сайта или общее количество посещений пользователем, если мы не будем очень осторожны, мы получим неверные результаты, не заметив этого.

SELECT SUM(c.visit_count) AS total_visits
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id

Результатом будет 21 посещение, что неверно.

И даже когда мы пытаемся суммировать общее количество посещений на пользователя:

SELECT c.customer_id, c.customer_name, SUM(c.visit_count) AS total_visits
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name;

Мы получаем неверные значения для одного из клиентов (клиента, у которого более одного заказа):

customers table:
+-------------+---------------+--------------+
| customer_id | customer_name | total_visits |
+-------------+---------------+--------------+
|      1      |   John Doe    |      10      |
|      2      |  Jane Smith   |      8       |
|      3      | Mike Johnson  |      3       |
+-------------+---------------+--------------+

Мы можем увидеть, что пошло не так, взглянув на таблицу, полученную в результате соединения:

+-------------+---------------+--------------+----------+------------+--------------+
| customer_id | customer_name | visit_count  | order_id | order_date | total_amount |
+-------------+---------------+--------------+----------+------------+--------------+
|      1      |   John Doe    |     5        |    1     | 2023-07-10 |    50.00     |
|      1      |   John Doe    |     5        |    2     | 2023-07-12 |    75.00     |
|      2      |  Jane Smith   |     8        |    3     | 2023-07-11 |   120.50     |
|      3      | Mike Johnson  |     3        |    4     | 2023-07-15 |    25.75     |
+-------------+---------------+--------------+----------+------------+--------------+

Это явление называется разветвлением, и его трудно заметить, потому что результаты частично верны. Например, если мы агрегируем одно из других измерений (например, вычисляем количество посещений на одного клиента), результаты будут неправильными только для клиентов, которые сделали более 1 заказа.

Вот весь код SQL, чтобы проверить его самостоятельно на такой платформе, как sqlite:

CREATE TABLE customers (
  customer_id integer,
  customer_name varchar(255),
  visit_count integer
);

CREATE TABLE orders (
  order_id integer,
  customer_id integer,
  order_date date,
  total_amount decimal(10, 2)
);

INSERT INTO customers (customer_id, customer_name, visit_count) VALUES
(1, 'John Doe', 5),
(2, 'Jane Smith', 8),
(3, 'Mike Johnson', 3);

INSERT INTO orders (order_id, customer_id, order_date, total_amount) VALUES
(1, 1, '2023-07-10', 50.00),
(2, 1, '2023-07-12', 75.00),
(3, 2, '2023-07-11', 120.50),
(4, 3, '2023-07-15', 25.75);

SELECT c.customer_id, c.customer_name, SUM(c.visit_count) AS total_visits
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name;

Нелегко избежать этих типов ошибок, особенно когда они происходят, они скрыты. Но достаточно знать, что они существуют, и перепроверить результаты или применить агрегацию к исходной таблице, когда объединение не требуется для вычислений.

Некоторые инструменты BI, такие как Google Looker, позаботятся об этих ошибках за вас, применяя так называемые симметричные агрегаты, но в противном случае вам придется справляться с ними самостоятельно.