除了选择和加入之外,还有其他任何东西都会丢失,需要帮助。我有一个表来维护创建的产品的属性。该表中目前有110k行。我正在寻找一种方法来查询数据并返回与每种产品属性变化相关的数据。
+-----------+---------+--------+--------+--------+
| attrib_id | prod_id | height | weight | length |
+-----------+---------+--------+--------+--------+
| 1 | 120 | 20 | 3 | 5 |
| 2 | 101 | 5 | 10 | 20 |
| 3 | 101 | 5 | 10 | 20 |
| 4 | 101 | 5 | 10 | 20 |
| 5 | 120 | 20 | 3 | 5 |
| 6 | 101 | 8 | 10 | 20 |
| 7 | 120 | 20 | 3 | 5 |
| 8 | 101 | 8 | 15 | 30 |
| 9 | 101 | 16 | 15 | 20 |
| 10 | 120 | 20 | 10 | 3 |
+-----------+---------+--------+--------+--------+
我希望在产品属性发生变化时将此类视为输出:
+-----------+---------+-------------+------------+------------+-------------+------------+------------+-------------+------------+------------+
| attrib_id | prod_id | orig_height | new_height | chg_height | orig_weight | new_weight | chg_weight | orig_length | new_length | chg_length |
+-----------+---------+-------------+------------+------------+-------------+------------+------------+-------------+------------+------------+
| 6 | 101 | 5 | 8 | 3 | 10 | | | 20 | | |
| 10 | 120 | 20 | | | 3 | 10 | 7 | 5 | 3 | -2 |
+-----------+---------+-------------+------------+------------+-------------+------------+------------+-------------+------------+------------+
答案 0 :(得分:1)
您的预期输出有点不正确。
您想要找到最小值和最大值attrib_id,然后使用聚合来查找所需的值:
select attrib_id,
prod_id,
original_height,
case when original_height = new_height then null else new_height end new_height,
nullif(new_height - original_height, 0) chg_height,
original_weight,
case when original_weight = new_weight then null else new_weight end new_weight,
nullif(new_weight - original_weight, 0) chg_weight,
original_length,
case when original_length = new_length then null else new_length end new_length,
nullif(new_length - original_length, 0) chg_length
from (
select t2.max_id attrib_id,
t.prod_id,
max(case when t.attrib_id = t2.min_id then t.height end) original_height,
max(case when t.attrib_id = t2.max_id then t.height end) new_height,
max(case when t.attrib_id = t2.min_id then t.weight end) original_weight,
max(case when t.attrib_id = t2.max_id then t.weight end) new_weight,
max(case when t.attrib_id = t2.min_id then t.length end) original_length,
max(case when t.attrib_id = t2.max_id then t.length end) new_length
from t
join (
select prod_id,
min(attrib_id) min_id,
max(attrib_id) max_id
from t
group by prod_id
) t2 on t.prod_id = t2.prod_id
and t.attrib_id in (t2.min_id, t2.max_id)
group by t.prod_id
) t;
答案 1 :(得分:1)
好的,我会建议一个完全不同的方法。我想到了在你的问题中读到“当产品属性发生变化时”的字样。其他答案每次重新计算所有连接和聚合,而您的表t
本质上是一个历史日志,它必然会增长和增长,并且您的查询将变得越来越慢。我的方法是创建一个表report
并通过触发器使其保持同步。你必须从两个空表开始
DROP TABLE IF EXISTS t;
CREATE TABLE t (attrib_id INT, prod_id INT, height INT, weight INT, length INT);
DROP TABLE IF EXISTS report;
CREATE TABLE report (
attrib_id INT, prod_id INT,
orig_height INT, new_height INT, chg_height INT,
orig_weight INT, new_weight INT, chg_weight INT,
orig_length INT, new_length INT, chg_length INT
);
然后,定义触发器:
DROP TRIGGER IF EXISTS trig;
DELIMITER $$
CREATE TRIGGER trig AFTER INSERT ON t FOR EACH ROW BEGIN
DECLARE old_prod_id, old_height, old_weight, old_length INT;
SELECT prod_id, new_height, new_weight, new_length
INTO old_prod_id, old_height, old_weight, old_length
FROM report
WHERE prod_id = NEW.prod_id;
IF ISNULL(old_prod_id) THEN
INSERT INTO report(attrib_id, prod_id, orig_height, orig_weight, orig_length)
VALUES (NEW.attrib_id, NEW.prod_id, NEW.height, NEW.weight, NEW.length);
ELSEIF old_height != NEW.height OR old_weight != NEW.weight OR old_length != NEW.length
OR ISNULL(old_height) -- First change: I suppose checking one field is enough
THEN
UPDATE report SET
attrib_id = NEW.attrib_id,
new_height = NEW.height, chg_height = NEW.height - orig_height,
new_weight = NEW.weight, chg_weight = NEW.weight - orig_weight,
new_length = NEW.length, chg_length = NEW.length - orig_length
WHERE prod_id = NEW.prod_id;
END IF;
END$$
DELIMITER ;
当您使用您提供给我们的值填充t
时,您会得到:
> SELECT * FROM report;
+-----------+---------+-------------+------------+------------+-------------+------------+------------+-------------+------------+------------+
| attrib_id | prod_id | orig_height | new_height | chg_height | orig_weight | new_weight | chg_weight | orig_length | new_length | chg_length |
+-----------+---------+-------------+------------+------------+-------------+------------+------------+-------------+------------+------------+
| 10 | 120 | 20 | 20 | 0 | 3 | 10 | 7 | 5 | 3 | -2 |
| 9 | 101 | 5 | 16 | 11 | 10 | 15 | 5 | 20 | 20 | 0 |
+-----------+---------+-------------+------------+------------+-------------+------------+------------+-------------+------------+------------+
您的情况会更加灵活,您可以根据需要轻松微调SELECT ... FROM report
查询。
答案 2 :(得分:0)
我不确定这是你在找什么,但它跟踪所有的变化:
select attrib_id, prod_id,
height as ori_height, nheight as new_height, (nheight - height) as chg_height,
weight as ori_weight, nweight as new_weight, (nweight - weight) as chg_weight,
length as ori_length, nlength as new_length, (nlength - length) as chg_length
from (
select attr1.attrib_id, attr1.prod_id, attr1.height, attr1.weight, attr1.length
,(select attr2.height from attr attr2
where attr2.prod_id = attr1.prod_id and attr2.attrib_id > attr1.attrib_id limit 1) nheight
,(select attr2.weight from attr attr2
where attr2.prod_id = attr1.prod_id and attr2.attrib_id > attr1.attrib_id limit 1) nweight
,(select attr2.length from attr attr2
where attr2.prod_id = attr1.prod_id and attr2.attrib_id > attr1.attrib_id limit 1) nlength
from attr attr1
order by attr1.prod_id, attr1.attrib_id
) calc
;
它会逐行返回所有更改:
+-----------+---------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| attrib_id | prod_id | ori_height | new_height | chg_height | ori_weight | new_weight | chg_weight | ori_length | new_length | chg_length |
+-----------+---------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| 2 | 101 | 5 | 5 | 0 | 10 | 10 | 0 | 20 | 20 | 0 |
| 3 | 101 | 5 | 5 | 0 | 10 | 10 | 0 | 20 | 20 | 0 |
| 4 | 101 | 5 | 8 | 3 | 10 | 10 | 0 | 20 | 20 | 0 |
| 6 | 101 | 8 | 8 | 0 | 10 | 15 | 5 | 20 | 30 | 10 |
| 8 | 101 | 8 | 16 | 8 | 15 | 15 | 0 | 30 | 20 | -10 |
| 9 | 101 | 16 | NULL | NULL | 15 | NULL | NULL | 20 | NULL | NULL |
+-----------+---------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| 1 | 120 | 20 | 20 | 0 | 3 | 3 | 0 | 5 | 5 | 0 |
| 5 | 120 | 20 | 20 | 0 | 3 | 3 | 0 | 5 | 5 | 0 |
| 7 | 120 | 20 | 20 | 0 | 3 | 10 | 7 | 5 | 3 | -2 |
| 10 | 120 | 20 | NULL | NULL | 10 | NULL | NULL | 3 | NULL | NULL |
+-----------+---------+------------+------------+------------+------------+------------+------------+------------+------------+------------+