ПЕРЕСЕЧЕНИЕ в MySQL

У меня есть две таблицы, записи и данные. записи имеют несколько полей (имя, фамилия и т. д.). Каждое из этих полей является внешним ключом для таблицы данных, в которой хранится фактическое значение. Мне нужно выполнить поиск по нескольким полям записи.

Ниже приведен пример запроса с использованием INTERSECT, но мне нужен такой, который работает в MySQL.

SELECT records.id FROM records, data WHERE data.id = records.firstname AND data.value = "john"
INTERSECT
SELECT records.id FROM records, data WHERE data.id = records.lastname AND data.value = "smith"

Спасибо за любую помощь.


person Community    schedule 19.02.2010    source источник
comment
Взгляните на это: ужас кодирования. com/блог/2007/10/   -  person Mike Atlas    schedule 20.02.2010
comment
@Mike Atlas: это не имеет ничего общего с соединениями. Это можно решить таким образом, но запись в блоге Джеффа не актуальна.   -  person Aaronaught    schedule 20.02.2010
comment
Да, это связано с соединениями и актуально. Он объясняет, какое соединение SQL эквивалентно пересечению двух данных (внутреннее соединение). Исходя из этого, Джереми должен понять стандартный синтаксис SQL для пересечения. Я разместил это только как комментарий, так как другие дали точный ответ ниже.   -  person Mike Atlas    schedule 20.02.2010
comment
Проверьте ответ @Djebel по адресу stackoverflow.com/questions/2621382/   -  person Vikas Khunteta    schedule 23.05.2014


Ответы (7)


Вы можете использовать внутреннее соединение для фильтрации строк, которые имеют совпадающую строку в другой таблице:

SELECT DISTINCT records.id 
FROM records
INNER JOIN data d1 on d1.id = records.firstname AND data.value = "john"
INNER JOIN data d2 on d2.id = records.lastname AND data.value = "smith"

Одной из многих других альтернатив является предложение in:

SELECT DISTINCT records.id 
FROM records
WHERE records.firstname IN (
    select id from data where value = 'john'
) AND records.lastname IN (
    select id from data where value = 'smith'
)
person Andomar    schedule 19.02.2010
comment
Рассмотрим случай, когда запись (имя, фамилия) имеет только (a, b), а данные (имя, фамилия) имеют только (a, c) и (d, b). - person Makmeksum; 28.06.2018

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

Все, что вы делаете, это «ОБЪЕДИНЯЙТЕ ВСЕ» каждый из запросов, которые вы хотите пересечь, и смотрите, какие из них вы получили каждый раз.

SELECT * From (

    (Select data1.* From data1 Inner Join data2 on data1.id=data2.id where data2.something=true)
    Union All
    (Select data1.* From data1 Inner Join data3 on data1.id=data3.id where data3.something=false)

) As tbl GROUP BY tbl.ID HAVING COUNT(*)=2 

Поэтому, если мы получим одну и ту же запись в обоих запросах, ее счетчик будет равен 2, и окончательный циклический запрос будет включать ее.

person Enigma Plus    schedule 15.05.2012

Вместо этого используйте соединения:

SELECT records.id
FROM records
JOIN data AS D1 ON records.firstname = D1.id
JOIN data AS D2 ON records.lastname = D2.id
WHERE D1.value = 'john' and D2.value = 'smith'

Вот некоторые тестовые данные:

CREATE TABLE records (id INT NOT NULL, firstname INT NOT NULL, lastname INT NOT NULL);
INSERT INTO records (id, firstname, lastname) VALUES
(1, 1, 1),
(2, 1, 2),
(3, 2, 1),
(4, 2, 2);

CREATE TABLE data (id INT NOT NULL, value NVARCHAR(100) NOT NULL);
INSERT INTO data (id, value) VALUES
(1, 'john'),
(2, 'smith');

Ожидаемый результат:

2

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

person Mark Byers    schedule 19.02.2010

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

SELECT * FROM
( SELECT records.id FROM records, data WHERE data.id = records.firstname AND data.value = "john" ) x1
NATURAL JOIN
( SELECT records.id FROM records, data WHERE data.id = records.lastname AND data.value = "smith" ) x2
person donatJ    schedule 21.09.2020

Общей заменой INTERSECT в MYSQL является внутреннее соединение:

SELECT DISTINCT * FROM 
(SELECT f1, f2, f3... FROM table1 WHERE f1>0)
INNER JOIN
(SELECT f1, f2, f3... FROM table2 WHERE f1>0)
USING(primary_key)

Или конкретно для вашего случая:

SELECT DISTINCT * FROM 
(SELECT records.id FROM records, data WHERE data.id = records.firstname AND data.value = "john") query1
INNER JOIN
(SELECT records.id FROM records, data WHERE data.id = records.lastname AND data.value = "smith") query2
USING (id)
person Will Hay    schedule 08.11.2017

SELECT t.id FROM table t WHERE NOT EXISTS (SELECT t2.id, FROM table2 t2 WHERE t2.id = t1.id)

https://dev.mysql.com/doc/refman/5.7/en/exists-and-not-exists-subqueries.html

person Nazar Maksymchuk    schedule 03.04.2018

Поскольку Mysql не поддерживает INTERSECT, у вас может быть 2 альтернативы: внутреннее соединение и in. Это решение с in:

SELECT records.id FROM records, data 
WHERE data.id = records.firstname AND data.value = "john"
    AND records.id in (SELECT records.id FROM records, data 
    WHERE data.id = records.lastname AND data.value = "smith);
person vinhNguyen.bmt    schedule 15.07.2019