【问题标题】:LEFT JOIN select latest row from the left joinLEFT JOIN 从左连接中选择最新的行
【发布时间】:2021-06-26 17:55:16
【问题描述】:

我有一个公司数据库,其中包含所有详细信息。它还有一个单独的表来存储信用等级。

DROP TABLE IF EXISTS `company`;
CREATE TABLE IF NOT EXISTS `company` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET latin1 NOT NULL,
  `email` varchar(255) CHARACTER SET latin1 NOT NULL,
  `address` varchar(255) NOT NULL,
  `address2` text NOT NULL,
  `address3` text NOT NULL,
  `phone` text NOT NULL,
  `contacts` text NOT NULL,
  `islive` tinyint(1) NOT NULL DEFAULT '1',
  `qt` tinyint(1) NOT NULL DEFAULT '30',
  `pt` tinyint(1) NOT NULL DEFAULT '30',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `creditrating`;
CREATE TABLE IF NOT EXISTS `creditrating` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `cid` int(11) NOT NULL,
  `rating` int(11) NOT NULL,
  `arating` varchar(10) NOT NULL,
  `type` tinyint(1) NOT NULL DEFAULT '1',
  `thedate` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `company` (`id`, `name`, `email`, `address`, `address2`, `address3`, `phone`, `contacts`, `islive`, `qt`, `pt`) VALUES
(190, 'Test Company', 'test@test.com', 'Testing Client 1\r\nsdfsdfsdf\r\nsdfsdfsdf', 'Testing Client 1\r\nsdfsdfsdf\r\nsdfsdfsdf', 'Testing Client 1\r\nsdfsdfsdf\r\nsdfsdfsdf', '65165156', 'test name', 1, 30, 30),
(191, 'Test Company 2', 'test2@test2.com', 'Testing Client 2\r\nsdfsdfsdf\r\nsdfsdfsdf', 'Testing Client 2\r\nsdfsdfsdf\r\nsdfsdfsdf', 'Testing Client 2\r\nsdfsdfsdf\r\nsdfsdfsdf', '65165156', 'test name 2', 1, 30, 30);

INSERT INTO `creditrating` (`id`, `cid`, `rating`, `arating`, `type`, `thedate`) VALUES
(3, 190, 684, 'da774', 1, '2021-03-30 15:08:52'),
(6, 190, 222, 'DD222', 1, '2021-03-30 17:46:22');

我试图只检索公司详细信息和信用评级表上的最新行。

我最接近让它工作的 SQL 是 (Mysql 5.6):

SELECT c.id
     , AES_DECRYPT(c.name, 'co1') as name
     , AES_DECRYPT(c.phone, 'co3') as phone
     , c.islive
     , r.rating 
  FROM company c 
  LEFT 
  JOIN creditrating r 
    ON (SELECT r.thedate FROM creditrating WHERE c.id=r.cid ORDER BY r.thedate DESC LIMIT 1)

DB FIDDLE HERE

目前它正在带回同一家公司的 2 行而不是 1 行。

提前感谢你们通过我的方式提供的任何指点。

【问题讨论】:

    标签: mysql sql left-join mysql-5.6


    【解决方案1】:

    以前的版本没有窗口函数,但你可以切换到用户定义的变量

    DROP TABLE IF EXISTS `company`;
    CREATE TABLE IF NOT EXISTS `company` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) CHARACTER SET latin1 NOT NULL,
      `email` varchar(255) CHARACTER SET latin1 NOT NULL,
      `address` varchar(255) NOT NULL,
      `address2` text NOT NULL,
      `address3` text NOT NULL,
      `phone` text NOT NULL,
      `contacts` text NOT NULL,
      `islive` tinyint(1) NOT NULL DEFAULT '1',
      `qt` tinyint(1) NOT NULL DEFAULT '30',
      `pt` tinyint(1) NOT NULL DEFAULT '30',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    DROP TABLE IF EXISTS `creditrating`;
    CREATE TABLE IF NOT EXISTS `creditrating` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `cid` int(11) NOT NULL,
      `rating` int(11) NOT NULL,
      `arating` varchar(10) NOT NULL,
      `type` tinyint(1) NOT NULL DEFAULT '1',
      `thedate` datetime NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    INSERT INTO `company` (`id`, `name`, `email`, `address`, `address2`, `address3`, `phone`, `contacts`, `islive`, `qt`, `pt`) VALUES
    (190, 'Test Company', 'test@test.com', 'Testing Client 1\r\nsdfsdfsdf\r\nsdfsdfsdf', 'Testing Client 1\r\nsdfsdfsdf\r\nsdfsdfsdf', 'Testing Client 1\r\nsdfsdfsdf\r\nsdfsdfsdf', '65165156', 'test name', 1, 30, 30),
    (191, 'Test Company 2', 'test2@test2.com', 'Testing Client 2\r\nsdfsdfsdf\r\nsdfsdfsdf', 'Testing Client 2\r\nsdfsdfsdf\r\nsdfsdfsdf', 'Testing Client 2\r\nsdfsdfsdf\r\nsdfsdfsdf', '65165156', 'test name 2', 1, 30, 30);
    
    INSERT INTO `creditrating` (`id`, `cid`, `rating`, `arating`, `type`, `thedate`) VALUES
    (3, 190, 684, 'da774', 1, '2021-03-30 15:08:52'),
    (6, 190, 222, 'DD222', 1, '2021-03-30 17:46:22');
    
    SELECT 
        id, name, phone, islive, rating, `thedate`
    FROM
        (SELECT 
            name,
                phone,
                islive,
                rating,
                `thedate`,
                IF(id = @id, @rnk:=@rnk + 1, @rnk:=1) AS rnk,
                @id:=id AS id
        FROM
            (SELECT 
            c.id,
                AES_DECRYPT(c.name, 'co1') AS name,
                AES_DECRYPT(c.phone, 'co3') AS phone,
                c.islive,
                r.rating,
                `thedate`
        FROM
            company c
        LEFT JOIN creditrating r ON c.id = r.cid) t1, (SELECT @id:=- 1, @rnk:=0) t2
        ORDER BY id , `thedate` DESC) t3
    WHERE
        rnk = 1;
    
    编号 |姓名 |电话 |生活 |评级 |日期 --: | :--- | :---- | -----: | -----: | :----------------- 190 | | | 1 | 222 | 2021-03-30 17:46:22 191 | | | 1 | |

    db小提琴here

    【讨论】:

    • 谢谢@nbk 我已经设法使用不同的查询来做到这一点,但是您的查询与我的问题相同,它没有带回 r.thedate DESC。
    • @Robert 看到改变的答案
    • 谢谢,成功了。我能问一下你做了什么改变来让它工作吗?
    • 数据在之前的方法中是错误排序的,我也用 id 上的 amn 索引重新编写了连接,这样会更快,你的方法
    • 这是不正确的;它不能保证工作。 MySQL 文档特别警告不要在一个表达式中分配一个变量,然后在同一个 select 中的另一个表达式中使用它。不保证表达式的求值顺序。
    【解决方案2】:

    您可以为此使用窗口函数:

    SELECT c.id, AES_DECRYPT(c.name, 'co1') as name, AES_DECRYPT(c.phone, 'co3') as phone, c.islive, r.rating
    FROM company c LEFT JOIN
         (SELECT r.*,
                  ROW_NUMBER() OVER (PARTITION BY r.cid ORDER BY r.thedate DESC) as seqnum
          FROM creditrating r
         ) r
         ON c.id = r.cid AND r.seqnum = 1;
    

    【讨论】:

    • 感谢您的指点,我已经测试了您的版本并通过了一些错误,我将尝试使用它,看看我是否可以让您的查询以某种方式工作
    • 刚刚发现为什么我不能让它工作,在对它的工作原理进行了一些修改之后,这是因为它适用于版本 8+,而服务器所在的数据库是 5.6跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-11
    • 2020-08-02
    • 2019-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-24
    相关资源
    最近更新 更多