【问题标题】:MySQL - How to make one single SQL request for this case?MySQL - 如何为这种情况发出一个 SQL 请求?
【发布时间】:2020-09-03 10:40:08
【问题描述】:

我几天来一直在尝试为以下 SQL 请求寻找解决方案,但没有成功。

我的情况:

我有 3 张桌子(链接:https://i.stack.imgur.com/BswG0.png

  • Companies,其中包含公司
  • Requests,其中包含公司发送的请求
  • 报价,其中包含对公司提交的请求的报价,也包括直接提交给公司的自发报价

表 Offers 包含 2 个外键:

  • offers_fk_companies
  • offers_fk_requests

如果报价与公司发送的请求相关联,则字段 offers_fk_requests 包含一个值,字段 offers_fk_companies 为空。

如果在没有请求的情况下将报价直接提交给公司,则 offers_fk_requests 字段为空,offers_fk_companies 字段包含一个值。

我想在 Offers 表上进行 SELECT,以获取 所有条目 直接提交给公司的报价(没有任何请求)以及根据公司请求提交的报价。

我是带着这个要求而来的:

SELECT *
FROM `offers`

LEFT JOIN `requests` ON `offers_fk_requests` = requests.`id`
JOIN `companies` AS companies1 ON requests.`fk_companies` = companies1.`companies_id`

LEFT JOIN `companies` AS companies2 ON offers.`fk_companies` = companies2.`companies_id`

WHERE ...

当我执行上述请求时,我得到的结果与我将其分成 2 个不同的请求时不同:

SELECT *
FROM `offers`

LEFT JOIN `requests` ON `offers_fk_requests` = requests.`id`
JOIN `companies` AS companies1 ON requests.`fk_companies` = companies1.`companies_id`

WHERE ...
SELECT *
FROM `offers`

LEFT JOIN `companies` AS companies2 ON offers.`fk_companies` = companies2.`companies_id`

WHERE ...

基本上,有 2 种不同的路径:一种是从餐桌报价到餐桌公司,另一种是从餐桌报价到餐桌公司,但通过中间表请求。

我怎样才能用我的单个请求而不是那些单独的请求组合获得相同的结果?

我不能使用 UNION,因为字段数不同。我不知道在哪里可以找到解决方案...

提前致谢。

编辑

看来,如果我接受我的原始请求,并且对所有连接使用 LEFT OUTER JOIN,它就可以工作。

选择 * FROM offers

左外连接 requests ON offers_fk_requests = requests.id 左外连接 companies AS Companies1 ON requests.fk_companies = Companies1.companies_id

LEFT OUTER JOIN companies AS Companies2 ON offer.fk_companies = Companies2.companies_id

在哪里...

@Marcel:感谢您将我引向正确的方向!

【问题讨论】:

  • 您好,欢迎来到 Stackoverflow。这是一个准备充分且完整的问题!
  • 当您说您对这些优惠感兴趣时,您为什么要加入?您可以选择要约并仅根据包含的外键进行过滤。
  • @Marcel。感谢您的评论。我需要在一个 SQL 请求中获取所有匹配的条目,因为除其他外,我需要根据日期对它们进行排序,而且在我的应用程序中单独显示它们是没有意义的。条目必须混合。

标签: mysql


【解决方案1】:

根据 OP 的评论,一切都应该一口气完成,我建议干脆做

SELECT * 
FROM offers
LEFT OUTER JOIN companies ON companyId /*simplified*/
LEFT OUTER JOIN requests ON requestId /*simplified*/

左外连接仅在匹配时连接数据,否则将字段留空。所以你最终得到了所有的报价,并填写了可用的字段。

但是,对于当前的设计,对于那些有请求的人,公司数据是空的。我建议,将公司外键也设置在基于请求的那些上,从而使该键是强制性的。由于这个要求,他们无论如何都与一家公司联系在一起。

【讨论】:

  • 我刚刚测试了你的建议。它有效,但对于每一个报价,我都会得到大量不必要的信息。因此,不幸的是,您的解决方案不适合我的情况。
  • 是否可以在请求中使用某种条件来产生最终请求,例如: IF fieldA is null then do request1 ELSE do request2 ?我从来没有在我的请求中使用过条件,所以这对我来说是全新的,我什至不知道这是否可能。
  • 如果你想有 2 个不同的请求,没问题。您应该决定在您的应用程序中执行该操作,而不是在数据库中。
【解决方案2】:

如果使用 UNION,缺失的字段可以用 NULL 补全。

SELECT *
FROM `offers`

LEFT JOIN `requests` ON `offers_fk_requests` = requests.`id`
JOIN `companies` AS companies1 ON requests.`fk_companies` = companies1.`companies_id`
UNION ALL SELECT null, null, null, `fk_companies`, `companies_id`
FROM `offers`

LEFT JOIN `companies` AS companies2 ON offers.`fk_companies` = companies2.`companies_id`
WHERE `companies_id` IS NOT NULL;

要获取同一列中的所有company_id,可以使用以下查询。

SELECT `requests`.`id` AS `requests_id`, coalesce(`requests`.`fk_companies`, `companies`.`companies_id`) AS `companies_id`
FROM `offers`

LEFT JOIN `companies` ON `offers`.`fk_companies` = `companies`.`companies_id`
LEFT JOIN `requests` ON `offers`.`offers_fk_requests` = `requests`.`id`;

db fiddle

【讨论】:

    猜你喜欢
    • 2020-10-13
    • 1970-01-01
    • 1970-01-01
    • 2018-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多