2011-10-13 224 views
2

我有2个表如下:JOINING逗号分隔值

TABLE:CITY 

CITY_ID CITY 
---------------- 
1 London 

2 Chicago 

3 Newyork 

4 Delhi 


TABLE:TRAIN 

TRAIN_ID CITY_TRAVELS 
---------------------- 
1111   1,3 

2222   4 

3333   1,2 

4444   2,3 

我想要写的查询应该得到下面的结果: 另外CITY_TRAVELS在TRAIN表的类型是VARCHAR 和CITY_ID的CITY表是INT类型。 查询结构将如何?

TRAIN_ID CITY 
------------------------- 
1111  London,Newyork 

2222  Delhi 

3333  London,Chicago 

4444  Chicago,Newyork 

感谢 萨蒂亚吉特

+8

最近几个专栏中的所有CSV数据都是如此。仅供参考,你做错了。在“TRAIN”表中丢失“CITY_TRAVELS”列,并用“TRAIN_ID”和“CITY_ID”列创建另一个表“TRAIN_CITY”。请参阅http://en.wikipedia.org/wiki/Junction_table – Phil

+7

为什么用逗号分隔的废话违反数据库设计的所有原则?存储的旅行正常化,然后你不必去写疯狂的查询,永远不会执行 – SQLMenace

+3

*“设计是不是很棒”*是一个**史诗**轻描淡写 – Phil

回答

4
-- sample data 
declare @City table 
(
    CityID int, 
    City varchar(50) 
) 

declare @Train table 
(
    TrainID int, 
    CityTravels varchar(50) 
) 

insert into @City 
select 1, 'London' 
union all 
select 2, 'Chicago' 
union all 
select 3, 'Newyork' 
union all 
select 4, 'Delhi' 

insert into @Train 
select 1111, '1,3' 
union all 
select 2222, '4' 
union all 
select 3333, '1,2' 
union all 
select 4444, '2,3' 


-- solution 
;with cte as 
(
    select 
     t1.TrainID, t2.City 
    from 
    (
     select 
      TrainID, 
      -- t2.c - the xml tag that function nodes provides 
      -- query('data(.)') gets the value of the tag 
      CityID = cast(cast(t2.c.query('data(.)') as varchar) as int) 
     from 
     (
      select 
       TrainID, 
       -- represent Cities list in the xml, 
       -- which is proper for xquery node function 
       -- for example <root><a>1</a><a>2</a></root> 
       CityTravelsXml = cast('<root><a>' + replace(CityTravels, ',', '</a><a>') + '</a></root>' as xml) 
      from @Train 
     ) t1 
     -- xquery nodes function for each tag /root/a returns a separate row 
     -- with single column the represents the tag 
     cross apply CityTravelsXml.nodes('/root/a') t2(c) 
    ) t1 
    join @City t2 on t1.CityID = t2.CityID 
) 


select 
    TrainID, 
    -- truncate the last comma 
    Cities = case when Cities is not null then substring(Cities, 1, len(Cities) - 1) end 
from 
(
    select 
     TrainID, 
     Cities = 
     (
      -- for xml here concatenates strings in a column 
      select 
       City + ',' 
      from cte t2 
      where t2.TrainID = t1.TrainID 
      for xml path('') 
     ) 
    from @Train t1 
) t 

编辑:删除第二个解决方案,因为一些测试后显示性能不合适,inspite它具有表少引用。

+0

我的头想要爆炸......但它*确实*“回答”了问题,所以+1。 – 2011-10-14 01:27:24

+0

+1进行测试。伟大的工作,Leha。 –

+0

不可扩展......当波士顿下周加入时会发生什么。 –

5

以及结构是可怕的,但你可以在一些UDF解析逗号分隔字符串,并使用子查询加入号码城市。希望文章"Split Function in Sql Server to break Comma-Separated Strings into Table"会帮助你!

+1

+1我喜欢这样。这是“糟糕的现有解决方案”抽象的好方法。 – 2011-10-14 00:37:51

+0

这只是解决方案的一半...... OP仍然需要将名称重新组合在一起。 –

1
create database train 

create table city(
city_id int identity(1,1), 
city varchar(max) 
) 

create table train(
train_id int identity(1111,1111), 
city_travels varchar(max) 
) 

insert into city values ('London'); 
insert into city values ('Chicago'); 
insert into city values ('NewYork'); 
insert into city values ('Delhi'); 

insert into train values ('1,3,4'); 
insert into train values ('4'); 
insert into train values ('1,2'); 
insert into train values ('1,2,3,4'); 

create table #train(
train_id int, 
city varchar(max) 
) 
declare @count int, @id int,@first int; 
declare @train_id int,@index int; 
declare @city_travels varchar(max),@city_name varchar(max); 
set @city_name=null; 

declare train_cursor CURSOR for 
select train_id,city_travels from train 
open train_cursor 
fetch next from train_cursor into @train_id,@city_travels 

    while (@@fetch_status=0) 
    begin 
     set @first=0; 
     set @index = charindex(',',@city_travels); 
      if(@index!=0) 
      begin 
       if(@first=0) 
       begin 
        set @id=convert (int,substring(@city_travels,1,@index-1)); 
        set @city_travels=substring(@city_travels,@index+1,len(@city_travels)); 
        set @city_name=((select city from city where [email protected])+','); 
        set @index=charindex(',',@city_travels); 
        set @first=1; 
       end 
       while(@index!=0) 
       begin 
        set @id=convert (int,substring(@city_travels,1,@index-1)); 
        set @city_travels=substring(@city_travels,@index+1,len(@city_travels)); 
        set @index=charindex(',',@city_travels) 
        set @city_name=(@city_name+(select city from city where [email protected])+','); 
       end 
      set @id=convert (int,@city_travels); 
      set @city_name=(@city_name+(select city from city where [email protected])); 
      insert into #train values (@train_id,@city_name); 
      set @city_name=null; 
      end 
     else 
     begin 
      set @id=convert (int,@city_travels); 
      set @city_name=(select city from city where [email protected]); 
      insert into #train values (@train_id,@city_name); 
      set @city_name=null; 
     end 
    fetch next from train_cursor into @train_id,@city_travels 
    end 
select * from city; 
select * from train; 
select * from #train; 
close train_cursor 
deallocate train_cursor 
truncate table #train