2009-06-29 6 views
2

쿼리 작성에 대한 도움을 찾고 있습니다.동일한 쿼리에서 테이블을 두 번 이상 조인합니까?

Products 

id | (20 other columns I don't need) 
1 

product_names 

product_id | product_name 
1     my product 
2     my second product 
3     my third product 

cross_sell_products (where each product may have one, two, or no cross sell products) 

product_id | cross_sell_product_id 
1     2 
1     3 

나는 하나의 나에게 (자신의 이름) 모든 제품의 목록을 줄 것이다 쿼리, 그들의 교차 판매 제품 이름을 각각 사용하는 찾고 있어요 :이 같은 세 개의 테이블이 있습니다.

문제는이 모든 정보가 product_names 테이블에서 나오고 동일한 쿼리 내에서 동일한 테이블에서 두 번 이상 조인을 수행하는 방법을 모르겠다는 것입니다. (희망 의미가 그!)

그래서 출력이 무언가 같이 될 것이다 :

id | product_name | cross_sell_product_1 | cross_sell_product_2 
1   my product   my second product   my third product 

이 어떤 도움을 주셔서 감사합니다!

+0

물론이 - 우리가 ID 1이있을 때 내가 제대로 따른다면, –

+0

는 쇼핑 카트, 그리고 각 제품은 ('이 품목을 구매 한 고객은 다음 항목에 관심'같은 것을) 관련 제품을 가질 수 있습니다 우리 cross_sell_products 테이블을 점검하고 product_id = id (이 경우 1)로 해당 테이블의 모든 행을 찾으십시오. 그런 다음 corss_sell_product_1 열이 첫 번째 행의 corss_sell_product_id (이 경우 2 => 내 두 번째 제품)에 해당하는 product_name을 갖기를 원합니다. 그런 다음 두 번째 행에 대해 동일한 작업을 수행합니다 (존재하는 경우). –

+0

이 애플리케이션에서이 그룹화를 수행해야한다고 생각합니다. 어쨌든 내가 아는 한, MySQL에서 그렇게하기가 어렵습니다. –

답변

3

테이블의 별명을 지정합니다. 당신은 같은 일을 할 수 있습니다

SELECT p.product_name, x.product_name 
from products p 
inner join cross_sell_products c 
    on c.product_id = c.product_id 
inner join products x 
    on c.product_id = x.product_id; 
+0

두 가지 문제가 있습니다. 첫 번째 조인 절의 오타가 있으며 교차 판매 제품이없는 경우이 쿼리는 행을 반환하지 않습니다. – RedFilter

2

는 테이블 자체 사이에 가입하려면, 당신은 자기 조인을 사용합니다. 이는 별칭을 사용하여 수행됩니다 (예 :

select employee.name employee, 
     employer.name manager 
    from employees employee, 
    join employees employer on employer.name = employee.manager 
; 
1

별명을 제공하여 테이블을 두 번 이상 추가 할 수 있습니다. 예를 들어

SELECT 
    * 
FROM 
    MyTable AS MyTable1 
INNER JOIN 
    MyTable AS MyTable2 
ON 
    MyTable1.Id = MyTable2.Id 
0

본질적으로 cross_sell 제품 테이블을 피벗하고 있기 때문에 이것은 매우 까다 롭습니다. 당신은 0, 1, 또는 두 개의 교차 판매 제품은 세 개의 열을 가지고 테이블을 수정할 수있는 경우 :

id cross_sell_product_id_1 cross_sell_product_id_2 

을 다음 당신은 다른 답변에 설명 된대로 더 간단하게 가입 할 수 있습니다. 그렇지 않다면 질의를하는 것이 약간 까다 롭습니다. 저는 MySQL 전문가는 아니지만 Oracle에서 알고 있습니다!

1

나는 당신의 문제에 대한 해결책을 찾았다 고 생각하지만, 나는 그것이 당신이 원하는대로 작동하는지 확신하지 못한다. 어쨌든, 꽤 복잡합니다. 그것은 레코드를 뒤집기 위해 임시 테이블을 사용하는 저장 프로 시저입니다. 아직 극복 할 수없는 버그가 있습니다. 임시 테이블의 결과를 캐시합니다. SELECT 문에 SQL_NO_CACHE를 추가하려고 시도했지만 효과가 없습니다. 아래 절차는 여기에 잘 나타나지 않을 수도 있으므로 this GitHub gist에서도 살펴볼 수 있습니다. 그 요지는 또한 테스트 테이블의 구조와 데이터를 포함합니다. 모든 버그 보고서 또는 피드백은 크게 감사하겠습니다.

DELIMITER $$ 

CREATE PROCEDURE `report`() 
BEGIN 
    DECLARE col_number  INT(2)   DEFAULT 0; 
    DECLARE counter   INT(2)   DEFAULT 0; 
    DECLARE done    INT(1)   DEFAULT 0; 
    DECLARE last_prod  VARCHAR(128) DEFAULT ""; 
    DECLARE prod_name  VARCHAR(128); 
    DECLARE cross_prod_name VARCHAR(128); 
    DECLARE col_name   VARCHAR(32); 
    DECLARE create_temp_tbl TEXT; 

    -- ------------------------------------------------------------------------ 
    -- Query for fetching products and associated cross products. 
    -- ------------------------------------------------------------------------ 
    DECLARE cross_products CURSOR FOR 
     SELECT SQL_NO_CACHE 
      b.product_name, 
      c.product_name 
     FROM cross_sell_products AS a 
     INNER JOIN product_names AS b ON 
      a.product_id = b.product_id 
     INNER JOIN product_names AS c ON 
      a.cross_sell_product_id = c.product_id; 

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 


    -- ------------------------------------------------------------------------ 
    -- Find the largest number of cross products for a single product 
    -- ------------------------------------------------------------------------ 
    SELECT SQL_NO_CACHE 
     COUNT(*) AS total INTO col_number 
    FROM cross_sell_products 
    GROUP BY product_id 
    ORDER BY total DESC 
    LIMIT 1; 


    -- ------------------------------------------------------------------------ 
    -- Get rid of any instance of report_tmp. Given its structure is changing 
    -- from procedure call to procedure call, it might cause problems because 
    -- of the different number of columns it has versus the ones that we want 
    -- to insert. 
    -- ------------------------------------------------------------------------ 
    DROP TABLE IF EXISTS report_temp; 


    -- ------------------------------------------------------------------------ 
    -- Create a table with as many fields for cross products as the number 
    -- stored in col_number (which is the maximum number of cross products for 
    -- a single product). 
    -- Also, make product_name a primary key. We'll need this later in the 
    -- insertion phase. 
    -- ------------------------------------------------------------------------ 
    SET create_temp_tbl = "CREATE TEMPORARY TABLE report_temp (product_name VARCHAR(128) PRIMARY KEY, "; 

    WHILE counter < col_number DO 
     SET col_name = CONCAT("cross_sel_product_", counter); 
     SET create_temp_tbl = CONCAT(create_temp_tbl, CONCAT(col_name, " VARCHAR(128)")); 

     IF counter != col_number - 1 THEN 
      SET create_temp_tbl = CONCAT(create_temp_tbl, ", "); 
     END IF; 

     SET counter = counter + 1; 
    END WHILE; 

    SET @x = CONCAT(create_temp_tbl, ");"); 

    PREPARE stmt FROM @x; 
    EXECUTE stmt; 
    DEALLOCATE PREPARE stmt; 
    TRUNCATE TABLE report_temp; 


    -- ------------------------------------------------------------------------ 
    -- Begin fetch of products and cross products 
    -- ------------------------------------------------------------------------ 
    OPEN cross_products; 

    REPEAT 
     FETCH cross_products INTO prod_name, cross_prod_name; 

     IF NOT done THEN 
      -- ---------------------------------------------------------------- 
      -- Be sure to reset the counter every time the product group is 
      -- changing, so that we don't attempt to use more fields than 
      -- there are in the temporary table. 
      -- ---------------------------------------------------------------- 
      IF NOT prod_name = last_prod THEN 
       SET counter = 0; 
       SET last_prod = prod_name; 
      END IF; 

      -- ---------------------------------------------------------------- 
      -- For each cross product of a product, try to insert it, in case 
      -- it's not the first one in the group a key duplication error will 
      -- be reported. In this case, update the entry with a new cross 
      -- product. 
      -- ---------------------------------------------------------------- 
      SET col_name  = CONCAT("cross_sel_product_", counter); 
      SET @insert_stmt = CONCAT("INSERT INTO report_temp SET" 
            ," product_name = ?, " 
            , col_name ," = ? " 
            ,"ON DUPLICATE KEY UPDATE " 
            , col_name ," = ?"); 

      SET @prod_name  = prod_name; 
      SET @cross_prod_name = cross_prod_name; 

      PREPARE stmt_ins FROM @insert_stmt; 
      EXECUTE stmt_ins USING @prod_name, @cross_prod_name, @cross_prod_name; 
      DEALLOCATE PREPARE stmt_ins; 

      -- Go to next field 
      SET counter = counter + 1; 
     END IF; 
    UNTIL done END REPEAT; 

    CLOSE cross_products; 

    -- ------------------------------------------------------------------------ 
    -- Return desired result 
    -- ------------------------------------------------------------------------ 
    SELECT SQL_NO_CACHE * FROM report_temp; 
END $$ 

DELIMITER ; 
관련 문제