我正在寻找一些构建查询的帮助。我有三张这样的表:
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 :(得分: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;
答案 1 :(得分:2)
要在表与自身之间进行连接,您必须使用自连接。这是通过使用别名来完成的,例如下面的“雇员”和“雇主”:
select employee.name employee,
employer.name manager
from employees employee,
join employees employer on employer.name = employee.manager
;
答案 2 :(得分:1)
您可以通过为其提供别名来多次添加表。例如
SELECT
*
FROM
MyTable AS MyTable1
INNER JOIN
MyTable AS MyTable2
ON
MyTable1.Id = MyTable2.Id
答案 3 :(得分:1)
我相信我找到了解决问题的方法,但我并不是100%确定它可以按你的意愿运作。无论如何,这很复杂。这是一个存储过程,它使用临时表来翻转记录。它有一个我无法克服的错误,它缓存临时表的结果。我尝试在SELECT语句中添加SQL_NO_CACHE,但没有效果。以下是程序,在SO上可能看起来不太好,所以你也可以在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 ;
答案 4 :(得分:0)
这非常棘手,因为您实际上是在转换cross_sell产品表。如果你有零个,一个或两个交叉销售产品,你可以修改你的表有三列:
id cross_sell_product_id_1 cross_sell_product_id_2
然后,您可以按照其他答案中的描述进行更简单的连接。如果没有,那么进行查询有点棘手 - 我不是MySQL专家,但我知道它在Oracle上!