使用不同的数据类型连接表

时间:2012-10-04 13:58:02

标签: sql-server join sql-function

我有以下表格:

Orders
  id int
  orderName varchar(5000)

Communication
  body varchar(5000)
  attachment varchar(5000)

样品订单数据:

id   name
132  ordGD
589  ordPG
6321 ordMF

示例通讯数据:

body    attachment
body1   132,589,6321

我想创建一个存储过程,从Communication

获取2列{body,Attachment}

在SP中,输入@attachment varchar(5000)包含多个orderid,逗号分隔,引用Orders表

问题:我希望OrderName根据与@Attachment匹配的订单中的Orderid

2 个答案:

答案 0 :(得分:1)

对于此类流程,您需要split attachment列中的数据。我使用与Split字符串类似的东西(有很多方法可以分割字符串,你可以在线搜索其他函数):

CREATE FUNCTION [dbo].[Split](@String varchar(MAX), @Delimiter char(1))       
returns @temptable TABLE (items varchar(MAX))       
as       
begin     
    declare @idx int       
    declare @slice varchar(8000)       

    select @idx = 1       
        if len(@String)<1 or @String is null  return       

    while @idx!= 0       
    begin       
        set @idx = charindex(@Delimiter,@String)       
        if @idx!=0       
            set @slice = left(@String,@idx - 1)       
        else       
            set @slice = @String       

        if(len(@slice)>0)  
            insert into @temptable(Items) values(@slice)       

        set @String = right(@String,len(@String) - @idx)       
        if len(@String) = 0 break       
    end   
return      

end

由于这会返回一个表,您可以加入数据。所以你的查询看起来像这样:

select o.id,
  o.name,
  c.body
from orders o
left join 
(
  select c.body, s.items as o_id
  from communications c
  cross apply dbo.split(c.attachment, ',') s
) c
  on o.id = c.o_id

请参阅SQL Fiddle With Demo

如果您只想使用正确的名称替换attachment字段中的值,则可以一步使用Split函数和CTE

;with cte as (
  select o.id,
    o.name,
    c.body
  from orders o
  left join 
  (
    select c.body, s.items as o_id
    from communications c
    cross apply dbo.split(c.attachment, ',') s
  ) c
    on o.id = c.o_id
)
select distinct c2.body,
  stuff((select distinct ', ' + c1.name
         from cte c1
         where c2.body = c1.body
         for XML path('')),1,1,'') attachment
from cte c2

请参阅SQL Fiddle with Demo

答案 1 :(得分:1)

正如其他人所评论的那样,正确的解决方案是将数据库模式更改为具有原子字段的规范化模式。

当前架构的解决方案是首先使用任何multiple ways available将附件字段拆分为订单号列表。下一步是将结果与id上的Orders表连接以获得结果。第三步是concatenate the names back into a list。请参阅提供的链接以了解拆分和加入的说明。

以下是执行3个步骤的代码段:

WITH
-- Numbers table for split logic
L0 AS(SELECT 1 AS c UNION ALL SELECT 1),
L1 AS(SELECT 1 AS c FROM L0 AS A, L0 AS B),
L2 AS(SELECT 1 AS c FROM L1 AS A, L1 AS B),
L3 AS(SELECT 1 AS c FROM L2 AS A, L2 AS B),
Numbers AS(SELECT ROW_NUMBER() OVER(ORDER BY c) AS n FROM L3),

-- The join query for step 2
bodyOrders AS
(SELECT body,        
       o1.name orderName
FROM   Numbers AS nums 
INNER JOIN Communication AS valueTable 
ON nums.n <= CONVERT(int, LEN(valueTable.attachment)) 
AND SUBSTRING(N',' + valueTable.attachment, n, 1) = N','
INNER JOIN Orders o1
ON LTRIM(RTRIM(SUBSTRING(valueTable.attachment, nums.n, 
   charindex(N',', valueTable.attachment + N',', nums.n) - nums.n))) = o1.id
)

-- Concatenation logic for step 3
SELECT  body,
stuff( (SELECT ','+ orderName
               FROM bodyOrders b2
               WHERE b2.body = b1.body 
               ORDER BY orderName
               FOR XML PATH(''), TYPE).value('.', 'varchar(5000)')
            ,1,1,'')
       AS orderNumbers
      FROM bodyOrders b1
      GROUP BY body;

此代码段未提供针对大型数据集执行此操作的最佳或高效方法。这只是一个例子,说明如果你必须沿着这条路走下去的话。

Example SQL Fiddle