2010-11-12 3 views
5

У меня есть две таблицы A и B. A является родителем B. Я пытаюсь найти все As, у которых нет определенного B в качестве ребенка. Обычно я хотел бы сделатьSQL Выбор строк и исключение детей

SELECT A.id FROM A 
    WHERE A.id NOT IN 
     (SELECT B.AId FROM B WHERE B.someFK = foo);

Однако по причинам производительности Увлекаюсь не использовать внутренний выбор. Я пытался что-то вроде:

SELECT A.id FROM A 
    LEFT JOIN B ON (A.id = B.AId) 
    WHERE B.someFK != foo OR B.someFK IS NULL

Проблема заключается в следующем возвращается, как имеющие более одного ребенка, независимо от того, если они имеют указанный B.

EDIT: Изменено B.id к B. someFK

+0

Упс, не думал, что это будет иметь значение для примера, но B.id должен быть B.someFK. Это означает, что As может использовать исключение foo. – Jim

+0

, вы должны, вероятно, отредактировать это непосредственно в вопросе, чтобы он был более заметен для новых читателей. – DMA57361

+0

Вы новичок в StackOverflow. Пожалуйста, примите ответ, если он решит вашу проблему. – Falcon

ответ

1

Я бы с существующей оговорки, так как это было сделано для такой цели:

SELECT A.id FROM A WHERE NOT EXISTS (SELECT 1 FROM B WHERE B.id = foo and B.AId=a.id); 

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

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

0

Попробуйте использовать ограничение MAX на родительской таблице. Я не использовал MySql в какое-то время, но это должно дать вам идею

1

Ваш LEFT JOIN будет возвращать одну строку для каждого A - B ссылки (или одной строки в течение A, без ссылки на B), а затем удаляет ссылки, которые не в состоянии соответствовать вашим критериям - оставляя позади любой другой линии связи, что конкретный A имеет в B, что не то, что вы хотите.

Однако, я думаю, необходим внутренний выбор.
Но, может быть, попробовать EXISTS вместо:

SELECT A.id 
FROM A 
WHERE NOT EXISTS (SELECT * FROM B WHERE B.AId = A.id AND B.someFK = foo); 
0

Попробуйте

SELECT DISTINCT A.id FROM A 
LEFT JOIN B ON (A.id = B.AId) 
WHERE B.id != foo OR B.id IS NULL 
+0

по производительности плохой выбор, с объединением и отличным. – Falcon

0

Вы должны поместить все критерии в LEFT JOIN.

Что касается повторяющихся строк, просто ОТКЛЮЧИТЕ его.

SELECT DISTINCT A.id 
FROM A 
LEFT JOIN B 
ON A.id = B.AId AND B.someFK = "foo" 
WHERE B.AId IS NULL 
Смежные вопросы