SQL - 根据多个列将记录从一个表匹配到另一个表

时间:2011-09-29 18:52:29

标签: mysql sql ms-access

我有两张桌子:
tblhobby

   +-------+-------+-------+-------+  
   | 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 个答案:

答案 0 :(得分:3)

糟糕的数据库设计,但是,假设你必须忍受它:

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 :(得分:1)

我知道这并没有直接回答你的问题,而其他人则指出你的桌面设计存在问题。应该是这样的:

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.

此设计使用Join or Junction table的概念,允许您在数据之间建立多对多关系。在这种情况下,人和爱好。

然后您可以像这样查询数据:

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

我的示例中的PersonH​​obbies表采用了人员表和爱好表,并启用了人与爱好之间的关系。我知道这对你来说可能看起来更多...额外的表格,额外的列。但请相信我们,这种设计将使您的生活在不久的将来变得更加简单。实际上,通过尝试找出一个比当前数据库更简单的查询,您已经感受到了设计的痛苦。

我想生成一个符合您要求的WHERE过滤器,但我不太明白您的追求。你能解释一下吗?

答案 2 :(得分:1)

您可以使用查询将现有表格转换为“虚拟表格”,我认为应该更容易使用。将此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”,因为它是reserved word。当我在子查询中使用qryHobbiesUnion时,我将[name]别名为人,以避免方括号出现问题。

我认为爱好的任何“空”值都是空的。如果空格也可以是空字符串(“”),请将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中所有人都有匹配的人。所以没有选择爱好的人没有比赛。如果你想要不同的行为,这可能会变得更加丑陋。 : - )

答案 3 :(得分:0)

您真的必须了解有关关系数据库的更多信息。你的设计不好。你应该有一张桌子与人和一个有兴趣爱好的桌子。然后你应该有一个表,通过ID将这两个表联系起来。

你的桌子应该看起来像这样

表:人 COLUMNS:PID(INT,主键),NAME

表:爱好 专栏:HID(INT,主键),爱好

表:人民爱好 COLUMNS: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'

答案 4 :(得分:0)

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
        )

答案 5 :(得分:0)

借用Joe的answer

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的answer可以类似地扩展。