2010-10-12 35 views
23

Tôi muốn tạo một quy trình được lưu trữ sẽ làm khớp với hai bảng. Yêu cầu của tôi là để phù hợp với hai bảng dựa trên các cột người dùng đi như là một đầu vào.Tách các chuỗi bằng cách sử dụng mysql

Cú pháp:

CREATE PROCEDURE reconcile.matchTables(
    IN TAB1 VARCHAR(25), 
    IN TAB1 VARCHAR(25), 
    IN COLS1 VARCHAR(250) , 
    IN COLS2 VARCHAR(250)) 

EX:

matchTables('table1', 'table2', 'col1#col2#col3#col4' , 'col2#col13#col1#col8') 

Bây giờ thủ tục lưu trữ nên hình thành các mệnh đề where như sau

table1.col1 = table2.col2 
    and table1.col2 = table2.col13 
    and table1.col3 = table2.col1 
    and table1.col4 = table2.col8 
+1

có thể trùng lặp của (http://stackoverflow.com/questions/471914/can-you-split-explode-a-field-in-a-mysql-query) –

+1

Tôi có một câu hỏi ngu ngốc: vì người dùng nhập hai tham số (hai danh sách cột), tại sao bạn không để cô ấy chèn 8 tham số (một cột cho mỗi cột)? Số lượng các cột đó có thay đổi không? –

Trả lời

-1

Không có chức năng để S plit a String. Bạn có thể làm như sau:

DROP PROCEDURE IF EXISTS matchTables; 
DELIMITER | 
CREATE PROCEDURE matchTables(
    IN TAB1 VARCHAR(25), 
    IN TAB2 VARCHAR(25), 
    IN COLS1 VARCHAR(250), 
    IN COLS2 VARCHAR(250) 
) 
BEGIN 
    SET @col1Values = COLS1; 
    SET @col2Values = COLS2; 
    SET @whereClause = ' WHERE '; 
    SET @anotherCondition = ''; 

    WHILE (LOCATE('#', @col1Values) > 0) 
    DO 
     SET @value1 = SUBSTRING(@col1Values, 1, LOCATE('#', @col1Values) - 1); 
     SET @value2 = SUBSTRING(@col2Values, 1, LOCATE('#', @col2Values) - 1); 
     SET @col1Values = SUBSTRING(@col1Values, LOCATE('#', @col1Values) + 1); 
     SET @col2Values = SUBSTRING(@col2Values, LOCATE('#', @col2Values) + 1); 

     SET @whereClause = CONCAT(@whereClause, @anotherCondition, TAB1, '.', @value1, ' = ', TAB2, '.', @value2, ' '); 
     SET @anotherCondition = ' AND '; 
    END WHILE; 

    SET @value1 = SUBSTRING(@col1Values, 1, LENGTH(@col1Values)); 
    SET @value2 = SUBSTRING(@col2Values, 1, LENGTH(@col2Values)); 
    SET @whereClause = CONCAT(@whereClause, @anotherCondition, TAB1, '.', @value1, ' = ', TAB2, '.', @value2, ' '); 

    SET @qry = CONCAT('SELECT * FROM ', TAB1, ', ', TAB2, @whereClause); 
    PREPARE stmt1 FROM @qry; 
    EXECUTE stmt1; 
    DEALLOCATE PREPARE stmt1; 

END| 
DELIMITER ; 
+0

Substring_index là lựa chọn tốt hơn so với việc sử dụng kết hợp chuỗi con, định vị và độ dài - liên kết được cung cấp bởi @Mark Amery cho biết cách thực hiện điều này. Substring_index quan tâm đến các lần xuất hiện của chuỗi tìm kiếm và có thể thực hiện tìm kiếm theo cả hai hướng - nhúng một chuỗi con trong chuỗi khác có thể trích xuất chuỗi con theo cách vị trí. – RMathis

1

MySQL không bao gồm chức năng tách chuỗi được phân tách. Tuy nhiên, rất dễ dàng để tạo ra chức năng của riêng bạn.

tài xác định chức năng:

CREATE [AGGREGATE] FUNCTION function_name 
RETURNS {STRING|INTEGER|REAL|DECIMAL} 

Chức năng:

CREATE FUNCTION SPLIT_STR(
    x VARCHAR(255), 
    delim VARCHAR(12), 
    pos INT 
) 
RETURNS VARCHAR(255) 
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos), 
     LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1), 
     delim, ''); 

Cách sử dụng:

SELECT SPLIT_STR(string, delimiter, position) 
1

trả lời

Bảng 1

CREATE TABLE `Table1` (
    `Col1` varchar(100) DEFAULT NULL, 
    `Col2` varchar(100) DEFAULT NULL, 
    `Col3` varchar(100) DEFAULT NULL, 
    `Col4` varchar(100) DEFAULT NULL, 
    `DummyColumn` varchar(45) DEFAULT NULL 
) 

Bảng 2

CREATE TABLE `Table2` (
    `col2` varchar(100) DEFAULT NULL, 
    `col13` varchar(100) DEFAULT NULL, 
    `col1` varchar(100) DEFAULT NULL, 
    `col8` varchar(100) DEFAULT NULL 
) 

Stored Procedure

CREATE DEFINER=`Connect7827`@`%` PROCEDURE `reconcile.matchTables`(
IN TAB1 VARCHAR(25), 
    IN TAB2 VARCHAR(25), 
    IN COLS1 VARCHAR(250) , 
    IN COLS2 VARCHAR(250)) 
StartfromHere: BEGIN 


     DECLARE NoOfColumnInTable1 INT unsigned DEFAULT 0; 
     DECLARE NoOfColumnInTable2 INT unsigned DEFAULT 0; 
     Declare Column1Count int default 1; 
     Declare Column2Count int default 1; 
     Declare vPickOneValue varchar(100); 
     Declare querystring varchar(8000); 
     Declare NoOFRowsInFinalResult int default 1; 
     Declare _Tab1 varchar(1000); 
     Declare _TAB2 varchar(1000); 
     Declare _COLS1 varchar(1000); 
     Declare _COLS2 varchar(1000); 


     -- Column Names for Table 1 
     DROP TEMPORARY TABLE IF EXISTS Table1_Columns; 
     CREATE TEMPORARY TABLE Table1_Columns(Column_Name varchar(100)); 
     SET @buffer= CONCAT_WS('','insert into Table1_Columns(Column_Name) 
     SELECT COLUMN_NAME 
     FROM INFORMATION_SCHEMA.COLUMNS 
     WHERE table_name = ',"'",TAB1,"'"); 
     -- Select @buffer; 
     PREPARE stmt FROM @buffer; 
     EXECUTE stmt; 
     -- Column Names for Table 2 
     DROP TEMPORARY TABLE IF EXISTS Table2_Columns; 
     CREATE TEMPORARY TABLE Table2_Columns(Column_Name varchar(100)); 
     SET @buffer= CONCAT_WS('','insert into Table2_Columns(Column_Name) 
     SELECT COLUMN_NAME 
     FROM INFORMATION_SCHEMA.COLUMNS 
     WHERE table_name = ',"'",TAB2,"'"); 
     -- Select @buffer; 
     PREPARE stmt FROM @buffer; 
     EXECUTE stmt; 

     Set NoOfColumnInTable1=(Select count(*) from Table1_Columns); 
     Set NoOfColumnInTable2=(Select count(*) from Table2_Columns); 

     -- Select NoOfColumnInTable1,NoOfColumnInTable2; 
     if (NoOfColumnInTable1=0) then 
      Select 'Table 1 not found in database'as'Result'; 
      leave StartfromHere; 
     end if; 
     if (NoOfColumnInTable2=0) then 
      Select 'Table 2 not found in database' as'Result' ; 
      leave StartfromHere; 
     end if; 
     IF (NoOfColumnInTable1!=NoOfColumnInTable2) then 
      Select 'No of column to be joined must be equal.'as'Result'; 
      leave StartfromHere; 
     end if; 

     DROP TEMPORARY TABLE IF EXISTS BasedOn_Col1_List; 
     CREATE TEMPORARY TABLE BasedOn_Col1_List(ID int NOT NULL AUTO_INCREMENT, Column_Name varchar(100), PRIMARY KEY (id)); 
     while Column1Count< NoOfColumnInTable1+1 do 
       set @Query=CONCAT_WS('' ,"insert into BasedOn_Col1_List(Column_Name) Select SUBSTRING_Index('",COLS1,"','#',",Column1Count,");"); 
       -- Select @Query as'Value'; 
       PREPARE stmt1 FROM @Query; 
       EXECUTE stmt1; 
       SET Column1Count=Column1Count+1; 
     end while; 
     SET Column1Count=1; 
     WHILE Column1Count<=NoOfColumnInTable1 do 
      SET vPickOneValue=(Select Concat(Column_Name,"#") from BasedOn_Col1_List where ID=Column1Count); 
      update BasedOn_Col1_List set Column_Name=replace(Column_Name,vPickOneValue,"") where ID<>Column1Count; 
      -- Select vPickOneValue; 
      SET Column1Count=Column1Count+1 ; 
     end while; 

     -- Preapre Table from Column2 Parameter 
     DROP TEMPORARY TABLE IF EXISTS BasedOn_Col2_List; 
     CREATE TEMPORARY TABLE BasedOn_Col2_List(ID int NOT NULL AUTO_INCREMENT, Column_Name varchar(100), PRIMARY KEY (id)); 
     while Column2Count< NoOfColumnInTable2+1 do 
       set @Query=CONCAT_WS('' ,"insert into BasedOn_Col2_List(Column_Name) Select SUBSTRING_Index('",COLS2,"','#',",Column2Count,");"); 
       -- Select @Query as'Value'; 
       PREPARE stmt2 FROM @Query; 
       EXECUTE stmt2; 
       SET Column2Count=Column2Count+1; 
     end while; 
     SET Column2Count=1; 
     WHILE Column2Count<=NoOfColumnInTable2 do 
      SET vPickOneValue=(Select Concat(Column_Name,"#") from BasedOn_Col2_List where ID=Column2Count); 
      update BasedOn_Col2_List set Column_Name=replace(Column_Name,vPickOneValue,"") where ID<>Column2Count; 
      -- Select vPickOneValue; 
      SET Column2Count=Column2Count+1 ; 
     end while; 

     DROP TEMPORARY TABLE IF EXISTS TableFromColumnList; 
     CREATE TEMPORARY TABLE TableFromColumnList 
        ( ID int NOT NULL AUTO_INCREMENT, 
         Table1Name varchar(100), 
         Column_Name_Table1 varchar(100), 
         Table2Name varchar(1000), 
         Column_Name_Table2 varchar(100), 
         PRIMARY KEY (id) 
        ); 
     Insert into TableFromColumnList(Column_Name_Table1,Column_Name_Table2,Table1Name,Table2Name)  
     select t1.Column_Name,t2.Column_Name,TAB1,TAB2 
     from BasedOn_Col1_List t1 , BasedOn_Col2_List t2 where t1.Id=t2.id;   


     -- -- Preparing the final Result ---------------- 
     While NoOFRowsInFinalResult<=NoOfColumnInTable2 do --/Or NoOFRowsInFinalResult<=NoOfColumnInTable2 -- 

      SET _Tab1 =(Select Table1Name from TableFromColumnList where Id=NoOFRowsInFinalResult); 
      SET _COLS1 =(Select Column_Name_Table1 from TableFromColumnList where Id=NoOFRowsInFinalResult); 
      SET _TAB2 =(Select Table2Name from TableFromColumnList where Id=NoOFRowsInFinalResult); 
      SET _COLS2 =(Select Column_Name_Table2 from TableFromColumnList where Id=NoOFRowsInFinalResult); 

      IF NoOFRowsInFinalResult=1 then 
       SET querystring =concat_ws("" , querystring,_Tab1,".", _COLS1 , "=",_Tab2,".", _COLS2," "); 
      else 
       SET querystring =concat_ws("" , querystring ,"and",_Tab1,".", _COLS1 , "=" ,_Tab2,".", _COLS2 ," "); 
      end if; 

      SET NoOFRowsInFinalResult=NoOFRowsInFinalResult+1 ; 
     End while; 
     SET querystring=concat_ws("","Select * from ",TAB1,", " ,TAB2," where ",querystring); 
     Select querystring; 

END 
+1

Giả định: DataTypes của các cột được ánh xạ trong cả hai bảng phải giống nhau. –

0
CREATE PROCEDURE matchTables 
@TAB1 VARCHAR(25), 
@TAB2 VARCHAR(25), 
@COLS1 VARCHAR(250) , 
@COLS2 VARCHAR(250) 

AS 


BEGIN 
DECLARE @WHEREstring VARCHAR(MAX) 
SET @WHEREstring = 
' 
WHERE 
     ' 
SELECT @WHEREstring = @WHEREstring + @TAB1 +'.'+ tab1.col+' = '[email protected]+'.' + tab2.col +' AND 
     ' 
      FROM 
      (
       SELECT QUOTENAME(split.a.value('.','VARCHAR(100)')) AS col, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNum 
        FROM 
        (
         SELECT Cast ('<M>' + Replace(@COLS1, '#', '</M><M>')+ '</M>' AS XML) AS Tab1Data 
        ) AS A 
        CROSS apply Tab1Data.nodes ('/M') AS Split(a) 
      ) tab1 
      INNER JOIN 
      (
       Select QUOTENAME(AliasSplit.c.value('.', 'varchar(100)')) AS col, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNum 
       FROM 
       (
        SELECT Cast ('<A>' + Replace(@COLS2, '#', '</A><A>')+ '</A>' AS XML) AS Tab2Data 
       ) AS A 
       CROSS apply Tab2Data.nodes ('/A') AS AliasSplit(c) 
      ) tab2 
      ON tab1.RowNum = tab2.RowNum 
     SET @WHEREstring= LEFT(@WHEREstring, LEN(@WHEREstring) - 8) 

     print @WHEREstring 
END 

Bây giờ, hãy thực hiện nó bằng cách sử :::

01.235.
EXEC matchTables 'table1', 'table2', 'col1#col2#col3#col4' , 'col2#col13#col1#col8' 

tôi hy vọng bạn nhận được mệnh đề where mong muốn. cổ vũ

0

Bạn có thể xây dựng chức năng riêng của mình: - [? Bạn có thể chia/nổ một lĩnh vực trong một truy vấn MySQL]

CREATE FUNCTION String_split(inp VARCHAR(255),del VARCHAR(255),loc INT) 
RETURNS VARCHAR(255) 
RETURN REPLACE(Substring(Substring_index(inp, del,loc),LENGTH(Substring_index(inp, del, loc-1)) + 1),del, ''); 
-1

CHAR_LENGTH trở lại chiều dài đúng trong chars

CREATE FUNCTION SPLIT_STR(
    x VARCHAR(255), 
    delim VARCHAR(12), 
    pos INT 
) 
RETURNS VARCHAR(255) 
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos), 
     CHAR_LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1), 
     delim, ''); 
Các vấn đề liên quan