【问题标题】:Combine four queries into one将四个查询合二为一
【发布时间】:2014-09-29 14:47:22
【问题描述】:

我继承了一个遗留代码库和一个带有它的数据库(我无法修改),我在重构代码时遇到了这些查询。如果可能的话,我试图将 4 个单独的查询放在一个中。如果需要,我将提供表模式。另外,如果您认为无法在一个查询中解决,请详细说明。

这些是查询(它是关于运动的),最终目的是获取给定用户创建和/或加入的所有杯子

  • cups 表包含创建的杯子、它们的创建者等
  • joined table 包含已加入特定杯子的用户,他们已结束的位置(排名)
  • registered_cups 表包含杯子的名称

第一个是尝试获取用户创建的所有杯子

SELECT cup_id FROM cups WHERE user_id = 'givenUser' AND cup_type <> 6

第二个是尝试获取用户加入的所有杯子

SELECT joined.cup_id, joined.cup_rank FROM joined LEFT JOIN cups USING (cup_id) WHERE joined.user_id = 'givenUser' AND cups.cup_type <> 6

现在,第一个结果被放入一个逗号分隔的字符串中,然后提供给下一个查询。第三个是读取所选杯子的信息

SELECT cup_id, user_id, status FROM joined WHERE cup_id IN (cupList)

最后一个得到杯子的名称,它们的版本,并订购它们

SELECT name, cup_id, edition, cups.user_id FROM cups LEFT JOIN registered_cups USING(register_id) WHERE cup_id IN (cupList) ORDER BY name ASC, edition DESC

正如你所看到的,有很多重复,而且不需要的东西,所以这就是我想出的:

SELECT cups.cup_id, cups.edition, cups.user_id, joined.cup_rank, registered_cups.name
FROM cups, joined, registered_cups
WHERE cups.cup_id = joined.cup_id
AND cups.register_id = registered_cups.register_id
AND joined.user_id = '308288'
AND cups.cup_type <>6
ORDER BY registered_cups.name ASC , cups.edition DESC 

我的查询的问题是我只得到了用户加入的杯子,但也有可能用户创建了一个杯子,但没有参与。这就是前两个查询的原因,但我不知道如何成功组合它们。我希望你能理解我想要达到的目标。

更新:

这里是架构的fiddle,有一点输入。有问题的用户是user_id = 133,它应该基本上选择所有行,即21,其中一个应该是一个有组织但没有被用户加入的杯子,所有其他的都是.

【问题讨论】:

  • 您应该使用LEFT JOIN,而不是隐式连接和按位置过滤

标签: mysql sql


【解决方案1】:

有几种方法可以做到这一点。您可以像这样进行外部连接:

SELECT cups.cup_id, cups.edition, cups.user_id, joined.cup_rank, registered_cups.name
  FROM cups INNER JOIN registered_cups ON cups.register_id = registered_cups.register_id
       LEFT OUT JOIN joined ON cups.cup_id = joined.cup_id and joined.user_id = '308288'
 WHERE cups.cup_type <>6
   AND (joined.user_id IS NOT NULL
    OR cups.user_id = '308288')
 ORDER BY registered_cups.name ASC , cups.edition DESC 

或者像这样的联合:

SELECT cups.cup_id, cups.edition, cups.user_id, joined.cup_rank, registered_cups.name
  FROM cups, joined, registered_cups
 WHERE cups.cup_id = joined.cup_id
   AND cups.register_id = registered_cups.register_id
   AND joined.user_id = '308288'
   AND cups.cup_type <>6
 UNION
SELECT cups.cup_id, cups.edition, cups.user_id, null, registered_cups.name
  FROM cups, registered_cups
 WHERE cups.register_id = registered_cups.register_id
   AND cups.user_id = '308288'
   AND cups.cup_type <>6
   AND NOT EXISTS 
       (SELECT 1 
          FROM joined 
         WHERE cups.user_id = joined.user_id and cups.cup_id = join.cup_id)
 ORDER BY registered_cups.name ASC , cups.edition DESC 

【讨论】:

  • 我根本无法进行第一个查询,不知道我在哪里做错了,它甚至让我的服务器崩溃了!但是我成功了第二个,我理解它并得到了我想要的结果,除了我更改了 order 子句,因为它无法识别列。无论如何,感谢您分享您的意见。
【解决方案2】:

我假设您有一个 users 表,并且在加入之前创建了杯子(似乎是逻辑)

SELECT
    c.cup_id,
    u.user_name,
    c.edition,
    j.status,
    j.cup_rank,
    cr.user_id IS NOT NULL created,
    r.name
FROM
    (SELECT 133 user_id) u
/* semi cross join the cups table */
JOIN
    cups c
    ON u.user_id = 133 AND c.cup_type <> 6
JOIN
    registered_cups r
    ON c.register_id = r.register_id
LEFT JOIN
    joined j
    ON c.cup_id = j.cup_id AND u.user_id = j.user_id
LEFT JOIN
    cups cr
    ON c.cup_id = cr.cup_id AND u.user_id = cr.user_id
ORDER BY r.name, c.edition

也许我有一些列名错误或来自错误的表,但想法保持不变

编辑: SQL Fiddle

【讨论】:

  • 虽然我确实掌握了你的想法,但我没有成功让它发挥作用,并返回我期望的结果。不过还是谢谢你@Gervs。
  • 也许您可以提供一些示例数据和您期望的结果。尽管您接受了答案,但可以(并且应该)优化该查询
  • 当然,我已经用小提琴更新了这个问题。
  • 我更改了一些字段名,在我看来它得到的结果与联合查询相同。看小提琴
  • 嗯...虽然它在这个例子中返回了相同的结果,但它没有在我的数据库中返回正确的结果。之所以如此,是因为这里只有这些行,基本上都应该被选中。但是我添加了额外的行来检查为什么我的数据库返回不同的结果,并且您提供的查询也获取了额外的行(这应该是错误的,因为我提供了不同的用户 ID)。这是添加了额外行的fiddle
猜你喜欢
  • 2013-11-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-23
  • 2012-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多