Как выбрать строки без соответствующей записи в другой таблице?

Я делаю некоторые работы по обслуживанию приложения базы данных, и я обнаружил, что радость радостей, хотя значения из одной таблицы используются в стиле внешних ключей, ограничений на внешние ключи для таблиц нет.

Я пытаюсь добавить ограничения FK для этих столбцов, но я нахожу это, потому что в таблицах из предыдущих ошибок, которые были наивно исправлены, уже существует целая загрузка плохих данных, мне нужно найти строки, которые не совпадают с другой таблицей, а затем удаляют их.

Я нашел несколько примеров такого рода запросов в Интернете, но все они, кажется, приводят примеры, а не объяснения, и я не понимаю, почему они работают.

Может кто-нибудь объяснить мне, как построить запрос, который возвращает все строки без совпадений в другой таблице, и что он делает, чтобы я мог самостоятельно выполнять эти запросы, а не прибегать к SO для каждой таблицы в этом беспорядок, который не имеет ограничений FK?

Ответ 1

Вот простой запрос:

SELECT t1.ID
FROM Table1 t1
    LEFT JOIN Table2 t2 ON t1.ID = t2.ID
WHERE t2.ID IS NULL

Ключевыми моментами являются:

  • LEFT JOIN; это вернет ВСЕ строки из Table1, независимо от того, есть ли соответствующая строка в Table2.

  • Предложение WHERE t2.ID IS NULL; это ограничит результаты, возвращаемые только тем строкам, где идентификатор, возвращаемый из Table2, равен нулю - другими словами, в Table2 есть запись NO для этого идентификатора из Table1. Table2.ID будет возвращен как NULL для всех записей из Table1, где идентификатор не сопоставляется в Table2.

Ответ 2

Я бы использовал выражение EXISTS, так как оно более мощное, вы можете точнее выбрать строки, которые хотите присоединиться, в случае из LEFT JOIN вам нужно взять все, что в объединенной таблице. Его эффективность, вероятно, такая же, как в случае LEFT JOIN с нулевым тестом.

SELECT t1.ID
FROM Table1 t1
WHERE NOT EXISTS (SELECT t2.ID FROM Table2 t2 WHERE t1.ID = t2.ID)

Ответ 3

SELECT id FROM table1 WHERE foreign_key_id_column NOT IN (SELECT id FROM table2)

В таблице 1 есть столбец, к которому вы хотите добавить ограничение внешнего ключа, но значения в foreign_key_id_column не все совпадают с id в таблице 2.

  1. Первоначальный выбор перечисляет id из таблицы1. Это будут строки, которые мы хотим удалить.
  2. Предложение NOT IN в операторе where ограничивает запрос только теми строками, в которых значение foreign_key_id_column отсутствует в списке id таблицы 2.
  3. Оператор SELECT в круглых скобках получит список всех id которые находятся в таблице 2.

Ответ 4

Где T2 - таблица, к которой вы добавляете ограничение:

SELECT *
FROM T2
WHERE constrained_field NOT
IN (
    SELECT DISTINCT t.constrained_field
    FROM T2 
    INNER JOIN T1 t
    USING ( constrained_field )
)

И удалите результаты.

Ответ 5

Пусть у нас есть следующие 2 таблицы (зарплата и работник) enter image description here

Теперь я хочу те записи из таблицы сотрудников, которых нет в зарплате. Мы можем сделать это тремя способами:

  1. Использование внутреннего соединения
select * from employee
where id not in(select e.id from employee e inner join salary s on e.id=s.id)

enter image description here

  1. Использование левого внешнего соединения
select * from employee e 
left outer join salary s on e.id=s.id  where s.id is null

enter image description here

  1. Использование полного соединения
select * from employee e
full outer join salary s on e.id=s.id where e.id not in(select id from salary)

enter image description here

Ответ 6

От подобного вопроса здесь MySQL Внутренний Запрос Соединения, чтобы Получить Записи, Не Представленные в Другой Таблице, я получил это, чтобы работать

SELECT * FROM bigtable 
LEFT JOIN smalltable ON bigtable.id = smalltable.id 
WHERE smalltable.id IS NULL

smalltable - это место, где у вас отсутствуют записи, bigtable - это место, где у вас есть все записи. В списке запросов перечислены все записи, которые не существуют в smalltable но существуют в bigtable. Вы можете заменить id любым другим подходящим критерием.

Ответ 7

Я не знаю, какой из них оптимизирован (по сравнению с @AdaTheDev), но этот, кажется, быстрее, когда я использую (по крайней мере, для меня)

SELECT id FROM table_1 EXCEPT SELECT DISTINCT (table1_id) table1_id FROM table_2

Если вы хотите получить любой другой конкретный атрибут, вы можете использовать:

SELECT COUNT(*) FROM table_1 where id in (SELECT id FROM table_1 EXCEPT SELECT DISTINCT (table1_id) table1_id FROM table_2);

Ответ 8

Вы можете выбрать Просмотры, как показано ниже:

CREATE VIEW AuthorizedUserProjectView AS select t1.username as username, t1.email as useremail, p.id as projectid, 
(select m.role from userproject m where m.projectid = p.id and m.userid = t1.id) as role 
FROM authorizeduser as t1, project as p

а затем поработайте над представлением для выбора или обновления:

select * from AuthorizedUserProjectView where projectid = 49

что дает результат, как показано на рисунке ниже, то есть для несоответствующего столбца был заполнен нуль.

[Result of select on the view][1]

Ответ 9

Вы можете сделать что-то вроде этого

   SELECT IFNULL('price'.'fPrice',100) as fPrice,product.ProductId,ProductName 
          FROM 'products' left join 'price' ON 
          price.ProductId=product.ProductId AND (GeoFancingId=1 OR GeoFancingId 
          IS NULL) WHERE Status="Active" AND Delete="No"

Ответ 10

Как выбрать строки без соответствующей записи в таблице "Оба"?

    select * from [dbo].[EmppDetails] e
     right join [Employee].[Gender] d on e.Gid=d.Gid
    where e.Gid is Null

    union 
    select * from [dbo].[EmppDetails] e
     left join [Employee].[Gender] d on e.Gid=d.Gid
    where d.Gid is Null