Имате две LEFT JOINS :
- Първото ляво присъединяване може да се присъедини към няколко реда от
solved. Кажете, 'jane' и 'luke' са решили задачата. - Второто ляво присъединяване може да се присъедини само към потребители на име „luke“ („luke“ в условието за присъединяване!).
Все пак получаватеи двете редове, 'jane' просто не се показва, условието за присъединяване я филтрира, но LEFT JOIN все пак запазва реда в резултата и добавя NULL стойности.
Можете да постигнете това, което търсите, като използвате скоби и [INNER] JOIN вместо LEFT JOIN между solved и users . Ръководството:
Използвайте скоби, ако е необходимо, за да определите реда на влагане. При липса на скоби
JOINs гнездо отляво надясно.
SELECT c.name AS cat_name, t.name AS task_name, u.name AS user_name
FROM task t
JOIN category c ON cat.id = t.category_id
LEFT JOIN
(solved s JOIN users u ON u.id = s.user_id AND u.name = 'luke') ON s.task_id = t.id
ORDER BY 1, 2, 3;
-
Използване на име на таблица
usersвместо запазената дума.user -
Ако приемем, че
users.nameсе дефинирауникален или можете да имате няколко потребители с име 'luke'. -
Ако
(task.id, users.id)вsolvedе дефиниранUNIQUEилиPRIMARY KEY, нямате нужда отDISTINCTизобщо.
Получената заявка е не само правилна, но и по-бърза.
SqlAlchemy версия на горната заявка: (донесено от @van)
Това предполага, че Category , Task и User са картографирани класове, докато solved е екземпляр на Table (само асоциативна таблица, както е показано в примера с код Много към много):
user_name = 'luke'
q = (session.query(Category.name, Task.name, User.name)
.select_from(Task)
.join(Category)
.outerjoin(
join(solved, User,
(solved.c.user_id == User.id) & (User.name == user_name),
))
.order_by(Category.name, Task.name, User.name)
)