mysql 對指定字段進行去重並返回最新一條記錄


源表數據結構

CREATE TABLE `c_org_index_score` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `org_name` varchar(255) DEFAULT NULL COMMENT '部門編碼',
  `org_code` varchar(255) DEFAULT NULL COMMENT '部門名稱',
  `index_code` varchar(255) DEFAULT NULL COMMENT '指標編碼',
  `score` int(11) DEFAULT NULL COMMENT '評分',
  `create_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8 COMMENT='部門指標評分表';

插入數據

INSERT INTO `c_org_index_score`(`org_name`, `org_code`, `index_code`, `score`, `create_date`) VALUES ('紀委監委', 'GO_yb8ptad3itmc9', 'index_1', 90, '2021-12-09 16:12:16');
INSERT INTO `c_org_index_score`(`org_name`, `org_code`, `index_code`, `score`, `create_date`) VALUES ('市委辦', 'GO_nex86hpyof9ozy', 'index_1', 92, '2021-12-09 16:12:16');
INSERT INTO `c_org_index_score`(`org_name`, `org_code`, `index_code`, `score`, `create_date`) VALUES ('紀委監委', 'GO_yb8ptad3itmc9', 'index_2', 90, '2021-12-09 16:12:16');
INSERT INTO `c_org_index_score`(`org_name`, `org_code`, `index_code`, `score`, `create_date`) VALUES ('市委辦', 'GO_nex86hpyof9ozy', 'index_2', 90, '2021-12-09 16:12:16');
INSERT INTO `c_org_index_score`(`org_name`, `org_code`, `index_code`, `score`, `create_date`) VALUES ('紀委監委', 'GO_yb8ptad3itmc9', 'index_1', 85, '2021-12-10 09:12:16');
INSERT INTO `c_org_index_score`(`org_name`, `org_code`, `index_code`, `score`, `create_date`) VALUES ('市委辦', 'GO_nex86hpyof9ozy', 'index_1', 86, '2021-12-10 09:12:14');

源表數據如下,當我需要查詢本周各部門index_1的分數時,只需要獲取最新的記錄。

目標數據內容:index_code 為 ‘index_1’的score應該獲取日期為2021-12-10的數據

方案一

SELECT *  FROM c_org_index_score 
WHERE
        id NOT IN (SELECT min_id FROM ( SELECT min( id ) AS min_id, index_code, org_name, create_date FROM c_org_index_score GROUP BY org_name ) t );

思路:
一般數據表設計會定義id自增,這時先對數據分組,查詢分組中最小的id,並排除相應數據即可。
1)以分組字段進行分組,獲取分組中最小的id內容;
2)查詢條件設為排除“分組后最小的一組id”。
該方案的缺陷是,如果按照org_name進行分組時,存在一部分org_name原本就只有一組,那么在使用id not in() 方式時,會將僅有的一組org_name排除在外。

方案二:

SELECT
        id,
        org_name,
        org_code,
        SUBSTRING_INDEX(GROUP_CONCAT( index_code ORDER BY create_date DESC ), ',', 1) AS index_code,
        SUBSTRING_INDEX( GROUP_CONCAT( score ORDER BY create_date DESC ), ',', 1 ) AS score,
        max(create_date) create_date
FROM
        c_org_index_score 
GROUP BY
        org_code,
        create_date 
ORDER BY
        create_date DESC;

思路:
將需要去重的字段,先按照降序排列,然后通過 GROUP_CONCAT() 函數進行連接,通過SUBSTRING_INDEX() 截取第一個數值。全表通過指定字段和時間字段進行分組。
這種方式需要注意將對應的字段值,也通過同樣的方式取值,以達到字段值的匹配。
該方案存在的缺陷是,字段數很多且都需要獲取最新記錄的時候,SUBSTRING_INDEX() 函數、GROUP_CONCAT()函數在每個字段中都要拼接,SQL語句繁瑣、組織麻煩。

方案三:
SELECT * FROM (SELECT * FROM c_org_index_score ORDER BY create_date desc limit 10)t GROUP BY t.org_name,t.index_code
思路:
通過EXPLAIN 執行后可以看到, 該方案在搜索過程中使用了臨時表,即 order by 與limit 一起使用時,mysql在排序結果中找到最初的row_count行之后就會完成這條語句,而不是對整個結果集進行排序。
EXPLAIN SELECT * FROM (SELECT * FROM c_org_index_score ORDER BY create_date desc limit 4)t GROUP BY t.org_name,t.index_code;

相關函數說明
1)substring_index(str,delim,count) 將str字段按指定分隔符進行分割,截取分割后的count個字段內容。

substring_index(str,delim,count)

  str:要處理的字符串

  delim:分隔符

  count:計數

例如:
① SELECT SUBSTRING_INDEX( '紀委監委,市委辦,人大辦,公安廳', ',', 3 ) org_name;
② SELECT SUBSTRING_INDEX( '紀委監委,市委辦,人大辦,公安廳', ',', 1 ) org_name

運行結果:


2)group_concat( [DISTINCT] 要連接的字段 [Order BY 排序字段 ASC/DESC] [Separator ‘分隔符’] )
默認分割符是逗號
例如:
SELECT GROUP_CONCAT( org_name ORDER BY create_date DESC ) org_name_all FROM c_org_index_score;
運行結果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM