5

我知道这很复杂,但我真诚地希望有人能检查一下。我制作了简短版(以便更好地理解问题)和完整版(使用原始 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 db 获取:

  • 产品编号
  • ean13 代码
  • 上行代码
  • ID 为 24 的功能
  • id 为 25 的功能

获取 id_product、ean13 和 upc 很容易,因为它是 ps_product 表中的一行。为了获得我使用子查询的功能(JOIN 没有成功)。

因此,我选择了 id_product, ean13, upc, (subquery1) 作为 code1, (subquery2) 作为 code2。然后我需要扔掉空行。但不能只将 code1 或 code2 放在 WHERE 中。为了让它工作,我必须把所有东西都放在子查询中。

这段代码可以工作,但它非常难看,我敢打赌这应该以不同的方式完成

我怎样才能让它变得更好?

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
4

4 回答 4

3
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在这里

于 2013-10-09T15:30:48.840 回答
0

This is not a simple question because it's not a standard query, by the way if you can make use of views you can do the following procedure. Assuming you're starting from this tables:

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');

First create a view that joins the two tables:

create or replace view C_join as
select A.firstA, A.secondA, B.firstB
from A
join B on B.id=A.id;

Create the view that groups the rows in table B:

create or replace view d_group_concat as
select firstA, secondA, group_concat(firstB) groupconcat
from c_join
group by firstA, secondA

Create the view that does what you need:

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

And that's all. Hope this helps you.

If you can't create views, this could be the query:

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
于 2013-10-09T16:04:51.663 回答
0

非常感谢大家的回答。詹姆斯的回答是第一个,最简单的,并且在我的情况下非常有效。该查询的运行速度比我的快几倍,带有子查询。谢谢,詹姆斯!

只需几句话我为什么需要它:

它是 Prestashop 和批发交易平台集成组件的一部分。批发商在平台上使用 4 种产品代码系统(ean13、upc 和 2 个其他系统)。这 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;
于 2013-10-10T07:52:59.720 回答
0

您想要做的是称为Pivot Query。MySQL 不支持数据透视查询,但其他 RDBMSen 支持。

您可以使用派生列模拟数据透视查询,但必须指定每个派生列。也就是说,MySQL 本身不可能使列数与另一个表的行数匹配。这必须提前知道。

将结果查询为行然后使用 PHP 将聚合到列中会容易得多。例如:

while ($row = $result->fetch()) {
    if (!isset($table[$row->id])) {
        $table[$row->id] = array();
    }
    $table[$row->id][] = $row->feature;
于 2013-10-09T15:13:52.707 回答