2010-10-12 65 views
23

我想创建一个存储过程,它将执行两个表的匹配。我的要求是根据列用户传递作为输入匹配两个表。使用mysql分割字符串

语法:

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') 

现在存储过程应成为其中类似以下

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

的可能的复制( http://stackoverflow.com/questions/471914/can-you-split-explode-a-field-in-a-mysql-query) – 2017-04-01 12:25:32

+1

我有一个愚蠢的问题:由于用户输入两个参数(两个列表列),为什么不让她插入8个参数(每列一个)?这些列的数量是可变的吗? – 2017-05-02 15:20:21

回答

-1

条款有没有功能小号切分字符串。你可以这样做:

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是比使用子字符串,定位和长度组合更好的选择 - 由@Mark Amery提供的链接显示了这是如何完成的。 Substring_index关心搜索字符串的出现并且可以在两个方向上执行搜索 - 在另一个方向中嵌入substring_index可以以位置方式提取子字符串。 – RMathis 2017-04-05 13:28:39

1

MySQL不包括功能拆分分隔的字符串。但是,创建自己的功能非常简单。

用户定义函数:

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

功能:

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, ''); 

用法:

SELECT SPLIT_STR(string, delimiter, position) 
1

回答

表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 
) 

表2

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

存储过程

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

假设:要在两个表中映射的列的DataType必须相同。 – 2017-05-12 10:47:07

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 

现在,执行它使用:::

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

我希望你能得到所需的where子句。欢呼声

0

你可以建立自己的函数: - [?在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在字符返回正确的长度

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, '');