MYSQL:从每个组中检索最后一条记录,并与另一个表的数据相结合

MYSQL:从每个组中检索最后一条记录,并与另一个表的数据相结合,mysql,sql,Mysql,Sql,有一个购买表,其中包含有关产品的信息。这将为购买的每个产品在tStockMP表中生成一行或多行 现在,我需要显示每个库存产品的表信息。由于purchase表包含更改的历史记录,因此在TPURCHAES表中按purchase\u id分组时,该信息位于最高的keyid中 我已经提供了一个完整的脚本,这里有描述我的问题的示例数据 DROP TABLE IF EXISTS tPurchases; DROP TABLE IF EXISTS tStockMP; -- The purchase table

有一个购买表,其中包含有关产品的信息。这将为购买的每个产品在tStockMP表中生成一行或多行

现在,我需要显示每个库存产品的表信息。由于purchase表包含更改的历史记录,因此在TPURCHAES表中按purchase\u id分组时,该信息位于最高的keyid中

我已经提供了一个完整的脚本,这里有描述我的问题的示例数据

DROP TABLE IF EXISTS tPurchases;
DROP TABLE IF EXISTS tStockMP;

-- The purchase table
CREATE TABLE tPurchases (
                            keyid                        INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                            brand                        VARCHAR(255),
                            model                        VARCHAR(255),
                            purchase_id                  INT
                           );

INSERT INTO tPurchases (brand,model,purchase_id) VALUES ("Hp","note1",23);
INSERT INTO tPurchases (brand,model,purchase_id) VALUES ("Lg","IPSLED",45);
INSERT INTO tPurchases (brand,model,purchase_id) VALUES ("Hp","notE1",23);
INSERT INTO tPurchases (brand,model,purchase_id) VALUES ("Bx","BOX",56);
INSERT INTO tPurchases (brand,model,purchase_id) VALUES ("LG","IPSLED",45);
INSERT INTO tPurchases (brand,model,purchase_id) VALUES ("HP","NOTE1",23);


-- The Stock MP Table
CREATE TABLE tStockMP (
                       keyid                        INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                       purchase_id                  INT,
                       status                       TINYINT
);

INSERT INTO tStockMP (purchase_id,status) VALUES (23,1);
INSERT INTO tStockMP (purchase_id,status) VALUES (23,1);
INSERT INTO tStockMP (purchase_id,status) VALUES (23,0);
INSERT INTO tStockMP (purchase_id,status) VALUES (45,0);
INSERT INTO tStockMP (purchase_id,status) VALUES (56,1);
INSERT INTO tStockMP (purchase_id,status) VALUES (56,1);
INSERT INTO tStockMP (purchase_id,status) VALUES (56,0);

-- Example data
-- 
-- tPurchases table
-- keyid brand model   purchase_id
-- 0     Hp    note1   23
-- 1     Lg    IPSLED  45
-- 2     Hp    notE1   23
-- 3     Bx    BOX     56
-- 4     LG    IPSLED  45
-- 5     HP    NOTE1   23
-- 
-- 
-- tStockMP   table.
-- purchase_id  status
-- 23           1 
-- 23           1
-- 23           0
-- 45           0
-- 56           1
-- 56           1
-- 56           0
-- 
-- 
-- Expected result
-- 
-- purchase_id  status  brand  model  
-- 23           1       HP     NOTE1   
-- 23           1       HP     NOTE1
-- 23           0       HP     NOTE1
-- 45           0       LG     IPSLED
-- 56           1       Bx     BOX
-- 56           1       Bx     BOX
-- 56           0       Bx     BOX


SELECT s.keyid, s.purchase_id, s.status, p.brand, p.model, p.keyid AS purkeyid 
FROM tStockMP AS s, tPurchases AS p 
WHERE s.purchase_id = p.purchase_id;

-- +-------+-------------+--------+-------+--------+----------+
-- | keyid | purchase_id | status | brand | model  | purkeyid |
-- +-------+-------------+--------+-------+--------+----------+
-- |     1 |          23 |      1 | Hp    | note1  |        1 |
-- |     1 |          23 |      1 | Hp    | notE1  |        3 |
-- |     1 |          23 |      1 | HP    | NOTE1  |        6 |-> *
-- |     2 |          23 |      1 | Hp    | note1  |        1 |
-- |     2 |          23 |      1 | Hp    | notE1  |        3 |
-- |     2 |          23 |      1 | HP    | NOTE1  |        6 |-> *
-- |     3 |          23 |      0 | Hp    | note1  |        1 |
-- |     3 |          23 |      0 | Hp    | notE1  |        3 |
-- |     3 |          23 |      0 | HP    | NOTE1  |        6 |-> *
-- |     4 |          45 |      0 | Lg    | IPSLED |        2 |
-- |     4 |          45 |      0 | LG    | IPSLED |        5 |-> *
-- |     5 |          56 |      1 | Bx    | BOX    |        4 |-> *
-- |     6 |          56 |      1 | Bx    | BOX    |        4 |-> *
-- |     7 |          56 |      0 | Bx    | BOX    |        4 |-> *
-- +-------+-------------+--------+-------+--------+----------+

我需要“过滤”结果,以便在最终查询中只保留*行,以免我需要手工操作。但是我不知道如何修改我的查询并实现这一点。

如果您的数据库支持窗口函数,您可以使用
行号()
来标识每个组的“最新”记录,并使用该信息过滤数据集:

SELECT *
FROM (
    SELECT 
        s.keyid, 
        s.purchase_id, 
        s.status, 
        p.brand, 
        p.model, 
        p.keyid AS purkeyid,
        ROW_NUMBER() OVER(PARTITION BY s.keyid ORDER BY p.keyid DESC) rn
    FROM tStockMP AS s
    INNER JOIN tPurchases AS p ON p.purchase_id = s.purchase_id
) t
WHERE rn = 1

如果您的数据库支持窗口功能,则可以使用
ROW\u NUMBER()
标识每个组的“最新”记录,并使用该信息筛选数据集:

SELECT *
FROM (
    SELECT 
        s.keyid, 
        s.purchase_id, 
        s.status, 
        p.brand, 
        p.model, 
        p.keyid AS purkeyid,
        ROW_NUMBER() OVER(PARTITION BY s.keyid ORDER BY p.keyid DESC) rn
    FROM tStockMP AS s
    INNER JOIN tPurchases AS p ON p.purchase_id = s.purchase_id
) t
WHERE rn = 1
切勿在
FROM
子句中使用逗号。I典型的解决方案是使用相关子查询:

SELECT s.keyid, s.purchase_id, s.status, p.brand, p.model, p.keyid AS purkeyid 
FROM tStockMP s JOIN
     tPurchases p 
     ON s.purchase_id = p.purchase_id
WHERE p.keyid = (SELECT MAX(p2.keyid)
                 FROM tPurchases p2
                 WHERE p2.purchase_id = p.purchase_id
                );
tpourchases(purchase\u id,keyid)
上有一个索引,这通常具有最佳性能

如果我使用窗口函数来处理此问题,我会将其表述为:

SELECT s.keyid, s.purchase_id, s.status, p.brand, p.model, p.keyid AS purkeyid 
FROM tStockMP s JOIN
     (SELECT p.*,
             ROW_NUMBER() OVER (PARTITION BY purchase_id ORDER BY keyid DESC) as seqnum
      FROM tPurchases p 
     ) p
     ON s.purchase_id = p.purchase_id
WHERE seqnum = 1;
GMB有另一种方法。如果您有大量的数据,比较这两种方法的性能会很有趣。对于所有比较,我建议使用与上述相同的索引。

切勿在
FROM
子句中使用逗号。I典型的解决方案是使用相关子查询:

SELECT s.keyid, s.purchase_id, s.status, p.brand, p.model, p.keyid AS purkeyid 
FROM tStockMP s JOIN
     tPurchases p 
     ON s.purchase_id = p.purchase_id
WHERE p.keyid = (SELECT MAX(p2.keyid)
                 FROM tPurchases p2
                 WHERE p2.purchase_id = p.purchase_id
                );
tpourchases(purchase\u id,keyid)
上有一个索引,这通常具有最佳性能

如果我使用窗口函数来处理此问题,我会将其表述为:

SELECT s.keyid, s.purchase_id, s.status, p.brand, p.model, p.keyid AS purkeyid 
FROM tStockMP s JOIN
     (SELECT p.*,
             ROW_NUMBER() OVER (PARTITION BY purchase_id ORDER BY keyid DESC) as seqnum
      FROM tPurchases p 
     ) p
     ON s.purchase_id = p.purchase_id
WHERE seqnum = 1;

GMB有另一种方法。如果您有大量的数据,比较这两种方法的性能会很有趣。对于所有比较,我建议使用与上述相同的索引。

首先在
tpourchaes
中使用
NOT EXISTS
,仅获取具有max
keyid
的行,然后加入
tStockMP

SELECT s.keyid, s.purchase_id, s.status, t.brand, t.model, t.keyid AS purkeyid 
FROM tStockMP AS s 
INNER JOIN (
  SELECT p.* FROM tPurchases AS p
  WHERE NOT EXISTS (
    SELECT 1 FROM tPurchases
    WHERE purchase_id = p.purchase_id AND keyid > p.keyid
  )
) AS t ON t.purchase_id = s.purchase_id
请参阅。
结果:


首先在
tpources
中使用
notexists
,仅获取具有max
keyid
的行,然后加入到
tStockMP

SELECT s.keyid, s.purchase_id, s.status, t.brand, t.model, t.keyid AS purkeyid 
FROM tStockMP AS s 
INNER JOIN (
  SELECT p.* FROM tPurchases AS p
  WHERE NOT EXISTS (
    SELECT 1 FROM tPurchases
    WHERE purchase_id = p.purchase_id AND keyid > p.keyid
  )
) AS t ON t.purchase_id = s.purchase_id
请参阅。
结果:


如何知道我的数据库是否支持行号。我有两个dbs。我在(我的个人笔记本电脑)中开发的数据库和将使用此查询的服务器中的数据库。@aarelovich:您使用哪个数据库:mysql、oracle、sql server…?我刚刚检查过。RDS配置为MySQL 5.7。很明显,这是MySQL 8.0以来的一个特性,所以我认为我不能使用它。我如何知道我的数据库是否支持行数。我有两个dbs。我在(我的个人笔记本电脑)中开发的数据库和将使用此查询的服务器中的数据库。@aarelovich:您使用哪个数据库:mysql、oracle、sql server…?我刚刚检查过。RDS配置为MySQL 5.7。很明显,这是MySQL 8.0以来的一个特性,所以我认为我不能使用它。我感兴趣的是为什么在from子句中不使用它?我一直在用它们。但是我对写问题还很陌生,所以,我很欣赏你的见解我也同意你的回答,因为我觉得第一个问题,我最了解!我感兴趣的是为什么在from子句中不使用?我一直在用它们。但是我对写问题还很陌生,所以,我很欣赏你的见解我也同意你的回答,因为我觉得第一个问题,我最了解!非常感谢。我毫不怀疑,这是一个有效的答案。然而,前一个问题中的第一个选项似乎更直截了当,特别是对于像我这样的初学者。当做非常感谢。我毫不怀疑,这是一个有效的答案。然而,前一个问题中的第一个选项似乎更直截了当,特别是对于像我这样的初学者。当做