Объясните принцип работы `INNER JOIN`. Приведите пример.

Ответ

INNER JOIN (или просто JOIN) — это операция в SQL, которая возвращает записи, имеющие совпадающие значения в обеих таблицах. Если для строки из одной таблицы не найдено совпадения в другой, эта строка не включается в результирующий набор.

Представьте две таблицы: users (пользователи) и orders (заказы).

SELECT users.name, orders.product
FROM users
INNER JOIN orders ON users.id = orders.user_id;

Этот запрос вернет список имен пользователей вместе с продуктами, которые они заказали. Пользователи, не сделавшие ни одного заказа, в результат не попадут.

Пример использования в Go с database/sql:

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq" // Пример с драйвером PostgreSQL
)

func main() {
    // db - это ваш экземпляр *sql.DB
    rows, err := db.Query(`
        SELECT u.name, o.product
        FROM users AS u
        INNER JOIN orders AS o ON u.id = o.user_id`)
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    for rows.Next() {
        var name, product string
        if err := rows.Scan(&name, &product); err != nil {
            log.Println(err)
            continue
        }
        fmt.Printf("Пользователь: %s, Продукт: %sn", name, product)
    }

    if err := rows.Err(); err != nil {
        log.Fatal(err)
    }
}

Ключевые особенности:

  • Только совпадения: Возвращает только пересекающиеся данные из обеих таблиц.
  • Симметричность: A INNER JOIN B эквивалентно B INNER JOIN A (хотя порядок столбцов в результате может отличаться).
  • Производительность: Эффективность запроса сильно зависит от наличия индексов на соединяемых полях (users.id и orders.user_id).
  • Стандарт: Является наиболее часто используемым типом соединения.

Ответ 18+ 🔞

Давай разжую тебе этот INNER JOIN, чтобы ты не только понял, а прочувствовал его всей своей хитрой жопой.

Представь, что у тебя есть два списка. Первый — это твои кореша (users), а второй — заказы в пивнушке (orders). И вот ты такой подходишь и спрашиваешь: «Ну-ка, покажи мне, кто из этих пидоров что заказал, чтобы я знал, кому потом предъявить за недопитое».

INNER JOIN — это как раз тот самый занудный бухгалтер, который сядет и скрепит эти два списка ТОЛЬКО там, где есть совпадение. Нет заказа в списке orders на какого-то чувака из users? Ну и хуй с ним, в отчёт не попал, как будто его и не было. Сиди, смотри, как другие пьют.

Вот тебе код, который этот цирк и организует:

SELECT users.name, orders.product
FROM users
INNER JOIN orders ON users.id = orders.user_id;

Перевод на русский: «Дайте мне имена уёбков и названия их заказов, но только тех, у кого в ведомости на заказы (orders) значится их личный номер (user_id). Остальные, кто просто пришёл потусить, меня не ебут».

А теперь, блядь, пример на Go, чтобы ты не просто пялился в экран:

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq" // Допустим, база — постгрес, но похуй, принцип везде один
)

func main() {
    // db - это твой открытый коннект к базе, надеюсь, ты его не проёб
    rows, err := db.Query(`
        SELECT u.name, o.product
        FROM users AS u
        INNER JOIN orders AS o ON u.id = o.user_id`)
    if err != nil {
        log.Fatal(err) // Если запрос сломался — всё, пиздец, иди разбирайся
    }
    defer rows.Close() // Закрыть потом, а то память потечёт, как дешёвое пиво

    for rows.Next() {
        var name, product string
        if err := rows.Scan(&name, &product); err != nil {
            log.Println(err) // Один косячный ряд — не повод всю операцию нахуй посылать
            continue
        }
        fmt.Printf("Вот этот тип: %s, заказал вот это: %sn", name, product)
    }

    if err := rows.Err(); err != nil {
        log.Fatal(err) // А вот если ошибка в самом процессе чтения — это уже серьёзно
    }
}

Что тут, сука, важно запомнить:

  • Только пары: Вернёт только тех, кто и в списке гостей, и в списке заказов. Пришёл, нажрался в хлам, но ничего не купил? Для INNER JOIN ты — пустое место.
  • Порядок — не приговор: users JOIN orders или orders JOIN users — результат по смыслу будет один и тот же, просто столбцы могут в выводе поменяться местами, как носки после пьянки.
  • Индексы — это всё: Если на полях id и user_id нет индексов, запрос будет работать так медленно, что ты за это время успеешь прочитать всего «Муму» от начала до конца, включая сцену утопления. Серьёзно, добавь индексы, не будь мудаком.
  • Хлеб и масло: Это самый обычный, стандартный и часто используемый джоин. Если не указано иное, то JOIN — это всегда INNER JOIN. Его и используют в 80% случаев, когда нужно просто связать данные по логической связке.

Вот и вся магия. Не совпадения — нахуй. Совпадения — в отчёт. Всё просто, как три копейки.