SQL Query for Joining Tables Using A Columns Splitted Strings
Here's what I'm trying to do.
I have these:
Table1:
Name | Surname | Age | Location | ContactPeopleIds
John | Cobaing | 25 | Turkey | 1234,1512,1661, 2366,
Jack | Maltean | 29 | Italy | 6155,2333,1633,
Table2:
ID | Name | LastName | Location
1234 | Meg | Ryan | US
1512 | Jesy | Jade | US
1661 | John | Kradel | US
2366 | Jack | Abdona | Nigeria
TableIWant
Name | Surname | Age | Location | ContactPeopleNames
John | Cobaing | 25 | Turkey | Meg Ryan, Jesy Jade, John Kradel, Jack Abdona
I have found a splitter function called fn_ParseText2Table(data, splitter) that creates a table from the data splitted with splitter char. (Reference here)
For example:
select *
from dbo.fn_Pa开发者_开发百科rseText2Table('1234,1512,1661,2366', ',')
function produces:
int_value | num_value | txt_value
null | null | 1234
null | null | 1512
null | null | 1661
null | null | 2366
But I couldn't create a query using this.
I'm not sure to use t-sql or not. I've tried to use common table expression but couldn't manage that either.
If you can provide multiple solutions, it would be very kind to provide detail about their performance value differences.
ok...
When you suggested that you'd tried a CTE you where heading in the right direction.
What you need to do however is chain 3 CTE's together. Once you have the processing chain you then need to progressively pass things through it like a filter, first splitting the ID's into a column of ints, then joining the ints on table2 to get the names, then recombining those names.
As has been previously mentioned, whoever designed this designed it badly, but assuming your using MS-SQL server and T-SQL the following code will do what you need it to:
DECLARE @tempString AS varchar(max)
SET @tempString =''
;WITH firstCte AS
(
SELECT
CAST('<M>' + REPLACE(contactpeopleids, ',','</M><M>') + '</M>' AS XML) AS Names
FROM
soTable1
-- THIS WHERE CLAUSE MUST MATCH THE FINAL WHERE CLAUSE
WHERE
name = 'John'
AND surname = 'Cobaing'
)
,secondCte AS
(
SELECT
Split.a.value('.','VARCHAR(100)') AS NameIds
FROM
firstCte
CROSS APPLY Names.nodes('/M') Split(a)
)
,thirdCte AS
(
SELECT
t2.name + ' ' + t2.lastname AS theContactName
FROM
secondCte t1
-- NOTE: IF THE IDS YOU EXTRACT FROM TABLE 1 DO NOT HAVE A MATCH IN TABLE 2 YOU WILL GET NO RESULT FOR THAT ID HERE!
-- IF YOU WANT NULL RESULTS CHANGE THIS TO A 'LEFT JOIN'
INNER JOIN
soTable2 t2 ON t1.NameIds = t2.id
)
SELECT
@tempString = @tempString + ',' + theContactName
FROM
thirdCte
;
-- The select substring is used to remove the leading ','
SELECT
name,
surname,
age,
location,
SUBSTRING(@tempString,2,LEN(@tempString)) AS contactpeoplenames
FROM
soTable1
WHERE
name = 'John'
AND surname = 'Cobaing'
It's probably not as elegant as it could be, and for ease of use you might want to wrap it up in a user defined function and pass the firstname and surname of the person to look up into it. If you do it that way, then you can use the function in a regular SQL select query to return rows direct out of table 1 into a view or another table.
The fun part of it all is actually the way in which we trick SQL server into splitting the string. You'll notice that we actually replace the ',' with XML tags, then use the XML processing functions to make SQL server think that we are processing an XML string.
SQL Server has had great routines for doing this kind of task sing the 2005 version, and allows for whole blocks of XML to be serialised and de-serialised to/from a varchar field directly in your db table, by making SQL server think it's dealing with XML it does most of the hard work for us.
**NORMALIZED EXAMPLE OF SELF REFERENCING ONE TO MANY RELATIONSHIP**
Study this example, must apply to yur case, made it fast (and is not fianl code, for example no meassure taken on mysql failure)
Put mysql host username and password..
<?PHP
echo '<pre>';
//mysql connect
mysql_connect('localhost', 'root','');
mysql_select_db("test");
//add some tsting data
addTestingData();
//suppose this come from a user
$_POST['user_id']=1;
//get all contacts of user with id = 1
$sql =
"SELECT `tbl_users`.`user_id`, `user_name`,
`user_surname`,`user_location` from `tbl_users`
LEFT JOIN `tbl_user_contacts`
ON `tbl_users`.`user_id`=`tbl_user_contacts`.`contact`
where `tbl_user_contacts`.`user_id`=".
mysql_real_escape_string($_POST['user_id'])." ";
//get data from mysql
$result = mysql_query($sql ) ;
while($row= mysql_fetch_row($result) )
print_r( $row );
///////////////end////////////////////////////////////////////
function addTestingData()
{
mysql_query("DROP TABLE IF EXISTS `tbl_users`");
mysql_query("
CREATE TABLE `tbl_users` (
`user_id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT ,
`user_name` VARCHAR(50) NOT NULL,
`user_surname` VARCHAR(50) NOT NULL,
`user_location` VARCHAR(50) NOT NULL,
`user_age` smallint not null,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
");
for($i=1;$i<21;$i++) {
mysql_query("
insert into `tbl_users` (`user_name`,`user_surname`,`user_location`,
`user_age` ) values
('name{$i}','surname{$i}', 'location{$i}', '{$i}' ) ") ;
}
mysql_query("DROP TABLE IF EXISTS `tbl_user_contacts`");
mysql_query("
CREATE TABLE `tbl_user_contacts` (
`user_id` MEDIUMINT UNSIGNED NOT NULL ,
`contact` MEDIUMINT UNSIGNED NOT NULL ,
`other_field_testing` VARCHAR(30) NOT NULL,
PRIMARY KEY (`user_id`,`contact`),
CONSTRAINT `tbl_contact_fk1` FOREIGN KEY (`user_id`)
REFERENCES `tbl_users` (`user_id`)
ON DELETE CASCADE ,
CONSTRAINT `tbl_contact_fk2` FOREIGN KEY (`contact`)
REFERENCES `tbl_users` (`user_id`)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
");
$tmp=array();//help avoid dupicate entries while testing
for($i=1;$i<99;$i++) {
$contact=rand(1,20);
$user_id=rand(1,20);
if(!in_array($contact.$user_id,$tmp))
{
$tmp[]=$contact.$user_id;
mysql_query("
insert into `tbl_user_contacts` (`user_id`,`contact`,`other_field_testing` )
values ('{$user_id}','{$contact}','optinal-testing') ") ;
}//end of if
}//end of for
}//end of function
?>
精彩评论