簡體   English   中英

如何比較兩個逗號分隔的字段並在MySQL中獲得計數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM