代码之家  ›  专栏  ›  技术社区  ›  Rob

MySQL从多个表中选择行

  •  0
  • Rob  · 技术社区  · 15 年前

    我正在一个目录网站上工作,用户可以在那里浏览类别。类别可以包含其他类别和产品,并且产品可以属于多个类别。相关的数据库架构如下所示:

    CREATE TABLE products (
        product_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
        product_title VARCHAR(100) NOT NULL,
        product_status TINYINT UNSIGNED NOT NULL
    );
    
    CREATE TABLE product_categories (
        category_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
        parent_category_id INT UNSIGNED NOT NULL,
        category_title VARCHAR(100) NOT NULL,
        category_status TINYINT UNSIGNED NOT NULL,
        category_order INT UNSIGNED NOT NULL
    );
    
    CREATE TABLE products_categories (
        product_id INT UNSIGNED NOT NULL,
        category_id INT UNSIGNED NOT NULL,
        product_order INT UNSIGNED NOT NULL,
        PRIMARY KEY(product_id, category_id)
    );
    

    我的问题是我需要用 LIMIT n, n :

    $perpage = 20;
    $start = (isset($_GET['page'])) ? (int)$_GET['page'] * $perpage : 1;
    $limitsql = "LIMIT $start, $perpage";
    

    但是,如果不加入和合并结果,我就不知道如何同时选择不同的类别和产品。理想情况下,我想要这样的结果:

    product_id      |       product_title   |       category_id     |       category_title
    NULL            |       NULL            |       32              |       category foo
    NULL            |       NULL            |       239             |       category bar
    9391            |       product foo     |       NULL            |       NULL
    325             |       product bar     |       NULL            |       NULL
    

    我能做的最好的事情就是得到这样的东西,但这并没有真正的帮助:

    product_id      |       product_title   |       category_id     |       category_title
    9391            |       product foo     |       32              |       category foo
    325             |       product bar     |       239             |       category bar
    239             |       product foo2    |       32              |       category foo
    115             |       product bar2    |       239             |       category bar
    

    我唯一能想到的其他解决方案是查询该类别中的所有子类别和产品,将它们粘贴到一个PHP数组中,并用 array_slice . 考虑到产品的数量(几千件),这不是一个非常吸引人的选择。

    否则,我可以查询类别的数量,并将 $start LIMIT 按类别数的子句。不过,如果类别超过一整页的话,这会很混乱。

    下面是我当前的工作查询,它给出了上面的结果:

    SELECT
        p.product_id, p.product_title,
        c.category_id, c.category_title
    FROM products AS p
    JOIN product_categories AS c
        ON c.parent_category_id='20'
    INNER JOIN products_categories AS pc
        ON p.product_id=pc.product_id
    WHERE p.product_status='1' AND pc.category_id='20'
    ORDER BY pc.product_order ASC
    

    编辑

    我想我有办法 UNION 我完全忘记了

    SELECT
        c.category_id AS row_id, c.category_title AS row_title, 1 AS is_category
    FROM product_categories AS c
    WHERE c.parent_category_id='20'
    
    UNION 
    
    SELECT
        p.product_id AS row_id, p.product_title AS row_title, 0 AS is_category
    FROM products AS p
    INNER JOIN products_categories AS pc
        ON p.product_id=pc.product_id
    

    编辑2

    我想工会不会像我想的那样运作。由于这两个查询都被视为单独的查询,因此我无法应用 极限 对于整个结果,只有每个人 SELECT .另外,从每个语句中选择的列必须是另一个语句中相应类型的相同类型。

    2 回复  |  直到 15 年前
        1
  •  6
  •   OMG Ponies    15 年前

    用途:

    SELECT *
      FROM (SELECT c.category_id AS row_id, c.category_title AS row_title, 1 AS is_category
              FROM product_categories AS c
             WHERE c.parent_category_id='20'
            UNION 
            SELECT p.product_id AS row_id, p.product_title AS row_title, 0 AS is_category
              FROM products AS p
              JOIN products_categories AS pc ON p.product_id=pc.product_id) x
    LIMIT x, y
    
        2
  •  0
  •   MindStalker    15 年前

    另一种方法是改变模式,使类别和产品本质上是相同的。

    CREATE TABLE items (
        item_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
        item_title VARCHAR(100) NOT NULL,
        item_status TINYINT UNSIGNED NOT NULL,
        category_or_item TINYINT UNSIGNED NOT NULL,
    );
    
    CREATE TABLE items_parents (
        item_id INT UNSIGNED NOT NULL,
        parent_id INT UNSIGNED NOT NULL, #points to itemid
        item_order INT UNSIGNED NOT NULL,
        PRIMARY KEY(item_id, parent_id)
    );
    

    然后,您的查询是平面的,您可以按类别\或\项目对其进行排序,以便类别首先出现。