-1

我正在尝试使用动态键过滤数据透视表。

我有 3 个表,定义如下。当我不使用group by时,我的查询使用一个LEFT JOIN语句并产生如下结果:

示例 1
(来源:maverabilisim.com

黄色条是目标列,蓝色条是过滤条件。

我需要它返回如下所示的内容:

示例 2
(来源:maverabilisim.com

使用这样的条件:.... AND v.key_id=1 (color=1)

如何构建 SQL 查询以达到此结果?

我的 SQL 模式/测试数据:

CREATE TABLE `ads` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `ads_title` CHAR(80) NULL DEFAULT NULL,
    PRIMARY KEY (`id`)

);


CREATE TABLE `ads_keys` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `key` CHAR(25) NULL DEFAULT NULL ,
    `inlist` INT(1) UNSIGNED ZEROFILL NULL DEFAULT NULL ,
    PRIMARY KEY (`id`)
);
CREATE TABLE `ads_values` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `ads_id` INT(3) NULL DEFAULT NULL,
    `key_id` INT(10) NULL DEFAULT NULL,
    `value` INT(10) NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    UNIQUE INDEX `ads_id` (`ads_id`, `key_id`)
);
INSERT INTO `ads` VALUES (1, 'AAA');
INSERT INTO `ads` VALUES (2, 'BBB');
INSERT INTO `ads` VALUES (3, 'CCC');
INSERT INTO `ads` VALUES (4, 'DDD');
INSERT INTO `ads` VALUES (5, 'EEE');
INSERT INTO `ads` VALUES (6, 'FFF');
INSERT INTO `ads_keys` VALUES (1, 'KM', 1);
INSERT INTO `ads_keys` VALUES (2, 'OIL', 0);
INSERT INTO `ads_keys` VALUES (3, 'YEAR', 1);
INSERT INTO `ads_keys` VALUES (4, 'COLOR', 0);
INSERT INTO `ads_keys` VALUES (5, 'SPEED', 0);

INSERT INTO `ads_values` VALUES (1, 1, 1, 89000);
INSERT INTO `ads_values` VALUES (2, 1, 2, 200);
INSERT INTO `ads_values` VALUES (3, 1, 3, 2010);
INSERT INTO `ads_values` VALUES (4, 1, 4, 1);
INSERT INTO `ads_values` VALUES (5, 1, 5, 180);
INSERT INTO `ads_values` VALUES (6, 2, 1, 13000);
INSERT INTO `ads_values` VALUES (7, 2, 2, 150);
INSERT INTO `ads_values` VALUES (8, 2, 3, 2008);
INSERT INTO `ads_values` VALUES (9, 2, 4, 1);
INSERT INTO `ads_values` VALUES (10, 2, 5, 160);
INSERT INTO `ads_values` VALUES (11, 3, 1, 79800);
INSERT INTO `ads_values` VALUES (12, 3, 2, 172);
INSERT INTO `ads_values` VALUES (13, 3, 3, 2008);
INSERT INTO `ads_values` VALUES (14, 3, 4, 2);
INSERT INTO `ads_values` VALUES (15, 3, 5, 178);
INSERT INTO `ads_values` VALUES (16, 4, 1, 56781);
INSERT INTO `ads_values` VALUES (17, 4, 2, 127);
INSERT INTO `ads_values` VALUES (18, 4, 3, 2009);
INSERT INTO `ads_values` VALUES (19, 4, 4, 3);
INSERT INTO `ads_values` VALUES (20, 4, 5, 156);
INSERT INTO `ads_values` VALUES (21, 5, 1, 10200);
INSERT INTO `ads_values` VALUES (22, 5, 2, 205);
INSERT INTO `ads_values` VALUES (23, 5, 3, 2000);
INSERT INTO `ads_values` VALUES (24, 5, 4, 3);
INSERT INTO `ads_values` VALUES (25, 5, 5, 160);
INSERT INTO `ads_values` VALUES (26, 6, 1, 45877);
INSERT INTO `ads_values` VALUES (27, 6, 2, 150);
INSERT INTO `ads_values` VALUES (28, 6, 3, 2009);
INSERT INTO `ads_values` VALUES (29, 6, 4, 1);
INSERT INTO `ads_values` VALUES (30, 6, 5, 168);
4

2 回答 2

1

尝试

SELECT a.id, a.ads_title,
       MIN(CASE WHEN v.key_id = 1 THEN v.value END) `km`,
       MIN(CASE WHEN v.key_id = 3 THEN v.value END) `year`
  FROM ads_values v JOIN ads a
    ON v.ads_id = a.id 
 -- WHERE a.id = 2 -- if you need to fetch an ad with a particular id
 GROUP BY a.id, a.ads_title
HAVING SUM(CASE WHEN v.key_id = 4 AND v.value = 1 THEN 1 ELSE 0 END) > 0 

样本输出:

| 身份证 | ADS_TITLE | 公里 | 年份 |
---------------------------------
| 1 | AAA | 89000 | 2010 |
| 2 | 血脑屏障 | 13000 | 2008 |
| 6 | FFF | 45877 | 2009 |

这是SQLFiddle演示

于 2013-08-09T23:34:38.487 回答
1
SELECT ads.id, ads.ads_title, `km`.value AS `KM`, `year`.value AS `YEAR`
FROM ads
JOIN ads_values AS `color` ON (`color`.ads_id, `color`.key_id) = (ads.id, 4)
JOIN ads_values AS `km`    ON (`km`.ads_id, `km`.key_id)       = (ads.id, 1)
JOIN ads_values AS `year`  ON (`year`.ads_id, `year`.key_id)   = (ads.id, 3)
WHERE ads.id = 2 AND `color`.value = 1

重新发表您的评论,我认为您是在询问当表有很多行时此查询是否正常工作。

这是 EXPLAIN 的输出,显示它对每个连接都使用索引。要寻找的另一件事是rows要检查的行的估计值。下面的示例中的数字很小,但这可能是因为我们在表中只有少量行。

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: ads
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: color
         type: const
possible_keys: ads_id
          key: ads_id
      key_len: 10
          ref: const,const
         rows: 1
        Extra: NULL
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: km
         type: const
possible_keys: ads_id
          key: ads_id
      key_len: 10
          ref: const,const
         rows: 1
        Extra: NULL
*************************** 4. row ***************************
           id: 1
  select_type: SIMPLE
        table: year
         type: const
possible_keys: ads_id
          key: ads_id
      key_len: 10
          ref: const,const
         rows: 1
        Extra: NULL

为了比较,我在@peterm 的回答中对查询运行了 EXPLAIN。他的查询有较少的连接,但他的查询创建了一个临时表。这通常不利于性能。

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: a
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: v
         type: ref
possible_keys: ads_id,covering
          key: covering
      key_len: 5
          ref: const
         rows: 5
        Extra: Using index

解释只是一个估计。您应该使用真实数据测试这两个查询。

于 2013-08-09T23:22:03.120 回答