1

我的数据库中的一个表包含如下值,

               TBLFlow
FlowId         FlowName           ProcessId
------------------------------------------------
F00             Flow1         PID01-PID02-PID03

F01             Flow2         PID01-PID03-PID02

进程的名称列在另一个表中,如下所示,

       TBLProcess
ProcessId     ProcessName
---------------------------
 PID01         Process1
 PID02         Process2
 PID03         Process3

现在,我想拆分表“TBLFlow”中的值,以便通过在两个表之间执行连接(最好是“内部连接”)从表“TBLProcess”中获取它们的名称。最后,当我执行查询时,我希望结果如下,

FlowId         FlowName         ProcessId               ProcessName
------------------------------------------------------------------------------
 F01            Flow1        PID01-PID02-PID03     Process1-Process2-Process3 
 F01            Flow1        PID01-PID03-PID02     Process1-Process3-Process2 

我正在使用 SQL Server 2008 并希望在单个存储过程中执行此操作。您能帮我解决在存储过程中编写的查询吗?

编辑:

表“TBLFlow”可以重构如下,

               TBLFlow
FlowId         FlowName           ProcessId
------------------------------------------------
F00             Flow1               PID01

F00             Flow1               PID02

F00             Flow1               PID03

F01             Flow2               PID01

F01             Flow2               PID03

F01             Flow2               PID02
4

3 回答 3

2

我想象过这样的怪物

DECLARE @TBLFlow table (FlowId varchar(20), FlowName varchar(100), ProcessId varchar(1000))
DECLARE @TBLProcess table (ProcessId varchar(20), ProcessName varchar(100))
insert into @TBLFlow values ('F00','Flow1','PID01-PID02-PID03'), ('F01','Flow2','PID01-PID03-PID02')
insert into @TBLProcess values ('PID01','Process1'), ('PID02','Process2'), ('PID03','Process3')

;with c as
(
    select 
        1 as rn,
        FlowId,
        FlowName,
        CHARINDEX('-',ProcessId,1) as Pos,
        case when CHARINDEX('-',ProcessId,1)>0 then SUBSTRING(ProcessId,1,CHARINDEX('-',ProcessId,1)-1) else ProcessId end as value,
        case when CHARINDEX('-',ProcessId,1)>0 then SUBSTRING(ProcessId,CHARINDEX('-',ProcessId,1)+1,LEN(ProcessId)-CHARINDEX('-',ProcessId,1)) else '' end as ProcessId
    from @TBLFlow

    union all
    select
        rn + 1 as rn,
        FlowId,
        FlowName,
        CHARINDEX('-',ProcessId,1) as Pos,
        case when CHARINDEX('-',ProcessId,1)>0 then SUBSTRING(ProcessId,1,CHARINDEX('-',ProcessId,1)-1) else ProcessId end as Value,
        case when CHARINDEX('-',ProcessId,1)>0 then SUBSTRING(ProcessId,CHARINDEX('-',ProcessId,1)+1,LEN(ProcessId)-CHARINDEX('-',ProcessId,1)) else '' end as ProcessId
    from c
    where LEN(ProcessId)>0
)
select
    f.FlowId,
    f.FlowName,
    f.ProcessId,
    stuff(
        (
            select '-'+p.ProcessName
            from c
            inner join @TBLProcess p on p.ProcessId=c.value
            where c.flowid=f.flowid
            order by c.rn
            FOR XML PATH('')
        ),
        1,
        1,
        ''
    ) as ProcessName
from @TBLFlow f
于 2013-06-18T14:00:51.867 回答
0

你可以试试这个

SELECT F.*,ISNULL(P1.ProcessName,'') + '-' + ISNULL(P2.ProcessName,'') + '-' +  
ISNULL(P3.ProcessName,'')
FROM TBLFlow AS F
LEFT JOIN TBLProcess AS P1
ON   SUBSTRING(F.ProcessId,0,CHARINDEX('-',F.ProcessId)) = P1.ProcessId
LEFT JOIN TBLProcess AS P2
ON LEFT(RIGHT(F.ProcessId,LEN(F.ProcessId)-CHARINDEX('-',F.ProcessId,1)),
CHARINDEX('-   ',RIGHT(F.ProcessId,LEN(F.ProcessId)-
CHARINDEX('-',F.ProcessId,1)),1)-1) 
= P2.ProcessId
LEFT JOIN TBLProcess AS P3
ON SUBSTRING(F.ProcessId, LEN(RIGHT(F.ProcessId,LEN(F.ProcessId)-
CHARINDEX('-',F.ProcessId))) + 2,LEN(F.ProcessId)) = P3.ProcessId
于 2013-06-18T14:03:43.717 回答
0

看起来您正在要求两个单独的查询,一个是使用ProcessID列中的非规范化数据来解决您的原始表,然后是第二个查询(如果tblFlow数据是规范化的)。

tblFlow 非规范化查询

如果您无法规范化tblFlow表中的数据,这意味着您将数据存储在列表中,并用破折号 ( PID01-PID02-PID03) 分隔。然后我将按照以下方式进行。

首先,我将创建一个拆分字符串用户定义的函数,它将ProcessId字符串分成多个列。网上有很多功能,但这是我通常使用的功能:

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;

一旦你创建了函数。然后你会查询使用CROSS APPLYprocessId列表传递给函数。查询将是:

;with cte as
(
  select f.flowid, f.flowname, f.processid, s.items processItem
  from tblFlow f
  cross apply dbo.Split(f.processid, '-') s
) 
select *
from cte;

请参阅SQL Fiddle with Demo。这给出了一个结果:

| FLOWID | FLOWNAME |         PROCESSID | PROCESSITEM |
-------------------------------------------------------
|    F00 |    Flow1 | PID01-PID02-PID03 |       PID01 |
|    F00 |    Flow1 | PID01-PID02-PID03 |       PID02 |
|    F00 |    Flow1 | PID01-PID02-PID03 |       PID03 |
|    F01 |    Flow2 | PID01-PID03-PID02 |       PID01 |
|    F01 |    Flow2 | PID01-PID03-PID02 |       PID03 |
|    F01 |    Flow2 | PID01-PID03-PID02 |       PID02 |

ProcessItem数据拆分为行后,您就可以轻松地连接到现有表并生成新的ProcessNames. 要创建串联列表,您可以使用FOR XML PATH和 STUFF。查询将是:

;with cte as
(
  select f.flowid, f.flowname, f.processid, s.items processItem
  from tblFlow f
  cross apply dbo.Split(f.processid, '-') s
) 
select distinct c.flowid,
  c.flowname,
  c.processid,
  STUFF(
         (SELECT '-' + p.ProcessName
          FROM cte c2
          inner join tblProcess p
            on c2.processItem = p.processId
          where c.flowid = c2.flowid
          FOR XML PATH (''))
          , 1, 1, '')  AS ProcessName
from cte c;

请参阅SQL Fiddle with Demo。这给出了一个结果:

| FLOWID | FLOWNAME |         PROCESSID |                PROCESSNAME |
----------------------------------------------------------------------
|    F00 |    Flow1 | PID01-PID02-PID03 | Process1-Process2-Process3 |
|    F01 |    Flow2 | PID01-PID03-PID02 | Process1-Process2-Process3 |

标准化 tblFlow

现在,如果tblFlow数据已经规范化并且您想要创建两个连接列表,一个带有processId,另一个带有processName,那么您可以使用以下内容:

select distinct f.flowid,
  f.flowname,
  STUFF(
         (SELECT '-' + f1.Processid
          FROM tblFlow f1
          where f.flowid = f1.flowid
          FOR XML PATH (''))
          , 1, 1, '')  AS Processid,
  STUFF(
         (SELECT '-' + p.ProcessName
          FROM tblFlow f1
          inner join tblProcess p
            on f1.ProcessId = p.ProcessId
          where f.flowid = f1.flowid
          FOR XML PATH (''))
          , 1, 1, '')  AS ProcessName
from tblFlow f;

请参阅SQL Fiddle with Demo。这会产生一个结果:

| FLOWID | FLOWNAME |         PROCESSID |                PROCESSNAME |
----------------------------------------------------------------------
|    F00 |    Flow1 | PID01-PID02-PID03 | Process1-Process2-Process3 |
|    F01 |    Flow2 | PID01-PID03-PID02 | Process1-Process2-Process3 |
于 2013-06-19T04:00:39.053 回答