[英]How to compare two comma separate fields and get the count in MySQL
大家好,我有一個MySQL表,該表具有以逗號分隔的值的字段
id res
=============================
1 hh_2,hh_5,hh_6
------------------------------
2 hh_3,hh_5,hh_4
------------------------------
3 hh_6,hh_8,hh_7
------------------------------
4 hh_2,hh_7,hh_4
------------------------------
請參見上面的示例,實際上我需要將每一行“ res”與另一行的“ res”值進行比較,如果它們與其他行匹配,則需要顯示計數。 請幫助我獲得計數。
例如,IN第一行“ hh_2”也存在於第四行中,因此我們需要計數為2,同樣,我們需要比較所有行中的所有行
我已經運行了對我有用的功能。 但是桌子好大。 它有數百萬條記錄,所以我的表演需要時間。 用50000條記錄檢查一條記錄需要25秒。 假設我的輸入是60行,則需要一個小時。 請幫助我如何優化。
CREATE FUNCTION `combine_two_field`(s1 CHAR(96), s3 TEXT) RETURNS int(11)
BEGIN
DECLARE ndx INT DEFAULT 0;
DECLARE icount INT DEFAULT 0;
DECLARE head1 char(10);
DECLARE head2 char(10);
DECLARE head3 char(10);
WHILE ndx <= LENGTH(s1) DO
SET head1 = SUBSTRING_INDEX(s3, ',', 1);
SET s3 = SUBSTRING(s3, LENGTH(head1) + 1 + @iSeparLen);
SET head2 = SUBSTRING_INDEX(s1, ',', 1);
SET s1 = SUBSTRING(s1, LENGTH(head2) + 1 + @iSeparLen);
IF (head1 = head2) THEN
SET icount = icount + 1;
END IF;
SET ndx = ndx + 1;
END WHILE;
RETURN icount;
END
And the table size is too big and i want to reduce fetching time also ...
更新查詢:
DROP PROCEDURE IF EXISTS `pcompare7` $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `pcompare7`(IN in_analysis_id INT(11))
BEGIN
drop table if exists `tmp_in_results`;
CREATE TEMPORARY TABLE `tmp_in_results` (
`t_id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
`r_id` bigint(11) NOT NULL,
`r_res` char(11) NOT NULL,
PRIMARY KEY (`t_id`),
KEY r_res (r_res)
)
ENGINE = InnoDB;
SELECT splite_snp(r_snp,id,ruid) FROM results WHERE technical_status = 1 and critical_status = 1 and autosomal_status = 1 and gender_status != "NO CALL" and analys_id = in_analysis_id;
-- SELECT * FROM tmp_in_results;
-- COmpare Functionality
SELECT a.t_id, b.id, SUM(IF(FIND_IN_SET(a.r_res, b.r_snp), 1, 0)) FROM tmp_in_results a CROSS JOIN results b GROUP BY a.t_id, b.id;
END $$
用於創建溫度表的功能:
DROP FUNCTION IF EXISTS `splite_snp` $$
CREATE DEFINER=`root`@`localhost` FUNCTION `splite_snp`(s1 TEXT, in_id bigint(96), ruid char(11)) RETURNS tinyint(1)
BEGIN
DECLARE ndx INT DEFAULT 0;
DECLARE icount INT DEFAULT 0;
DECLARE head1 TEXT;
DECLARE head2 TEXT;
DECLARE intpos1 char(10);
DECLARE intpos2 char(10);
DECLARE Separ char(3) DEFAULT ',';
DECLARE iSeparLen INT;
SET @iSeparLen = LENGTH( Separ );
WHILE s1 != '' DO
SET intpos1 = SUBSTRING_INDEX(s1, ',', 1);
SET s1 = SUBSTRING(s1, LENGTH(intpos1) + 1 + @iSeparLen);
INSERT INTO tmp_in_results(r_id,r_res) VALUES(in_id,intpos1);
END WHILE;
RETURN TRUE;
END $$
新表結構
pc_input
id in_res in_id
=============================
1 hh_2 1000
------------------------------
2 hh_3 1000
------------------------------
3 hh_6 1001
------------------------------
4 hh_2 1001
------------------------------
res_snp
id r_res r_id
=============================
1 hh_2 999
------------------------------
2 hh_3 999
------------------------------
3 hh_9 999
------------------------------
4 hh_2 998
------------------------------
5 hh_6 998
------------------------------
6 hh_9 998
------------------------------
結果:
in_id r_id matches_count
=============================
1000 999 2 (hh_2,hh_3)
------------------------------
1000 998 1 (hh_2)
------------------------------
1001 999 1 (hh_2)
------------------------------
1001 998 2 (hh_2,hh_6)
------------------------------
我已經在表in_res,in_id和r_res和r_id中添加了單獨的索引
查詢:
SELECT b.r_id,count(*) FROM pc_input AS a INNER JOIN results_snps AS b ON (b.r_snp = a.in_snp) group by a.in_id,b.r_id;
但是mysql服務器被凍結了。 雲,請提出其他建議或優化我的查詢。
說明表:res_snp
Field Type Null Key Default Extra
id bigint(11) NO PRI NULL auto_increment
r_snp varchar(50) NO MUL NULL
r_id bigint(11) NO MUL NULL
解釋表:pc_input
Field Type Null Key Default Extra
id bigint(11) NO PRI NULL auto_increment
in_snp varchar(55) NO MUL NULL
in_id bigint(11) NO MUL NULL
說明查詢:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE a ALL in_snp NULL NULL NULL 192 Using temporary; Using filesort
1 SIMPLE b ref r_snp r_snp 52 rutgers22042014.a.in_snp 2861 Using where0
這是可能的,但是令人討厭。 正確規范化的數據庫會容易得多,但是有時您必須使用現有數據庫。
這樣的事情應該做(未經測試)。 它使用幾個子查詢來生成0到9之間的數字,組合允許的范圍是0到99。然后將其與substring_index一起使用以拆分字符串,並與DISTINCT一起使用以消除將要生成的重復項(我認為任何行上都不應有重復項—如果可以消除重復項,但是會變得更加復雜),那么該行僅用作子查詢來進行計數
SELECT aRes, COUNT(*)
FROM
(
SELECT DISTINCT sometable.id, SUBSTRING_INDEX(SUBSTRING_INDEX(sometable.res, ',', 1 + units.i + tens.i * 10), ',', -1) AS aRes
FROM sometable
CROSS JOIN (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
) Sub1
GROUP BY aRes
編輯-現在經過測試:
http://www.sqlfiddle.com/#!2/0ef59/4
編輯-可能的解決方案。 希望很快就能接受。
首先將輸入行提取到臨時表中:
CREATE TEMPORARY TABLE tmp_record
(
unique_id INT NOT NULL AUTO_INCREMENT,
id INT,
res varchar(25),
PRIMARY KEY (unique_id),
KEY `res` (`res`)
);
將您的測試數據加載到上面
INSERT INTO tmp_record (unique_id, id, res)
VALUES
(1, 1, 'hh_2'),
(2, 1, 'hh_5'),
(3, 1, 'hh_6'),
(4, 2, 'hh_3'),
(5, 2, 'hh_5'),
(6, 2, 'hh_4');
然后,您可以進行如下聯接。
SELECT a.id, b.id, SUM(IF(FIND_IN_SET(a.res, b.res), 1, 0))
FROM tmp_record a
CROSS JOIN sometable b
GROUP BY a.id, b.id
這是將每個輸入行與主表上的每一行連接起來,並檢查單個輸入是否在逗號分隔列表中。 如果是,則IF返回1,否則返回0。然后將這些值求和,並按2個ID分組。
未經測試,但希望這應該可以。 我不確定性能(這可能會很慢,因為您正在處理大量潛在記錄)。
請注意,臨時表僅持續與數據庫連接存在的時間長度。 如果需要通過多個腳本執行此操作,則可能需要創建一個普通表(記住完成后將其刪除)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.