MySQL объединяет таблицы различной структуры - PullRequest
0 голосов
/ 17 ноября 2018

У меня проблемы с получением результата или с правильным результатом в следующей задаче - http://www.sqlfiddle.com/#!9/696ed2/4

Общая цель - перечислить все транзакции пользователей, которые связаны друг с другом как «Клиенты». Поэтому, если Джон смотрит на свою приборную панель, он увидит, какие книги арендовала Алиса (его клиент) (включая название книги), и какие книги были проданы (он не сможет увидеть название этой книги).

Когда две родительские таблицы объединяются в родительскую таблицу, где для каждой зависимой таблицы установлен флаг 'active' для каждой строки, я не могу получить только активные строки.

# USERS 
CREATE TABLE `users` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `active` boolean DEFAULT NULL
);

INSERT INTO `users` (`id`, `name`, `active`) VALUES
(1, 'John', 1),
(2, 'Alice', 1),
(3, 'Jess', 1),
(4, 'Bob', 1);

# BOOKS 
CREATE TABLE `books` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `active` boolean DEFAULT NULL
);

INSERT INTO `books` (`id`, `name`, `active`) VALUES
(1, 'On the Road', 1),
(2, 'Neuromancer', 0),
(3, 'Modern History', 1),
(4, 'Red Mars', 1);

# TRANSACTIONS
CREATE TABLE `transactions` (
  `id` int(11) NOT NULL,
  `user_1_id` int(11) NOT NULL,
  `user_2_id` int(11) DEFAULT NULL,
  `book_id` int(11) DEFAULT NULL,
  `timestamp` varchar(20) DEFAULT NULL,
  `type` enum('Rent', 'Sold') NOT NULL
);

INSERT INTO `transactions` (`id`, `user_1_id`, `user_2_id`, `book_id`,     `timestamp`, `type`) VALUES
(1, 1, 2, 1, '1465238591', 'Rent'),
(2, 2, 1, 2, '1465238592', 'Rent'),
(3, 2, 3, 3, '1465238593', 'Rent'),
(4, 3, 4, NULL, '1465238594', 'Sold'),
(5, 2, 3, NULL, '1465238595', 'Sold'),
(6, 3, 4, NULL, '1465238596', 'Sold'),
(7, 2, 2, 4, '1465238597', 'Rent'),
(8, 1, 3, 1, '1465238598', 'Rent'),
(9, 2, 4, 2, '1465238598', 'Rent');

# RELATIONSHIPS
CREATE TABLE `relationships` (
  `id` int(11) NOT NULL,
  `user_1_id` int(11) DEFAULT NULL,
  `user_2_id` int(11) NOT NULL,
  `type` enum('Customer', 'Supplier') NOT NULL
);

INSERT INTO `relationships` (`id`, `user_1_id`, `user_2_id`, `type`) VALUES
(1, 1, 2, 'Customer'),
(2, 2, 1, 'Customer'),
(3, 2, 4, 'Customer'),
(3, 1, 4, 'Supplier'),
(3, 3, 1, 'Customer');

Запрос :

SELECT DISTINCT 
  t.id,
  t.type,
  t.timestamp,
  u1.name as user_1_name,
  u2.name as user_2_name,
  b.name as book_name
  FROM transactions t

  LEFT JOIN relationships r ON (r.user_1_id = 1 AND r.type = 'Customer')
  LEFT JOIN books b ON (b.id = t.book_id AND b.active)
  LEFT JOIN users u1 ON (u1.id = t.user_1_id) # AND u1.active
  LEFT JOIN users u2 ON (u2.id = t.user_2_id) # AND u2.active

  WHERE (r.user_2_id = t.user_1_id OR t.user_2_id = 1 AND t.user_1_id != 1)
    # AND b.active AND u1.active AND u2.active

[Результат]

| id | type |  timestamp | user_1_name | user_2_name |      book_name |
|----|------|------------|-------------|-------------|----------------|
|  3 | Rent | 1465238593 |       Alice |        Jess | Modern History |
|  2 | Rent | 1465238592 |       Alice |        John |         (null) | <<< Should not be here
|  7 | Rent | 1465238597 |       Alice |       Alice |       Red Mars |
|  5 | Sold | 1465238595 |       Alice |        Jess |         (null) | <<< Correct
|  9 | Rent | 1465238598 |       Alice |         Bob |         (null) | <<< Should not be here

В приведенном выше результате проблема в том, что книга Neuromancer имеет флаг 'active', установленный в 0, поэтому не должен появляться в результате. Я играл с размещением AND b.active в разных местах, но результаты всегда неверны. (См. http://www.sqlfiddle.com/#!9/696ed2/5)

Глядя на беспорядок выше, я даже не уверен, что мой подход хорош, любые предложения приветствуются.

1 Ответ

0 голосов
/ 17 ноября 2018

Как отметил Д.Смания в комментариях, вы должны убедиться, что b.active либо 1, либо NULL, но в зависимости от вашего условия LEFT JOIN b.active всегда будет 1, поэтому вам нужно выполнитьприсоединяйтесь только к id и полагайтесь на условие WHERE для сравнения.Это должно привести к результатам, которые вы запрашивали:

SELECT DISTINCT 
    t.id,
    t.type,
    t.timestamp,
    u1.name AS user_1_name,
    u2.name AS user_2_name,
    b.name AS book_name
FROM transactions t
    LEFT JOIN relationships r ON (r.user_1_id = 1 AND r.type = 'Customer')
    LEFT JOIN books b ON (b.id = t.book_id)
    LEFT JOIN users u1 ON (u1.id = t.user_1_id)
    LEFT JOIN users u2 ON (u2.id = t.user_2_id)
WHERE (r.user_2_id = t.user_1_id OR t.user_2_id = 1 AND t.user_1_id != 1)
    AND (b.active OR b.active IS NULL)
    AND u1.active AND u2.active

SQL Fiddle

Одно замечание - в вашем первом WHERE состоянии мне не ясно, имеете ли вы в виду:

(r.user_2_id = t.user_1_id OR (t.user_2_id = 1 AND t.user_1_id != 1))

или

((r.user_2_id = t.user_1_id OR t.user_2_id = 1) AND t.user_1_id != 1)

Всегда лучше быть явным с вашей логической группировкой, когда у вас есть смежные AND и OR условия.

...