#mysql #sql
#mysql #sql
Вопрос:
CREATE TABLE operations (
id int auto_increment primary key,
time_stamp DATE,
product VARCHAR(255),
plan_week VARCHAR(255),
quantity INT
);
INSERT INTO operations
(time_stamp, product, plan_week, quantity
)
VALUES
("2020-01-01", "Product_A", "CW01", "125"),
("2020-01-01", "Product_B", "CW01", "300"),
("2020-01-01", "Product_C", "CW01", "700"),
("2020-01-01", "Product_D", "CW01", "900"),
("2020-03-15", "Product_A", "CW01", "570"),
("2020-03-15", "Product_C", "CW02", "150"),
("2020-03-15", "Product_E", "CW02", "325");
Ожидаемый результат:
time_stamp | product | plan_week | quantity | difference_quantity
-------------|---------------|------------------|---------------|-------------------
2020-01-01 | Product_A | CW01 | 125 | 445
2020-03-15 | Product_A | CW01 | 570 | 445
| | | |
2020-01-01 | Product_B | CW01 | 300 | -300
| | | |
2020-01-01 | Product_C | CW01 | 700 | -550
2020-03-15 | Product_C | CW02 | 150 | -550
| | | |
2020-01-01 | Product_D | CW01 | 900 | -900
2020-03-15 | Product_E | CW02 | 325 | 325
В приведенном выше результате я хочу вычислить difference
между двумя time_stamps
и назначить это difference
каждой строке на product
и plan_week
, как вы можете видеть в столбце difference_quantity
.
Пока у меня есть этот запрос, который сравнивает два time_stamps
и возвращает максимальное количество между ними обоими:
SELECT
time_stamp,
product,
plan_week,
quantity,
MAX(quantity) OVER (PARTITION BY product) AS max_quantity
FROM operations
GROUP BY 1,2
ORDER BY 2,1;
Однако я понятия не имею, как я могу изменить этот запрос, чтобы вместо максимального количества отображалось difference_quantity
.
У тебя есть какие-нибудь идеи?
Ответ №1:
Я мог бы решить проблему с /- signs
, вычислив разницу между time_stamps
в отдельной таблице, а затем использовать LEFT JOIN
для этой таблицы:
SELECT
op.time_stamp,
op.product,
op.plan_week,
op.quantity,
t2.difference_quantity
FROM operations op
LEFT JOIN
(SELECT
product,
(sum(time_stamp_02) - sum(time_stamp_01)) AS difference_quantity
FROM
(SELECT
product,
SUM(CASE WHEN time_stamp = '2020-01-01' THEN quantity ELSE 0 END) AS time_stamp_01,
SUM(CASE WHEN time_stamp = '2020-03-15' THEN quantity ELSE 0 END) AS time_stamp_02
FROM operations
GROUP BY 1) t1
GROUP BY 1) t2 ON t2.product = op.product
GROUP BY 1,2
ORDER BY 2,1;
Ответ №2:
Неоптимизированное пошаговое решение. Все CTE могут быть легко сведены в один CTE.
Предполагается, что исходная таблица хранит строго два разных значения даты.
WITH
cte1 AS (SELECT DISTINCT time_stamp FROM operations),
cte2 AS (SELECT DISTINCT product FROM operations),
cte3 AS (SELECT * FROM cte1 CROSS JOIN cte2),
cte4 AS (SELECT cte3.*, operations.plan_week, COALESCE(operations.quantity, 0) quantity
FROM cte3 LEFT JOIN operations USING (time_stamp, product)),
cte5 AS (SELECT *, FIRST_VALUE(quantity) OVER (PARTITION BY product ORDER BY time_stamp DESC)
-FIRST_VALUE(quantity) OVER (PARTITION BY product ORDER BY time_stamp ASC) difference
FROM cte4)
SELECT * FROM cte5 WHERE plan_week IS NOT NULL ORDER BY 2,1;
Ответ №3:
Это отвечает на первоначальную версию вопроса.
Вы, кажется, описываете логику следующим образом:
SELECT o.*,
(CASE WHEN COUNT(*) OVER (PARTITION BY product) = 2
THEN MAX(quantity) OVER (PARTITION BY product) - MIN(quantity) OVER (PARTITION BY product)
ELSE quantity
END) AS difference_quantity
FROM operations o
ORDER BY product, time_stamp;
Комментарии:
1. Можно ли отобразить 300, 550 и 900 в виде отрицательных чисел?
2. @Akina: Я пытался, но не смог заставить это работать: dbfiddle.uk /…
3. @Michi . . . Лучше задать новый вопрос, а не аннулировать ответы, отредактировав вопрос с уже полученным ответом.
4. Значения -300 и -550 были там до того, как я отредактировал вопрос. Знак минуса -900 отсутствовал, и я отредактировал, чтобы ожидаемые результаты были полностью правильными.