SQL - сопоставление записей из одной таблицы в другую на основе нескольких столбцов - PullRequest
1 голос
/ 29 сентября 2011

У меня есть две таблицы:
табло

   +-------+-------+-------+-------+  
   | name  |hobby1 |hobby2 |hobby3 |  
   +-------+-------+-------+-------+   
   | kris  | ball  | swim  | dance |  
   | james | eat   | sing  | sleep |  
   | amy   | swim  | eat   | watch |  
   +-------+-------+-------+-------+

tblavailable_hobby

+----------------+ 
| available_hobby|
+----------------+
| ball           | 
| dance          | 
| swim           | 
| eat            | 
| watch          | 
+----------------+ 

SQL-запрос должен взять все столбцы в tblhobby и сопоставить его с tblavailable_hobby. Если все хобби совпадают с available_hobby, то человек выбран

запрос должен выдать

+--------+ 
| name   |
+--------+
| kris   | 
| amy    | 
+--------+

Пожалуйста, помогите

Спасибо за ответы. Я унаследовал эту базу данных и в настоящее время не могу ее нормализовать. Однако я хотел бы добавить еще один поворот в вопросе. Предположим:

   +-------+-------+-------+-------+  
   | name  |hobby1 |hobby2 |hobby3 |  
   +-------+-------+-------+-------+   
   | kris  | ball  | swim  | dance |  
   | james | eat   | sing  | sleep |  
   | amy   | swim  | eat   | watch | 
   | brad  | ball  |       | dance |
   +-------+-------+-------+-------+

Я бы хотел получить

+--------+ 
| name   |
+--------+
| kris   | 
| amy    | 
| brad   |
+--------+

как мне с этим справиться?

Ответы [ 6 ]

3 голосов
/ 29 сентября 2011

Плохой дизайн БД, но при условии, что вам придется с этим жить:

SELECT h.name
    FROM tblhobby h
        INNER JOIN tblavailable_hobby ah1
            ON h.hobby1 = ah1.available_hobby
        INNER JOIN tblavailable_hobby ah2
            ON h.hobby2 = ah2.available_hobby
        INNER JOIN tblavailable_hobby ah3
            ON h.hobby3 = ah3.available_hobby

РЕДАКТИРОВАТЬ : Ответ на поворот, предложенный в комментариях ниже.

SELECT h.name
    FROM tblhobby h
        LEFT JOIN tblavailable_hobby ah1
            ON h.hobby1 = ah1.available_hobby
        LEFT JOIN tblavailable_hobby ah2
            ON h.hobby2 = ah2.available_hobby
        LEFT JOIN tblavailable_hobby ah3
            ON h.hobby3 = ah3.available_hobby
    WHERE (h.hobby1 IS NULL OR ah1.available_hobby IS NOT NULL)
        AND (h.hobby2 IS NULL OR ah2.available_hobby IS NOT NULL)
        AND (h.hobby3 IS NULL OR ah3.available_hobby IS NOT NULL)
1 голос
/ 30 сентября 2011

Вы можете использовать запрос, чтобы преобразовать вашу существующую таблицу в «виртуальную таблицу», с которой, мне кажется, будет проще работать. Сохраните этот оператор SQL как qryHobbiesUnion.

SELECT [name] AS person, hobby1 AS hobby
FROM tblhobby
WHERE (((hobby1) Is Not Null))
UNION
SELECT [name], hobby2
FROM tblhobby
WHERE (((hobby2) Is Not Null))
UNION
SELECT [name], hobby3
FROM tblhobby
WHERE (((hobby3) Is Not Null));

Я заключил «имя» в квадратные скобки, потому что это зарезервированное слово . И я использовал псевдоним [name] как лицо, чтобы избежать проблем с квадратными скобками при использовании qryHobbiesUnion в подзапросе позже.

Я предполагал, что любые "пустые" значения для хобби будут нулевыми. Если пробелы также могут быть пустыми строками (""), измените предложения WHERE на такой шаблон:

WHERE Len(hobby1 & "") > 0

После того, как вы определите, какая версия предложения WHERE возвращает правильные строки, сохраните запрос и используйте его в другом запросе.

SELECT sub.person
FROM
    [SELECT qh.person, qh.hobby, ah.available_hobby
    FROM
        qryHobbiesUnion AS qh
        LEFT JOIN tblavailable_hobby AS ah
        ON qh.hobby = ah.available_hobby
        ]. AS sub
GROUP BY sub.person
HAVING (((Count(sub.hobby))=Count([sub].[available_hobby])));

Используя ваш второй набор образцов данных, этот запрос возвращает имена 3 человек, которых вы хотели: amy; Бреда; и крис.

Если бы tblhobby содержал строку для человека с пустыми полями хобби, этот запрос не включал бы имя этого человека. Это имеет смысл для меня, потому что, похоже, ваше намерение состоит в том, чтобы определить людей, чей выбор хобби совпадает в tblavailable_hobby. Так что у человека без выбора хобби нет совпадений. Если вы хотите другое поведение, это, вероятно, станет еще хуже. : -)

1 голос
/ 29 сентября 2011

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

Table: Person
Id    Name
-------------
1     Kris
2     James
3     Amy

table: PersonHobby (Join table)
PersonId HobbyId
----------------
1        1 -- Kris likes to ball
1        2 --   "           dance
1        3 --   "           swim
2        4  -- James likes to eat

Table: Hobby
Id   Name
--------------
1    Ball
2    Dance
3    Swim
4    Eat
etc.

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

Затем вы запрашиваете данные следующим образом:

SELECT * 
FROM Person p 
JOIN PersonHobby AS ph on p.Id = ph.PersonId
JOIN Hobby       AS h  on h.Id = ph.HobbyId

WHERE ... -- filter as you need to

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

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

0 голосов
/ 29 сентября 2011

Заимствование у Джо ответ :

SELECT h.name
    FROM tblhobby h
        LEFT JOIN tblavailable_hobby ah1
            ON h.hobby1 = ah1.available_hobby
        LEFT JOIN tblavailable_hobby ah2
            ON h.hobby2 = ah2.available_hobby
        LEFT JOIN tblavailable_hobby ah3
            ON h.hobby3 = ah3.available_hobby
WHERE (h.hobby1 IS NULL OR ah1.available_hobby IS NOT NULL)
    AND (h.hobby2 IS NULL OR ah2.available_hobby IS NOT NULL)
    AND (h.hobby3 IS NULL OR ah3.available_hobby IS NOT NULL)

ответ ypercube может быть расширен аналогичным образом.

0 голосов
/ 29 сентября 2011
SELECT name
FROM tblhobby AS h
WHERE EXISTS
        ( SELECT *
          FROM tblavailable_hobby AS ah1
          WHERE h.hobby1 = ah1.available_hobby
        )
  AND EXISTS
        ( SELECT *
          FROM tblavailable_hobby AS ah2
          WHERE h.hobby2 = ah2.available_hobby
        )
  AND EXISTS
        ( SELECT *
          FROM tblavailable_hobby AS ah3
          WHERE h.hobby3 = ah3.available_hobby
        )
0 голосов
/ 29 сентября 2011

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

Ваши таблицы должны выглядеть следующим образом

ТАБЛИЦА: Люди КОЛОННЫ: PID (INT, Primary Key), NAME

ТАБЛИЦА: Хобби КОЛОННЫ: HID (INT, Primary Key), Хобби

ТАБЛИЦА: PeoplesHobbies КОЛОННЫ: ID, PID, HID

ПОТОМ ваш запрос будет выглядеть примерно так

select * from people `p` inner join PeoplesHobbies `ph` on p.PID = ph.PID inner join on Hobbies `h` on ph.HID = h.HID where p.NAME = 'JOHN'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...