【问题标题】:SELECT from two tables based on the same id and grouped从基于相同 id 和分组的两个表中选择
【发布时间】:2015-04-01 09:23:35
【问题描述】:

我有两个结构不同的表(table1 已确认项目,table2 项目等待确认,每个用户可能在任一表中都有更多项目):

table1
id (primary) | user_id | group_id | name | description | active_from | active_to

table2
id (primary) | user_id | group_id | name | description | active_from

我试图拥有的是某个用户的所有项目的列表 - 即两个表中具有相同 user_id(例如 1)的行准备按 group_id 分组显示(即第一组 1,然后是第 2 组等)由name(在每个组内)排序。输出应该是这样的:

(all the groups below belong to the same user - with certain user_id)

# Group 1 (group_id) #
Item 67 (id): Apple (name), healthy fruit (description) (item stored in table1)
Item 29: Pear, rounded fruit (item stored in table2)

# Group 2 #
Item 14: Grape, juicy fruit (item stored in table2)

# Group 3 #
Item 116: Blackberry, shining fruit (item stored in table2)
Item 14: Plum, blue fruit (item stored in table1)
Item 7: Raspberry, red fruit (item stored in table1)

我无法找到可行的解决方案,我尝试使用 JOIN 以及使用 WHERE 子句的两个表中的简单 SELECT

我以下面的代码结束,由于返回了错误(高得多 - 冗余)的结果数量(不是谈论来自table2 的结果的未实现排序),因此显然无法正常工作:

SELECT table1.id, table1.user_id, table1.group_id, table1.active_from, table1.active_to, table2.id, table2.user_id, table2.group_id, table2.active_from
FROM table1
LEFT JOIN table2
ON table1.user_id = table2.user_id
WHERE (table1.group_id='".$group_id."' OR table2.group_id='".$group_id."') AND (table1.user_id='".$user_id."' OR table2.user_id='".$user_id."')
ORDER BY table1.property_name ASC

【问题讨论】:

  • 请提供一些样本数据和预期结果。
  • 你能用一些示例数据做一个 SQL 小提琴,这样我们就可以测试这个 + 预期的输出也会很好..
  • 我同意其他人的观点:显示示例数据和预期输出。你说两张桌子都是关于物品的。那么物品的钥匙是什么?名字?还是group_id?表的自然键是什么(即除了技术 id 之外,表中还有什么是唯一的)? user_id + group_id?
  • 上面添加的示例输出。致 Thorsten:table1 中项目的键是 id,table2 中是 id,如上所述(两个表都没有单个主键)。其他行也不能认为它们的组合是唯一的。
  • 好的,我明白了。我已经添加了一个答案。乍一看,顺便说一下,数据库设计看起来并不好。 (例如:这似乎是一个用户 - 水果关系,但我们链接到的只有一个用户表,没有水果表。这可能是故意的,但看起来很可疑。)告诉我们,如果你需要这方面的帮助.

标签: mysql sql


【解决方案1】:

union 适合您的问题。需要一些数据消息才能为联合的双方提供相同数量和类型的列:

select  group_id
,       id as item_id
,       name
,       description
,       source_table
from    (
        select  id
        ,       user_id
        ,       group_id
        ,       name
        ,       description
        ,       'from table1' source_table
        from    table1
        union all
        select  id
        ,       user_id
        ,       group_id
        ,       name
        ,       description
        ,       'from table2'  -- Column name is already defined above
        from    table2
        ) as SubQueriesMustBeNamed
where   user_id = 1
order by
        group_id
,       name

Working example at SQL Fiddle.

要根据需要格式化结果集,请遍历结果集。当group_id 发生变化时,打印一个# Group N # 标头。

客户端不需要有其他循环或迭代,只需一个foreach 或查询返回的一组行的等效项。

【讨论】:

  • 这帮助我使用UNION ALL 和假列构建了部分正确代码。但是,在输出代码中,我需要知道哪个项目来自哪个表。如何做到这一点?
  • 该示例包含一个source_table 列,您可以使用它来判断一行来自哪个表
  • 感谢您的解决方案。为了完成,您建议以最有效的方式显示组(“然后您可以为每个 group_id 创建一个组,并为它们显示聚合”)?
  • SQL 示例的 group by group_id 部分实现了“为每个 group_id 创建一个组”;)示例聚合为 count()max()
  • 这是否有助于我以示例中所述的形式列出结果? (我不需要在那里聚合。)目前,我通过第一个循环列出该用户的所有组和第二个(每个组内的内部循环)列出该组中的项目来列出每个组的结果。我的问题是,是否可以以更优雅的方式完成。
【解决方案2】:
select * from a t1 , b t2 where t1.user_id=t2.user_id and t1.group_id='' ORDER BY t1.name ASC 

【讨论】:

  • 虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
【解决方案3】:

好的,根据您在 cmets 部分所说的,我推测这两个表不相关。所以我们不想加入他们。

你想得到两个数据集联合的结果(即两个表,或者更准确地说:两个表的用户记录)。所以使用 UNION,或者更好:UNION ALL,(正如 Andomar 已经建议的那样)。

您不需要任何 GROUP BY,因为 SQL 中的 GROUP BY 意味着聚合数据(即每组获取一个结果行)。您想改为按 group_id 排序:

select *
from
(
  select group_id, id, name, description, 'confirmed' as status 
  from table1 where user_id = 12345
  union all
  select group_id, id, name, description, 'unconfirmed' as status
  from table2 where user_id = 12345
)
order by group_id;

【讨论】:

  • 上面的代码返回错误Every derived table must have its own alias
  • 你能解释一下'confirmed''unconfirmed'status的用法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-01
  • 2012-07-20
相关资源
最近更新 更多