Selecionar registros que mudaram seus valores anteriores

votos
0

Eu tenho uma tabela onde eu registrar a história do preço de produtos em um catálogo (outra tabela).

O preço de qualquer produto pode mudar a qualquer momento, então eu preciso para identificar apenas os produtos que mudaram seus preços. Por exemplo, eu tenho esta tabela:

+----+--------------+-------+---------------------+
| id | product_code | price | price_date          |
+----+--------------+-------+---------------------+
|  1 | P01          | 10.00 | 2019-01-01 00:00:00 |
|  2 | P01          | 15.00 | 2019-01-03 00:00:00 |
|  3 | P01          | 20.00 | 2019-01-05 00:00:00 |
|  4 | P01          | 15.00 | 2019-01-09 00:00:00 |
|  5 | P02          | 10.00 | 2019-01-04 00:00:00 |
|  6 | P02          | 15.00 | 2019-01-06 00:00:00 |
|  7 | P02          | 15.00 | 2019-01-07 00:00:00 |
|  8 | P03          | 15.00 | 2019-01-09 00:00:00 |
|  9 | P04          | 15.00 | 2019-01-01 00:00:00 |
| 10 | P04          | 15.00 | 2019-01-02 00:00:00 |
| 11 | P04          | 25.00 | 2019-01-05 00:00:00 |
| 12 | P05          | 15.00 | 2019-01-01 00:00:00 |
| 13 | P05          | 15.00 | 2019-01-02 00:00:00 |
+----+--------------+-------+---------------------+

e eu preciso este resultado:

+--------------+-------+---------------------+
| product_code | price | price_date          |
+--------------+-------+---------------------+
|          P01 | 20.00 | 2019-01-05 00:00:00 |
|          P01 | 15.00 | 2019-01-09 00:00:00 |
|          P04 | 15.00 | 2019-01-02 00:00:00 |
|          P04 | 25.00 | 2019-01-05 00:00:00 |
+--------------+-------+---------------------+

e isso são as exceções:

P02 não se alterou seu preço assim que eu ignorá-lo (várias vezes sim, o mesmo preço podem ser registradas consecutivamente)

P03 só tem 1 registo, então tecnicamente não se alterou seu preço, então eu ignorá-lo (isso é muito raro, mas alguns produtos nunca mudam seus preços)

P05 não se alterou seu preço assim que eu ignorá-lo

Eu coloquei esses dados, a fim de ler com facilidade, mas tecnicamente os dados podem estar em qualquer ordem.

Eu vos envio a consulta para que você não perca muito tempo:

CREATE TABLE PriceHistory(
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL,
product_code CHAR(3) NOT NULL,
price DECIMAL(5,2) NOT NULL,
price_date DATETIME NOT NULL,
PRIMARY KEY (id));

INSERT INTO PriceHistory(product_code, price, price_date) VALUES
('P01', 10, '2019-01-01'),
('P01', 15, '2019-01-03'),
('P01', 20, '2019-01-05'),
('P01', 15, '2019-01-09'),
('P02', 10, '2019-01-04'),
('P02', 15, '2019-01-06'),
('P02', 15, '2019-01-07'),
('P03', 15, '2019-01-09'),
('P04', 15, '2019-01-01'),
('P04', 15, '2019-01-02'),
('P04', 25, '2019-01-05'),
('P05', 15, '2019-01-01'),
('P05', 15, '2019-01-02');

Desde já, obrigado.

Publicado 10/10/2019 em 00:50
fonte usuário
Em outras línguas...                            


2 respostas

votos
0

Sua resposta não precisa exatamente porque eu esperar para ter os resultados em cada linha, mas esta resposta é bom o suficiente e se os postos de trabalho feito:

SELECT info1.*, info2.* FROM
(SELECT lasts.product_code, lasts.id AS last_id, penultimate.id AS penultimate_id FROM
    (SELECT product_code, MAX(id) AS id FROM PriceHistory GROUP BY product_code HAVING COUNT(product_code) > 1) lasts
INNER JOIN
    (SELECT product_code, MAX(id) AS id FROM PriceHistory WHERE id NOT IN (SELECT MAX(id) FROM PriceHistory GROUP BY product_code) GROUP BY product_code) penultimate
ON lasts.product_code = penultimate.product_code) relations
INNER JOIN PriceHistory info1 ON relations.last_id = info1.id
INNER JOIN PriceHistory info2 ON relations.penultimate_id = info2.id
WHERE info1.price != info2.price

E dá a este resultado:

+----+--------------+-------+---------------------+----+--------------+-------+---------------------+
| id | product_code | price | price_date          | id | product_code | price | price_date          |
+----+--------------+-------+---------------------+----+--------------+-------+---------------------+
|  4 | P01          | 15.00 | 2019-01-09 00:00:00 |  3 | P01          | 20.00 | 2019-01-05 00:00:00 |
| 11 | P04          | 25.00 | 2019-01-05 00:00:00 | 10 | P04          | 15.00 | 2019-01-02 00:00:00 |
+----+--------------+-------+---------------------+----+--------------+-------+---------------------+
Respondeu 10/10/2019 em 22:00
fonte usuário

votos
0

Isto parece um caso de uso natural para função de janela LAG(), disponível no MySQL 8.0:

SELECT product_code, price, price_date 
FROM (
    SELECT
        t.*,
        LAG(price) OVER(PARTITION BY product_code ORDER BY price_date) lag_price
    FROM PriceHistory t
) x WHERE price != lag_price

Demo no DB Fiddle - parece que há discrepâncias nos resultados esperados que você mostrou, mas esta parece ser a saída correta com base na minha compreensão da sua pergunta:

| product_code | price | price_date          |
| ------------ | ----- | ------------------- |
| P01          | 15    | 2019-01-03 00:00:00 |
| P01          | 20    | 2019-01-05 00:00:00 |
| P01          | 15    | 2019-01-09 00:00:00 |
| P02          | 15    | 2019-01-06 00:00:00 |
| P04          | 25    | 2019-01-05 00:00:00 |
Respondeu 10/10/2019 em 00:57
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more