【问题标题】:MySQL Join across multiple tablesMySQL Join 跨多个表
【发布时间】:2018-04-13 00:59:25
【问题描述】:

我的 Web 应用程序需要所有用户组、组成员的列表,以及他们根据组成员身份有权访问的产品列表。

Web 应用程序支持多个“站点”;作为这些用户、组和产品的唯一标识符的站点。

我有以下疑问:

SELECT u.id as user_id, u.username, ug.group_id, ug.group_name, u.firstname, u.surname, p.product_name, p.product_id, p.product_price, p.product_currency, p.is_public
    FROM user_groups ug
    LEFT JOIN user_group_users ugu ON ug.group_id = ugu.group_id
    RIGHT JOIN users u ON u.id  = ugu.user_id
    LEFT JOIN user_group_product ugp on ug.group_id = ugp.group_id
    LEFT JOIN product p on p.product_id = ugp.product_id
    WHERE u.site_id = 5
    ORDER BY ug.group_name desc, u.surname, u.firstname, u.username

这很好,我使用 PHP 连接结果来传递数据。

问题PRODUCTS 表也有一个 is_public 标志,我想在结果集中包含所有产品,这些产品也将此设置为 1 以及返回的产品用户具有组访问权限,但同样仅限于此站点。

所以,为了清楚起见,我希望返回:

  • 所有用户记录 - 无论他们是否具有组成员身份(将显示未分组的用户)
  • 具有关联组成员身份的所有用户记录
  • 所有组
  • 所有产品 - 用户是该组的成员
  • 所有产品 - 产品设置为公开 - is_public = 1

以上所有内容必须仅适用于相关网站。

更新 3:更新了需求说明

更新 2:表结构:

--
-- Table structure for table `user_group_users`
--

CREATE TABLE IF NOT EXISTS `user_group_users` (
  `user_group_id` bigint(20) unsigned NOT NULL auto_increment,
  `user_id` mediumint(9) NOT NULL default '0',
  `group_id` mediumint(9) NOT NULL default '0',
  `created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`user_group_id`),
  KEY `user_id` (`user_id`,`group_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=54 ;

--
-- Table structure for table `user_groups`
--

CREATE TABLE IF NOT EXISTS `user_groups` (
  `group_id` mediumint(8) unsigned NOT NULL auto_increment,
  `site_id` mediumint(9) NOT NULL,
  `group_name` varchar(100) NOT NULL default '',
  `is_default` tinyint(1) NOT NULL COMMENT 'Users are automatically added to default groups at registration',
  PRIMARY KEY  (`group_id`),
  KEY `site_id` (`site_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

--
-- Table structure for table `user_group_product`
--

CREATE TABLE IF NOT EXISTS `user_group_product` (
  `user_group_product_id` bigint(20) unsigned NOT NULL auto_increment,
  `group_id` mediumint(9) NOT NULL default '0',
  `product_id` mediumint(9) NOT NULL default '0',
  `created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`user_group_product_id`),
  KEY `product_id` (`product_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=124 ;

--
-- Table structure for table `product`
--

CREATE TABLE IF NOT EXISTS `product` (
  `product_id` mediumint(8) unsigned NOT NULL auto_increment,
  `payment_enabled` tinyint(1) NOT NULL default '0',
  `credit_enabled` tinyint(1) NOT NULL default '0',
  `product_name` varchar(100) NOT NULL default 'Default Product',
  `is_public` tinyint(1) NOT NULL default '1',
  `product_price` decimal(10,2) default NULL,
  `product_currency` varchar(5) default NULL,
  PRIMARY KEY  (`product_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;

【问题讨论】:

  • 您是否尝试过INNER JOIN 而不是LEFTRIGHT 加入并将此条件添加到WHERE 子句?
  • 你能包括你的表结构吗?您的问题是,“网站是这些用户、组和产品的唯一标识符”;您当前是按站点选择用户,而不是组或产品。
  • @Mahmoud Gamal - 感谢您的建议,但是我没有明确说明我必须返回该站点的所有用户,即使他们没有组访问权限,因为这些用户可以访问公共产品,即is_public=1。我现在已将此添加到原始问题中。
  • users 和 user_groups 上都有site_id - 这些应该总是相同的吗?如果没有,您是否要包括无法通过自己的 users 记录访问站点 5,但可以通过其 user_groups 记录访问的用户?
  • @MarkBannister - 感谢您的 cmets。 site_id 值在两个表中重复且相同。因此,我需要用户有权访问(通过组成员身份)或产品是公开的所有用户、所有组和所有产品。

标签: mysql sql join


【解决方案1】:

如果我正确理解了您的要求,这应该可以:

SELECT u.id as user_id, u.username, ug.group_id, ug.group_name, u.firstname, u.surname, p.product_name, p.product_id, p.product_price, p.product_currency, p.is_public
FROM user_groups ug
JOIN user_group_users ugu ON ug.group_id = ugu.group_id
JOIN users u ON u.id  = ugu.user_id
JOIN user_group_product ugp on ug.group_id = ugp.group_id
JOIN product p on p.product_id = ugp.product_id
WHERE u.site_id = 5
UNION ALL
SELECT u.id user_id, u.username, NULL group_id, NULL group_name, u.firstname, u.surname, p.product_name, p.product_id, p.product_price, p.product_currency, p.is_public
FROM users
CROSS JOIN product p
WHERE p.is_public = 1
ORDER BY 4 desc, 6, 5, 2

- 它应该返回站点 5 上的用户具有组访问权限的所有产品,以及所有用户的所有公共产品。

【讨论】:

  • 非常感谢马克。这种结构看起来很理想,但结果集包括来自其他站点的产品。某处 site_id 被忽略,可能在 UNION ALL SELECT 中。
  • @Ben:其他网站的产品是否有NULL用户组和is_public=1?如果是这样,它们被包括在内是因为您要求为所有用户提供所有公共产品?
  • @Ben:请注意,尽管您多次提到“来自其他网站”的产品,您的数据结构中没有任何内容可以使产品特定于某个网站。根据您告诉我们的情况,只有 用户 是特定于网站的。
  • @Ben:您是否有将产品映射到网站的查找表(以便特定网站可以使用公开可用的产品)?
  • 啊,是的!我很抱歉。是的,确实有另一组将产品映射到站点的表。我已将这些连接添加到 UNION ALL 下的较低 SELECT 并成功!非常感谢上述 SQL,因为 UNION ALL 是解决产品的两个连接问题的更好方法。一切顺利,本。
猜你喜欢
  • 2013-01-25
  • 1970-01-01
  • 2013-02-15
  • 1970-01-01
  • 1970-01-01
  • 2011-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多