我知道这很复杂,但是我衷心希望有人能检查一下。我制作了短版(以更好地理解问题)和完整版(使用原始SQL)
[TABLE A] [TABLE B]
|1|a|b| |1|x
|2|c|d| |1|y
|3| | | |2|z
|5| | | |2|v
|4|w
如何进行MySQL查询以获取类似的行:
1|a|b|x|y
2|c|d|z|v
A的2列和B的2行作为列,仅使用键1和2,无空结果
子查询?
我试图从Prestashop数据库中获取一行:
很容易获得id_product,ean13和upc,因为它是ps_product表中的一行。为了获得功能,我使用了子查询(JOIN无法解决)。
因此,我选择id_product,ean13,upc,(subquery1)作为代码1,(subquery2)作为代码2。然后我需要扔掉空白行。但是不能只是将code1或code2放在WHERE中。为了使其正常工作,我必须将所有内容放在子查询中。
此代码WORKS,但它非常丑陋,我敢打赌,应该以不同的方式进行。
我该如何更好?
SELECT * FROM(
SELECT
p.id_product as idp, p.ean13 as ean13, p.upc as upc, (
SELECT
fvl.value
FROM
`ps_feature_product` fp
LEFT JOIN
`ps_feature_value_lang` fvl ON (fp.id_feature_value = fvl.id_feature_value)
WHERE fp.id_feature = 24 AND fp.id_product = idp
) AS code1, (
SELECT
fvl.value
FROM
`ps_feature_product` fp
LEFT JOIN
`ps_feature_value_lang` fvl ON (fp.id_feature_value = fvl.id_feature_value)
WHERE fp.id_feature = 25 AND fp.id_product = idp
) AS code2,
m.name
FROM
`ps_product` p
LEFT JOIN
`ps_manufacturer` m ON (p.id_manufacturer = m.id_manufacturer)
) mainq
WHERE
ean13 != '' OR upc != '' OR code1 IS NOT NULL OR code2 IS NOT NULL
create table tablea
( id int,
col1 varchar(1),
col2 varchar(1));
create table tableb
( id int,
feature int,
cola varchar(1));
insert into tablea (id, col1, col2)
select 1,'a','b' union
select 2,'c','d' union
select 3,null,null union
select 5,null,null;
insert into tableb (id, feature, cola)
select 1,24,'x' union
select 1,25,'y' union
select 2,24,'z' union
select 2,25,'v' union
select 4,24,'w';
select a.id, a.col1, a.col2, b1.cola b1a, b2.cola b2a
from tablea a
inner join tableb b1 on (b1.id = a.id and b1.feature = 24)
inner join tableb b2 on (b2.id = a.id and b2.feature = 25);
SQLFiddle here。
您要执行的操作称为Pivot Query。 MySQL不支持透视查询,尽管其他RDBMSen也支持。
您可以模拟带有派生列的数据透视查询,但是必须指定每个派生列。也就是说,在MySQL本身中不可能使列数与另一个表的行匹配。这必须提前知道。
将结果查询为行,然后使用PHP将汇总成列会容易得多。例如:
while ($row = $result->fetch()) {
if (!isset($table[$row->id])) {
$table[$row->id] = array();
}
$table[$row->id][] = $row->feature;
这不是一个简单的问题,因为它不是标准查询,如果可以利用视图,则可以执行以下过程。假设您从此表开始:
CREATE TABLE `A` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`firstA` char(1) NOT NULL DEFAULT '',
`secondA` char(1) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
);
CREATE TABLE `B` (
`id` int(11) unsigned NOT NULL,
`firstB` char(1) NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `A` (`id`, `firstA`, `secondA`)
VALUES (1, 'a', 'b'), (2, 'c', 'd');
INSERT INTO `B` (`id`, `firstB`)
VALUES (1, 'x'), (1, 'y'), (2, 'z'), (2, 'v'), (4, 'w');
首先创建一个连接两个表的视图:
create or replace view C_join as
select A.firstA, A.secondA, B.firstB
from A
join B on B.id=A.id;
创建将表B中的行分组的视图:
create or replace view d_group_concat as
select firstA, secondA, group_concat(firstB) groupconcat
from c_join
group by firstA, secondA
创建满足您需求的视图:
create or replace view e_result as
select firstA, secondA, SUBSTRING_INDEX(groupconcat,',',1) firstB, SUBSTRING_INDEX(SUBSTRING_INDEX(groupconcat,',',2),',',-1) secondB
from d_group_concat
仅此而已。希望对您有帮助。
如果无法创建视图,则可能是查询:
select firstA, secondA, SUBSTRING_INDEX(groupconcat,',',1) firstB, SUBSTRING_INDEX(SUBSTRING_INDEX(groupconcat,',',2),',',-1) secondB
from (
select firstA, secondA, group_concat(firstB) groupconcat
from (
select A.firstA, A.secondA, B.firstB
from A
join B on B.id=A.id
) c_join
group by firstA, secondA
) d_group_concat
非常感谢大家的回答。 James的回答是最简单,最简单的方法,在我看来,这种方法非常有效。带有子查询的查询运行速度比我的快几倍。谢谢,詹姆斯!
只需几句话,为什么我需要它:
这是Prestashop和批发交易平台集成组件的一部分。批发商在平台上使用4种产品代码系统(ean13,upc和2个其他系统)。其他两个产品代码在Prestashop中作为产品功能添加。商店中有成千上万的产品,平台上有成千上万的产品。这就是为什么速度至关重要的原因。
这里是我的问题的完整版本的代码。也许有人会觉得这很有帮助。
查询以在一行中获取Prestashop产品代码和某些功能:
SELECT
p.id_product, p.ean13, p.upc, fvl1.value as code1, fvl2.value as code2
FROM `ps_product` p
LEFT JOIN
`ps_feature_product` fp1 ON (p.id_product = fp1.id_product and fp1.id_feature = 24)
LEFT JOIN
`ps_feature_value_lang` fvl1 ON (fvl1.id_feature_value = fp1.id_feature_value)
LEFT JOIN
`ps_feature_product` fp2 ON (p.id_product = fp2.id_product and fp2.id_feature = 25)
LEFT JOIN
`ps_feature_value_lang` fvl2 ON (fvl2.id_feature_value = fp2.id_feature_value)
WHERE
ean13 != '' OR upc != '' OR fvl1.value IS NOT NULL OR fvl2.value IS NOT NULL;