使用重复的case语句优化SQL Query

时间:2016-05-25 23:26:46

标签: mysql sql sql-function

我有以下设置:

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运算符的数组。

NB:

  1. concat运算符似乎不适用于SQLFiddle,但在我的机器上运行。我不知道我是否搞砸了一些语法?

  2. 列数可变。

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

2 个答案:

答案 0 :(得分:2)

您需要在功能中进行选择。试试这个:

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

答案 1 :(得分:1)

如果您不关心值为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;