-1

我有以下表格:

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

我想创建一个存储过程,从中获取 2 列 {body,Attachment}Communication

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

问题:我想要 OrderName 根据 Orderid 从 Orders 匹配到@Attachment

4

2 回答 2

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

如果您只想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

于 2012-10-04T16:47:47.630 回答
1

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

当前模式的解决方案是首先使用多种可用方法中的任何一种将附件字段拆分为订单号列表。下一步是将结果与 id 上的 Orders 表连接起来以获取结果。第三步是将名称连接回列表。有关拆分和连接的说明,请参阅提供的链接。

这是执行 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;

此代码段没有为大型数据集提供最佳或高效的方式来执行此操作。如果您必须走这条路,这只是一个示例。

示例 SQL 小提琴

于 2012-10-04T17:06:48.097 回答