Сплит-строки с использованием 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')
Теперь хранимая процедура должна сформировать предложение where, как показано ниже.
table1.col1 = table2.col2
and table1.col2 = table2.col13
and table1.col3 = table2.col1
and table1.col4 = table2.col8
Ответы
Ответ 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)
Ответ 2
Ответ
Таблица 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
Ответ 3
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. приветствия
Ответ 4
Вы можете создать свою собственную функцию:
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, '');
Ответ 5
Нет никакой функции для разбиения строки. Вы можете сделать следующее:
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 ;
Ответ 6
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, '');