【问题标题】:Getting info from two Mysql Tables从两个 Mysql 表中获取信息
【发布时间】:2012-02-21 17:42:37
【问题描述】:

我正在使用 Codeigniter,我正在尝试从两个表中调用信息:

产品: ID, 姓名, 价格, 描述, 类型标识

产品类型: t类别, 名称

我正在尝试从 Product 中提取所有信息并使用 Product.typeID 来匹配 Product_Type 表并仅拉回 tName。大多数情况下,Product_Type 表中至少有 3 行具有相同的 typeID。示例:

产品 1 将是一件 20 美元的红色衬衫,我需要大号、中号和小号。

我曾尝试使用 JOIN 来执行此操作,但它为我提供了我需要的 3 种类型,而且还复制了 3 次衬衫信息。

这是我的代码:

$this->db->select('product.id, product.name, product.price, product.description, product_type.tName');  
$this->db->from('product');
$this->db->where('perm_name', $id);
$this->db->join('product_type', 'product_type.tCategory = product.typeId', 'LEFT OUTER');
$query = $this->db->get(); 

任何帮助将不胜感激。

编辑:

Array
(
    stdClass Object
        (
            [id] => 2
            [name] => Tshirt 1
            [price] => 20
            [description] => Awesome tshirt
            [tName] => 1
    )

)

Array
(
    [0] => stdClass Object
        (
            [tCategory] => 1
            [tName] => Small
    )

    [1] => stdClass Object
        (
            [tCategory] => 1
            [tName] => Medium
    )
    [2] => stdClass Object
        (
            [tCategory] => 1
            [tName] => Large
    )

)

【问题讨论】:

  • 如果您的产品重复了 3 次,则您的联接条款不起作用,并且您执行的是笛卡尔积而不是左联接。你能提供一些导致你的问题的示例数据吗?我对product_type.tCategory 和product.typeID 列的内容特别感兴趣。尝试用“LEFT”替换“LEFT OUTER”。
  • 我添加了 print_r 时的样子。它说左外角的原因是我正在试验这些设置,看看它们中的任何一个是否会产生我想要的结果。
  • 相关列不包括在内。您正在对列 product_type.tCategory 和 product.typeID 执行连接。 “左”连接只是“左外”连接的缩写。经过短暂的研究,我发现你只用“左”来称呼它,例如$this->db->join('comments', 'comments.id = blogs.id', 'left');codeigniter.com/user_guide/database/active_record.html
  • product_type.tCategory = product.typeID 是我玩弄的一个错误,它应该是 product_type.tCategory = product.typeId 我放在数组中的是使用的结果'剩下'。它仍然给了我 3 个相同信息的数组。
  • 是的。您使用 $this->db->select() 语句过滤了相关列。我要求提供表格中的数据,而不是您的查询结果。如果我们看不到执行连接的列的值,我们几乎无法帮助您。只需输入select * from productselect * from product_type 的结果

标签: php mysql codeigniter


【解决方案1】:

要让产品行包含一个列types,其中填充了第二个表的行,您可以加入两个表并使用 group by:

SELECT 
    product.id, 
    max(product.name) as name, 
    max(product.price) as price, 
    max(product.description) as description, 
    group_concat(product_types.tName) as types

FROM
    product

LEFT JOIN
    product_type ON product.tName = product_types.tCategory

GROUP BY product.id

max(product.name) 背后没有魔法。不允许在 select-clause 中使用不在 group by-clause 或聚合中的列。由于 product.id 是主键,我们只会为每个 product.id 获得一个 product.name,因此我们不关心选择了 3 个 product.name 中的哪一个(来自 3 种类型的连接)。他们都是一样的。我们甚至可以在 select-clause 中写 any(product.name) 但我认为 mysql 不支持这一点。 =)

或者做一个相关的子查询~

SELECT 
    product.id, 
    product.name, 
    product.price, 
    product.description, 
    (SELECT 
         group_concat(product_types.tName)
     FROM product_types
     WHERE product.tName = product_types.tCategory
     GROUP BY product_types.tCategory
    ) as types

FROM
    product

我建议使用第一个查询,因为它会更容易对 mysql 进行优化。记录在案:我没有测试这些查询,所以它们可能需要一些调整。请告诉我。

Edit1:使用 max() 的进一步说明

在下面的查询中,我们不允许使用列name,因为我们只按列id 分组。

SELECT
    id,
    name /* not allowed */

FROM
    product

GROUP BY id

我们只能选择group by-clause 中的列。我们也可以使用不在 group by 子句中的列,尽管像 maxgroup_concat 这样的聚合函数。

要解决这个问题,我们只需将name 列添加到group by 子句

SELECT
    id,
    name /* ok because it's in group by */

FROM
    product

GROUP BY id, name

如果我们现在有不同的 name 值,我们将在结果中得到多个元组,例如:

对于product 表 (id, name) = {(1, Alice), (1, Bob)} 我们得到结果

1, Alice
1, Bob

因为我们将两列都分组了。

第二种方法是使用聚合函数,例如 max:

SELECT
    id,
    max(name) /* ok because it's aggregated */

FROM
    product

GROUP BY id

对于product 表 (id, name) = {(1, Alice), (1, Bob)} 我们得到结果

1, Bob /* max(Alice,Bob) = Bob, because A < B */

在您的示例中,我假设列 product.id 是主键,因此是唯一的。这意味着对于id 列中的相同值,我们不能在name 列中具有不同的值。 {(1, Alice), (1, Bob)} 是不可能的,但也许是 {(1, Alice), (2, Bob)}。如果我们现在GROUP BY product.id,我们会为组中的每个元组获得product.name 的值。但是因为id决定了name,所以这些值都是一样的:

SELECT 
    product.id, 
    product.name, 
    product_type.tName,

FROM
    product

LEFT JOIN
    product_type ON product.tName = product_types.tCategory

会导致

(1, "White T-Shirt", Small),
(1, "White T-Shirt", Medium),
(1, "White T-Shirt", Large),
(2, "Black T-Shirt", Small),
(2, "Black T-Shirt", Medium),
(2, "Black T-Shirt", Large)

按 product.id 分组后,结果将如下所示

(1, F("White T-Shirt", "White T-Shirt", "White T-Shirt"), 
     G(Small, Medium, Large)),
(2, F("Black T-Shirt", "Black T-Shirt", "Black T-Shirt"), 
     G(Small, Medium, Large))

其中FGselect 子句中使用的聚合函数。对于F,我们使用哪个值都没有关系,它们都是一样的。所以我们只使用了max。对于 g,我们使用 group_concat 将所有值连接在一起。

所以

F("White T-Shirt", "White T-Shirt", "White T-Shirt") = "White T-Shirt"
F("Black T-Shirt", "Black T-Shirt", "Black T-Shirt") = "Black T-Shirt"
G(Small, Medium, Large) = "Small, Medium, Large"

这将导致

(1, "White T-Shirt", "Small, Medium, Large"),
(2, "Black T-Shirt", "Small, Medium, Large")

【讨论】:

  • 太棒了,非常感谢您抽出宝贵的时间。我希望您不介意另一个问题,如果您不介意的话,我不明白您为什么要使用 max() sql 命令,您能否进一步解释一下。
  • 我在下面添加了一些进一步的解释:Edit1:使用 max() 的进一步解释希望它有所帮助。
猜你喜欢
  • 2019-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 2015-02-18
相关资源
最近更新 更多