如何从一个表和另一个表的 flag int 字段创建新视图(可以过滤)?

问题描述 投票:0回答:1

我有一张MODULES表(总共60个模块)

身份证 姓名
0 A
1 B
2 C
3 D

和表 EVENTS (有更多列,但对于问题来说是不必要的)

身份证 模块_已使用
0 1
1 15
2 8
3 3

表 EVENTS 有几百万行。

MODULES.ID 的值代表模块在 MODULES_USED 整数中的位位置(从 0 开始),因此,二进制 15 为 1111,表示模块 0、1、2、3 已被使用。同样,MODULES_USED 的值为 3 表示 0011,这意味着模块 0 和 1 已被使用。同样,1 表示 0001(模块 0),8 表示 0100(模块 2)。

我需要一个输出视图 MODULES_USED (这样我就可以创建柱形图),如下所示:

身份证 姓名 TIMES_USED
0 A 3
1 B 2
2 C 1
3 D 2

我想要实现的是关于 MODULES_USED 表的报告,最终用户可以通过 EVENTS 表的其他列(ID_COUNTRY、ID_Product...)进行筛选。

我尝试过的一个可能的解决方案是使用以下 SQL 查询的视图

SELECT
    `MODULES`.`ID` AS `ID`,
    `MODULES`.`NAME` AS `NAME`,
    (
    SELECT
        COUNT(`EVENTS`.`MODULES_USED`)
    FROM
        `EVENTS`
    WHERE
        (
            (
                `EVENTS`.`MODULES_USED` > 0
            ) AND(
                (
                    FLOOR(
                        (
                            `EVENTS`.`MODULES_USED` / POW(2, `MODULES`.`ID`)
                        )
                    ) % 2
                ) > 0
            )
        )
) AS `TIMES_USED`,
FROM
    `MODULES`

但这有两个主要问题:

速度很慢

除非修改视图,否则不允许过滤掉事件,例如,如果我想按 ID_Product(事件中的另一个字段)进行过滤,我必须编辑视图以在 WHERE 中添加 ID_PRODUCT = 1,但事实并非如此对报告的用户有用。另一种方法是在视图中使用不同的过滤条件创建额外的列(总计一列,每种产品一列,每个国家/地区一列,产品和国家/地区的每种组合一列...最终会产生数百列和执行时间(我在结束之前杀死了它)。

我想到的另一种方法是创建 EVENTS 表的视图,在其中为每个模块添加一列,但除了现在的 60 个之外,将来可能会增加到数百个,所以我不知道如何自动/以编程方式执行此操作,以及如何随后将其组合到转置的视图中。

mysql view
1个回答
0
投票

我不认为通过视图可以实现你所需要的。而且,我不确定你为什么想要这样做。

首先将聚合移至派生表中:

SELECT m.ID, m.NAME, IFNULL(SUM(e.num), 0) AS TIMES_USED
FROM MODULES m
LEFT JOIN (
    SELECT MODULES_USED, COUNT(*) AS num
    FROM `EVENTS`
    GROUP BY MODULES_USED
) e ON e.MODULES_USED & POW(2, m.ID)
GROUP BY m.ID;

即使没有

EVENTS.MODULES_USED
上的索引,这也应该表现得更好。当向内部查询添加过滤器(
ID_COUNTRY
ID_PRODUCT
等)时,理想情况下您需要一个覆盖过滤条件并以
MODULES_USED
结尾的索引来满足
GROUP BY
。添加索引来满足每种可能的组合显然是不可行的,因此您需要弄清楚最重要的用例是什么。

© www.soinside.com 2019 - 2024. All rights reserved.