2011-06-23 12 views
5

Tôi có một bảng với hàng triệu hàng và một cột văn bản có độ dài chính xác là 11,159 ký tự. Nó trông giống như thế này:Làm cách nào để chọn các ký tự không liên tiếp từ một chuỗi văn bản trong MySQL?

1202012101...(to 11,159 characters) 
1202020120... 
0121210212... 
... 
(to millions of rows) 

Tôi nhận ra rằng tôi có thể sử dụng

SELECT SUBSTR(column,2,4) FROM table; 

... nếu tôi muốn rút ra khỏi nhân vật 2, 3, 4, và 5:

1202012101... 
1202020120... 
0121210212... 
^^^^ 

Nhưng tôi cần trích xuất các ký tự không liên tục, ví dụ ký tự 1,5,7:

1202012101... 
1202020120... 
0121210212... 
^ ^^ 

Tôi nhận ra điều này có thể được thực hiện với một truy vấn như:

SELECT CONCAT(SUBSTR(colm,1,1),SUBSTR(colm,5,1),SUBSTR(colm,7,1)) FROM table; 

Nhưng truy vấn này được rất khó sử dụng để xây dựng cho hàng ngàn nhân vật mà tôi cần phải lựa chọn. Vì vậy, cho phần đầu của câu hỏi - làm thế nào để xây dựng một truy vấn mà làm điều gì đó như thế này:

SELECT CHARACTERS(string,1,5,7) FROM table; 

Bên cạnh đó, các chỉ số của nhân vật tôi muốn chọn từ một bảng khác nhau mà trông giống như thế này:

char_index keep_or_discard 
1   keep 
2   discard 
3   discard 
4   discard 
5   keep 
7   discard 
8   keep 
9   discard 
10   discard 

vì vậy cho phần thứ hai của câu hỏi, làm thế nào tôi có thể xây dựng một truy vấn để chọn nhân vật cụ thể từ bảng đầu tiên dựa trên việc keep_or_discard = "giữ" cho chỉ số của nhân vật đó trong bảng thứ hai?

+0

Bạn có thể cân nhắc thực hiện nó trong quy trình được lưu trữ. Tôi đã không bao giờ viết một SP cho MySQL, nhưng trong Postgres, tôi sẽ sử dụng PL/Perl cho rằng, vì perl là tuyệt vời ở đó loại thao tác văn bản. – Flimzy

+0

Ngoài ra, tôi sẽ kéo ra toàn bộ chuỗi và phân tích nó với một cái gì đó giống như Perl, nhưng bảng là một cái gì đó giống như 100GB (hàng triệu hàng), và tôi chỉ cần một phần nhỏ của chuỗi dài 11,159 ký tự đó. –

+0

Chỉ cần làm rõ, bảng này có 11159 * hàng * hoặc bảng có một cột với 11159 * ký tự * trong mỗi hàng? – JYelton

Trả lời

0

Bạn có thể viết một kịch bản php để làm điều này cho bạn:

<?php 
    //mysql connect 
    $conn = mysql_connect('localhost', 'mysql_user', 'mysql_password'); 

    if (!$conn) { 
     echo 'Unable to connect to DB: ' . mysql_error(); 
     exit; 
    } 

    //database connect 
    $db = mysql_select_db('mydb'); 

    if (!$db) { 
     echo 'Unable to select mydb: ' . mysql_error(); 
     exit; 
    } 

    //get the keep numbers you’re going to use. 
    //and change the number into string so, for example, instead of 5 you get 'SUBSTR(colm,5,1)' 
    $result = mysql_query("SELECT number FROM number_table WHERE keep_or_discard='keep'"); 
    $numbers = array(); 
    while ($row = mysql_fetch_assoc($result)) { 
     $row = 'SUBSTR(colm,' . $row . ',1)'; 
     $numbers = $row; 
    } 

    //implode the array so you get one long string with all the substrings 
    //eg. 'SUBSTR(colm,1,1),SUBSTR(colm,5,1),SUBSTR(colm,12,1)' 
    $numbers = implode(",", $numbers); 

    //pull the numbers you need and save them to an array. 
    $result = mysql_query("SELECT " . $numbers . " FROM table"); 
    $concat = array(); 
    while ($row = mysql_fetch_assoc($result)) { 
     $concat= $row; 
    } 

Và ở đó bạn có một mảng với những con số chính xác.

Tôi xin lỗi nếu bạn không thể/không muốn sử dụng PHP cho điều này, tôi thực sự không biết cách thực hiện điều này mà không cần PHP, Perl, Python hoặc một số ngôn ngữ tương tự khác. Hy vọng rằng giải pháp này sẽ giúp đỡ bằng cách nào đó ...

0

Làm thế nào về sql động? (Bạn sẽ cần phải xây dựng phần lựa chọn của truy vấn)

CREATE PROCEDURE example_procedure() 
BEGIN 
    -- 
    --build the concat values here  
    --  
    SET @ids := ''; 
    SET @S = 'SELECT @ids := built_concat_of_values FROM table'; 
    PREPARE n_StrSQL FROM @S; 
    EXECUTE n_StrSQL; 
    DEALLOCATE PREPARE n_StrSQL;  
END 
0

Nguồn của bạn khó khăn là lược đồ của bạn không đại diện cho mối quan hệ thực sự giữa các yếu tố dữ liệu. Nếu bạn muốn đạt được điều này với SQL "tinh khiết", bạn sẽ cần một sơ đồ như hơn:

table 
ID Index Char 
1  0  1 
1  1  2 
1  2  0 

charsToKeep 
ID Index Keep 
1  0  false 
1  1  true 
1  2  true 

Sau đó, bạn có thể thực hiện một truy vấn như:

SELECT Char FROM table t JOIN charsToKeep c ON t.ID = c.ID WHERE c.Keep = true 

Tuy nhiên, bạn có thể có lý do chính đáng để cấu trúc dữ liệu theo cách bạn có (lược đồ của tôi yêu cầu nhiều không gian lưu trữ hơn cho mỗi ký tự và thời gian xử lý cũng có thể dài hơn nhiều so với những gì tôi sắp đề xuất).

Vì SQL không có công cụ để hiểu lược đồ bạn đã nhúng vào bảng của mình, bạn sẽ cần phải thêm chúng với hàm do người dùng xác định.Ví dụ về SQL động của Kevin cũng có thể hoạt động, nhưng theo kinh nghiệm của tôi, điều này không nhanh bằng chức năng do người dùng định nghĩa.

Tôi đã làm điều này trong MS SQL nhiều lần, nhưng không bao giờ trong MySql. Về cơ bản, bạn cần một hàm, được viết bằng C hoặc C++, có một danh sách được phân cách bằng dấu phẩy gồm các chỉ mục bạn muốn trích xuất và chuỗi mà từ đó bạn muốn trích xuất chúng từ đó. Sau đó, hàm sẽ trả về một danh sách được phân cách bằng dấu phẩy của các giá trị được trích xuất đó. Xem các liên kết cho một điểm khởi đầu tốt đẹp:

http://dev.mysql.com/doc/refman/5.1/en/adding-functions.html

http://dev.mysql.com/doc/refman/5.1/en/adding-udf.html

Xây dựng danh sách nối các chỉ số bạn muốn trích xuất từ ​​bảng char_index, hãy thử các chức năng group_concat:

http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat

Hy vọng điều này sẽ hữu ích!

1

chức năng này làm những gì bạn muốn:

CREATE DEFINER = `root`@`localhost` FUNCTION `test`.`getsubset`(selection mediumtext, longstring mediumtext) 
RETURNS varchar(200) 
LANGUAGE SQL 
NOT DETERMINISTIC 
CONTAINS SQL 
SQL SECURITY DEFINER 
COMMENT 'This function returns a subset of characters.' 
BEGIN 
    SET @res:=''; 
    SET @selection:=selection; 
    WHILE @selection<>'' DO 
    set @pos:=CONVERT(@selection, signed); 
    set @res := concat_ws('',@res,SUBSTRING(longstring,@pos,1)); 
    IF LOCATE(',',@selection)=0 THEN 
     SET @selection:=''; 
    END IF; 
    set @selection:=SUBSTRING(@selection,LOCATE(',',@selection)+1); 
    END WHILE; 
    RETURN @res; 
END 

Lưu ý: CONVERT ('1,2,3,4', đã ký) sẽ mang lại 1, nhưng nó sẽ cung cấp một cảnh báo.

Tôi đã xác định nó có sẵn trong thử nghiệm cơ sở dữ liệu.

Hàm lấy hai tham số; một chuỗi (!) với một danh sách các vị trí và một chuỗi dài từ nơi bạn muốn các ký tự được chụp.

Một ví dụ của việc sử dụng này:

mysql> select * from keepdiscard; 
+---------+------------+ 
| charind | keepordisc | 
+---------+------------+ 
|  1 | keep  | 
|  2 | discard | 
|  3 | keep  | 
|  4 | discard | 
|  5 | keep  | 
|  6 | keep  | 
+---------+------------+ 
6 rows in set (0.00 sec) 

mysql> select * from test; 
+-------------------+ 
| longstring  | 
+-------------------+ 
| abcdefghijklmnopq | 
| 123456789   | 
+-------------------+ 
2 rows in set (0.00 sec) 

mysql> select getsubset(group_concat(charind ORDER BY charind),longstring) as result from keepdiscard, test where keepordisc='keep' group by longstring; 
+--------+ 
| result | 
+--------+ 
| 1356 | 
| acef | 
+--------+ 
2 rows in set, 6 warnings (0.00 sec) 

Những cảnh báo xuất phát từ việc chuyển đổi nhanh để nguyên đó được thực hiện trong hàm. (Xem nhận xét ở trên)