【问题标题】:JOINS between 7 tables7个表之间的联接
【发布时间】:2015-01-19 18:39:45
【问题描述】:

我在上一篇文章中得到了很多帮助,这让我更好地理解了数据库模型。我已经阅读了关于 JOINS 的教程和解释,但我似乎无法弄清楚,特此我的数据库模型;

    ***Person***        ***DrivingLicense***  ***DrivingLicenseLicenseTypes***
ID                  ID                    ID
Name                ExpiryDate            DrivingLicense_ID
                    Person_ID             LicenseType_ID

***LicenseTypes***  ***LicenseTypeVehicleTypes*** ***VehicleTypes***    ***Vehicles***
ID                  ID                            ID                    ID
LicenseType         LicenseType_ID                VehicleType           Make
                    VehicleType_ID                                      Model
                                                                        VehicleType_ID
                                                                        Person_ID

Person: (1, 'Person1'), (2, 'Person2');
DrivingLicense: (1, '2015-01-01', 1), (2, '2015-10-01', 2);
VehicleTypes: (1, 'Car'), (2, 'Motorbike');
LicenseTypes: (1, 'Car'), (2, 'Motorbike');
Vehicles: (1, 'Ford', 'Focus', 1), (2, 'Chevrolet', 'Caprice', 1), (3, 'Ducati', 'Multistrada', 2);
LicenseTypeVehicleTypes: (1, 1, 1), (1, 1, 2), (1, 2, 2);
DrivingLicenseLicenseTypes: (1, 1, 1), (1, 2, 2);

现在我想运行一个 SELECT 查询,基本上我想链接表:

PersonID.ID -> DrivingLicense.ID
DLLT.DrivingLicense_ID -> DrivingLicense.ID
DLLT.LicenseType_ID -> LicenseTypes.ID
LTVT.LicenseType_ID -> LicenseTypes.ID
LTVT.VehicleType_ID -> VehicleTypes.ID
Vehicles.Type_ID -> Vehicletypes.ID

我试过了:

SELECT * FROM Person
INNER JOIN DrivingLicense.ID ON Person.ID = DrivingLicense.ID
INNER JOIN DrivingLicenseLicenseTypes ON DrivingLicense.ID = DrivingLicenseLicenseTypes.DrivingLicense_ID
INNER JOIN LicenseTypes ON DrivingLicenseLicenseTypes.LicenseType_ID = LicenseTypes.ID
INNER JOIN LicenseTypeVehicleTypes ON LicenseTypes.ID = LicenseTypeVehicleTypes
INNER JOIN VehicleTypes ON LicenseTypeVehicleTypes.VehicleType_ID = VehicleTypes.ID
WHERE x=y AND x=y

我认为我从错误的方式开始并犯了 Rookie 错误,我尝试从 OUTER JOIN 开始,即使它们是空白的也能得到结果。

我是不是从错误的脚开始,我需要把台阶转过来吗?

也许是为了澄清一些事情:

在我运行查询的这个页面之前,我有 2 个搜索字段,1 个对人来说是唯一的,1 个对车辆来说是唯一的。

基于这 2 个值,我正在检查它们是否匹配(检查此人是否确实是该值的所有者)。到目前为止一切顺利。

之后,我想根据我的驾照类型、车辆类型和驾照的到期日来检查此人是否可以驾驶该车辆。有踏板车驾驶执照的人不得驾驶汽车。

因此,我在此处的帮助下调整了我的数据库设置,我已经阅读了 INNER、OUTER、CROSS、LEFT JOINS 等之间的区别。但我一直在寻找缺失的链接。我认为仍然缺少一些逻辑。

如何通过适当的 JOINS 收集我需要的信息?我想避免我正在使用的情况:

SELECT table1, table2 FROM column1, column2

例如。

以下查询给了我双重结果:

SELECT * 
FROM RijbewijsTypes
LEFT JOIN RijbewijstypeVoertuigtype ON RijbewijstypeVoertuigtype.RijbewijstypeID = RijbewijsTypes.ID
LEFT JOIN RijbewijsRijbewijsType ON RijbewijsRijbewijsType.RijbewijstypeID
LEFT JOIN Rijbewijs ON Rijbewijs.ID = RijbewijsRijbewijsType.RijbewijsID
LEFT JOIN Persoon ON Persoon.ID = Rijbewijs.PersoonID
LEFT JOIN Voertuig ON Voertuig.PersoonID = Persoon.ID
LEFT JOIN Merk ON Merk.ID = Voertuig.Merk
LEFT JOIN Type ON Merk.Type = Type.ID
WHERE Persoon.BSNNummer =  '20230913'
AND Voertuig.Kenteken =  'NH-UN-78'

【问题讨论】:

  • 是啊! DrivingLicenseLicenseTypes!
  • 查询是否失败?错误? 0 个结果?结果太多?会发生什么?
  • 您的 join 语句有误:还有一个 =
  • 1) 仅当两个表中的记录都在连接时,内部连接才会返回数据。 2) 左连接将包括来自第一个表的记录,而不是第二个 3) 右连接将包括来自第二个表而不是第一个表的记录。 4) 完全外连接将返回两个表中的所有记录,无论连接如何。使用 where 子句可以否定连接,所以一开始不要使用它们。如果您需要限制表中的数据,请限制连接 from A inner join b on a.id = b.id and b.value='No' 尝试不带 where 子句的完整外连接,然后从那里开始......
  • 你加入person.IDDrivingLicence.ID。你应该加入DrivingLicense.Person_ID。还有其他这样的错误,还有很多拼写错误,比如DrivingLice_ID 而不是DrivingLicence_ID。我认为您了解连接的基本概念,但是您需要自己清除很多小错误。确保您使用的工具可以清楚地显示错误消息,这样您就不会怀疑您是否有 0 行或只是一个语法错误。

标签: mysql sql join left-join inner-join


【解决方案1】:
  • INNER JOIN:仅返回两者中的数据
  • LEFT JOIN:总是返回第一个表中的数据,然后只返回第二个表中的相关数据
  • RIGHT JOIN:总是从第二个表返回数据,然后只返回相关数据表 第一的。
  • FULL OUTER:始终返回所有表中的所有数据并对齐 当他们相关时。 (在 mySQL 中不可用)
  • CROSS JOIN:返回第一个表中的所有数据并将其与第二个表中的所有数据相关联,没有关系......所以如果第一个表中有 2 条记录,第二个中有 5 条记录......总结果将是 10 条记录.

那么让我们试试……

SELECT * 
FROM LicenseTypes LT
LEFT JOIN LicenseTypeVehicleTypes LTVH
 on LTVH.LicenseType_ID = LT.ID
LEFT JOIN DrivingLIcense DL
 on DL.ID = DLLT.DrivingLicense_ID
LEFT JOIN Person P
 on P.ID = DL.Person_ID
LEFT JOIN LicenseTypeVehicleTypes LTVT
 on LTVT.LicenseType_ID = LT.ID
LEFT JOIN VehicleTypes VT
 on VT.ID = LTVT.VehicleType_ID
LEFT JOIN Vehicles V
 on V.ID = VT.ID
WHere P.Name = 'Person1' and V.ID = 'VIN'

如果 Person1 的许可证类型为“X”且“VIN”的许可证类型为“X” 然后会显示一条记录。 但是,如果没有,则不会返回任何记录。

如果未提供 where 子句,则所有许可证类型将连同人员和车辆一起返回 使用这些许可证类型。

如果人员或车辆未与特定许可证类型相关联,则不会退回。 如果您也需要这些人,那么我们必须将上述查询与一个开头的查询结合起来 以车辆开头的人和工会。

【讨论】:

  • 用 MySQL 标记,不支持完全外连接
  • 我得到:#1064 - 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以获取在 'FULL OUTER JOIN 附近使用的正确语法,可能是因为 MySQL 是的。还有其他方法可以做到这一点吗?
  • 不,它不会工作......数据不在外部表中的中间表将被排除在结果中。你真的需要了解数据的本质以及它是否是可选的。所有车辆都可能没有人,也可能不是所有人都被分配到汽车上,那么我认为我们可以通过使用正确的左右连接来做到这一点。 People、LicenseTypes 和 Vehicles 似乎是三个主要表。用英语解释期望的结果。您想要所有许可证类型以及人员和车辆列表吗?
  • - 一个人可以拥有多辆汽车 - 一个人有 1 个驾照,可以包含多个驾照类型。 - 车辆可以有 1 个所有者 - 车辆只能有 1 种类型。 - 1 Licentype 可以让你驾驶多辆车。我想完成一个显示我的列表:人名,他拥有的许可证,显示许可证类型。然后我想展示车辆,车辆类型和它需要什么驾驶执照。比方说,所有人都有一辆车,所有的车都有一个主人。
  • 您列出的表结构未列出所有者。车辆表上没有 person_ID。它显示的是人员和他们拥有的被许可人类型以及他们拥有的车辆和许可证类型。我没有看到它在哪里列出了与人相关的车辆。
【解决方案2】:

我已经把表格放在一个更符合逻辑的地方:

SELECT DISTINCT
    p.name,
    v.VehicleType,
    v.make,
    v.model,
    CASE
       WHEN ltvt.VehicleType_ID =  v.VehicleType_ID THEN 1
       ELSE 0
    END allowed
FROM
    Person p
JOIN
    Vehicles v
    ON p.ID = v.person_id
LEFT JOIN
    DrivingLicense dl
    ON p.ID = dl.Person_ID
LEFT JOIN
    DrivingLicenseLicenceType dlt
    ON dl.ID = dlt.DrivingLicense_ID
LEFT JOIN
    LicenseTypes lt
    ON dlt.LicenseType_ID = lt.ID
LEFT JOIN
    LicenseTypeVehicleTypes ltvt
    ON dlt.LicenseType_ID = ltvt.LicenseType_ID
    AND ltvt.VehicleType_ID = v.VehicleType_ID
    AND dl.ExpiryDate >= CURRENT_DATE 

这将导致所有人都拥有自己的车辆。 通过向最后一个左连接添加一些条件,您可以确定是否允许驾驶特定车辆。 如果您想要特定的人和/或特定的车辆,只需添加 WHERE 子句

更新

约翰有 1 个驾驶执照,有 2 种执照类型:B 和 AM。 B 和 AM 许可证类型都连接到 VehicleType: Scooter。只有 Licensetype B,连接到我的 VehicleType:Familywagon,当我将车辆类型从 Scooter 更改为 Familywagon 时,我的值显示为 0,我不允许驾驶这辆车

这与连接逻辑和数据模型有关。 因为驾驶执照与人相关,而不是直接与车辆相关,所以左连接的车辆类型将具有与许可证类型具有的车辆类型数量一样多的条目。

在您的情况下,John's Familywagon 将出现在结果中两次,一次用于许可证类型的踏板车部分(不允许他驾驶汽车),一次用于 Familywagon 部分(允许他驾驶汽车)开车)。

这可以通过创建一个带有子查询的虚拟表来避免,该子查询包含一个人可以驾驶的不同车辆类型。

SELECT
    p.name,
    v.VehicleType_ID,
    v.make,
    v.model,
    CASE
        WHEN dls.VehicleType_ID =  v.VehicleType_ID THEN 1
        ELSE 0
    END allowed
FROM
    Person p
JOIN
    Vehicles v
    ON p.ID = v.Person_ID
LEFT JOIN
    (SELECT DISTINCT
        dl.Person_ID,
        ltvt.VehicleType_ID
    FROM
        DrivingLicense dl       
    JOIN
        DrivingLicenseLicenseTypes dlt
        ON dl.ID = dlt.DrivingLicense_ID
    JOIN
        LicenseTypes lt
        ON dlt.LicenseType_ID = lt.ID
    JOIN
        LicenseTypeVehicleTypes ltvt
        ON dlt.LicenseType_ID = ltvt.LicenseType_ID
    WHERE
        dl.ExpiryDate >= CURRENT_DATE
    ) dls
    ON p.ID = dls.Person_ID
        AND dls.VehicleType_ID =  v.VehicleType_ID

请注意,如果您需要有关某个人的信息,则在子查询中包含 person 表可能是明智之举,这样您就可以缩小子查询的结果数量。

【讨论】:

  • 哇,谢谢,你让我清醒了。我想我明白了,我正在添加 soin JOINS 以从另一张桌子上调出车辆的颜色等。但我可以做到.我还有 1 个问题,我可以在 PHP 中回显“允许”的值吗?所以如果这个人是有效驾驶车辆,回显1,否则回显0?
  • 我还有 1 个问题我似乎无法解决,除了 1 件事外,一切都很完美:我有一个“约翰”,他有一辆车,它是一辆踏板车。 John 有 1 个驾照,有 2 个驾照类型:B 和 AM。 B 和 AM 许可证类型都连接到 VehicleType: Scooter。只有 Licensetype B 连接到我的 VehicleType:Familywagon,当我将车辆类型从 Scooter 更改为 Familywagon 时,我的值显示为 0,我不允许驾驶这辆车。除了我的 LicenseeType 与 VehicleType 匹配。有什么想法吗?
  • 您已将另一个答案标记为正确答案,因此问题已解决?
  • 那是一个错误,因为另一个答案也很有帮助,你的回答让我完全了解我想要创造的情况!我已将您的答案标记为正确答案。但是我仍然在为我的上述评论而苦苦挣扎,您有任何线索吗?同时我也在尝试一些东西,但我不确定要编辑什么。
  • 谢谢,我明白了,就像你说的驾驶执照与人有关,我明白你指的是什么。好吧,我要解决这个问题,我明白这背后的逻辑..我将在查询末尾添加另一个AND,以检查驾驶执照的日期,因为这不在子查询中,我不明白.. 还有1个(最后一个)问题(对不起),我有为我的车辆类型制作了一个额外的表,所以我想加入:Vehicle.Type VehicleType.ID,是否最好为此创建另一个子查询?我对我的人的性别做了同样的事情。我想将我的 Person.Gender 加入到 Gender.ID。
猜你喜欢
  • 2013-02-08
  • 1970-01-01
  • 1970-01-01
  • 2017-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-17
  • 1970-01-01
相关资源
最近更新 更多