Имате две LEFT JOINS
:
- Първото ляво присъединяване може да се присъедини към няколко реда от
solved
. Кажете, 'jane' и 'luke' са решили задачата. - Второто ляво присъединяване може да се присъедини само към потребители на име „luke“ („luke“ в условието за присъединяване!).
Все пак получаватеи двете редове, 'jane' просто не се показва, условието за присъединяване я филтрира, но LEFT JOIN
все пак запазва реда в резултата и добавя NULL стойности.
Можете да постигнете това, което търсите, като използвате скоби и [INNER] JOIN
вместо LEFT JOIN
между solved
и users
. Ръководството:
Използвайте скоби, ако е необходимо, за да определите реда на влагане. При липса на скоби
JOIN
s гнездо отляво надясно.
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)
)