使用重复的 case 语句优化 SQL 查询

Optimising SQL Query with repeated case statements

我有以下设置:

CREATE TABLE table_name
(
perf_id INT,
build_id INT,
series_id INT,
client_id INT,
measurement INT
);

INSERT INTO table_name VALUES (1, 1, 1, 1, 10);
INSERT INTO table_name VALUES (2, 1, 2, 1, 15);
INSERT INTO table_name VALUES (3, 2, 1, 1, 10);
INSERT INTO table_name VALUES (4, 2, 2, 1, 15);
INSERT INTO table_name VALUES (5, 2, 2, 1, 20);
INSERT INTO table_name VALUES (6, 3, 1, 1, 10);
INSERT INTO table_name VALUES (7, 3, 2, 1, 20);

然后我使用以下查询:

SELECT
build_id,
CONCAT(
MIN(CASE WHEN series_id IN (1) THEN measurement ELSE NULL END),
';',
AVG(CASE WHEN series_id IN (1) THEN measurement ELSE NULL END),
';',
MAX(CASE WHEN series_id IN (1) THEN measurement ELSE NULL END)
),
CONCAT(
MIN(CASE WHEN series_id IN (2) THEN measurement ELSE NULL END),
';',
AVG(CASE WHEN series_id IN (2) THEN measurement ELSE NULL END),
';',
MAX(CASE WHEN series_id IN (2) THEN measurement ELSE NULL END)
)
FROM table_name GROUP BY build_id;

你可以在这里找到一个 sqlFiddle http://sqlfiddle.com/#!9/efef8/17

我想优化我的查询,主要是为了减少重复代码。我将从 PHP 调用它,并绑定 IN 运算符的值。

我认为一个函数可以替代大量重复代码:

CREATE FUNCTION data(s INT)
RETURNS VARCHAR(50)
RETURN CONCAT(
MIN(CASE WHEN series_id IN (s) THEN measurement ELSE NULL END),
';',
AVG(CASE WHEN series_id IN (s) THEN measurement ELSE NULL END),
';',
MAX(CASE WHEN series_id IN (s) THEN measurement ELSE NULL END)
)

但这抱怨聚合函数使用不当。我也不确定如何为 IN 运算符传入数组。

注意:

  1. concat 运算符在 SQLFiddle 上似乎不起作用,但在我的机器上却起作用。不知道是不是我语法有问题?

  2. 列数可变。

  3. 我还将在 GROUP BY 之前控制一个 WHERE 语句,但是我有这个工作,我只是不想重复我的 concat 一百万次。

您的函数中需要有一个 select。试试这个:

DELIMITER $$

create FUNCTION data(s INT, id int)
RETURNS VARCHAR(50)
BEGIN
    DECLARE res VARCHAR(50);
    SET res = (SELECT CONCAT(
MIN(CASE WHEN series_id IN (s) THEN measurement ELSE NULL END),
';',
AVG(CASE WHEN series_id IN (s) THEN measurement ELSE NULL END),
';',
MAX(CASE WHEN series_id IN (s) THEN measurement ELSE NULL END)
)
from table_name
where build_id = id);
    RETURN res;
END$$


select
t.build_id
, data(1, t.build_id)
, data(2, t.build_id)
from table_name t
group by t.build_id

如果您不关心值为 0 的行:

SELECT build_id,
       CONCAT_WS(';', MIN(measurement), AVG(measurement), MAX(measurement)),
FROM table_name
WHERE series_id = 2
GROUP BY build_id;

获取其他行:

SELECT build_id,
       CONCAT_WS(';', MIN(measurement), AVG(measurement), MAX(measurement)),
FROM table_name
WHERE series_id = 2
GROUP BY build_id
UNION ALL
SELECT build_id, ''
FROM table_name
GROUP BY build_id
HAVING MAX(series_id = 2) = 0;