【问题标题】:Compare comma separated rows比较逗号分隔的行
【发布时间】:2013-09-03 06:19:51
【问题描述】:

我有一个要求,我应该将第一行与以前的数据库记录行进行比较,它们是逗号分隔的。 例子 : 我的表格数据如下所示:

      ID   Phase                Updated By
      1    Test1,Test2,Test3    sxmalla
      2    Test1,Test2          rkgauta
      3    Test1,Test3          sxmalla

我必须在 Phase 中显示最近的更改以及更新的人员。逗号分隔的数据在前端使用多个复选框提交。用户可以通过同一页面中的多个复选框来更新它们。 这里 Test3 是最近的更改,然后在 Test2 下面是最近的更改,第三行是实际的第一个条目。

我需要将结果显示为

      Phase        Updated By
      Test3        sxmalla
      Test2        rkgauta
      Test1,Test3  sxmalla

这是我目前用来比较 2 个逗号分隔行的代码

  ALTER Proc [dbo].[PMT_GetPhasesEditHistory]

  @Project_ID int
  As Begin
  SET NOCOUNT ON 
  Declare @added varchar(1000), @removed varchar(1000),@strN varchar(1000),@strO varchar(1000)
  DECLARE test_cursor CURSOR FOR                                    


  SET @strO=(SELECT TOP 1 P1.Phase from phase P1,Phase P2 where  P1.ID = P2.ID-1 and p1.project_id=@Project_ID order by p1.ID Desc)

  SET @strN =(SELECT TOP 1 P2.Phase from phase P1,Phase P2 
  where  P1.ID = P2.ID-1 and p1.project_id=@Project_ID order by p1.ID Desc)

  If object_id('dbo.#tN') is not null Begin ; drop table dbo.#tN ;End          

  CREATE TABLE dbo.#tN( var varchar(100));  insert into #tN select * from fnSplitStringAsTable(@strN,',')

  If object_id('dbo.#tO') is not null Begin; drop table dbo.#tO ;End          

  CREATE TABLE dbo.#tO (var varchar(100));  insert into #tO select * from fnSplitStringAsTable(@strO,',')

  Declare @i int
  Set @i=1
  Set @added = ''
  While @i != (select COUNT(*)+1 from #tN) 
  Begin
  if not exists(select VAR from #tO where var = (select Top 1 var from #tN where var in ( Select   Top (@i) VAR from #tN where Var in (Select Top (@i) var From #tN order by VAR desc) order by var asc)))
   Begin
   Set @added = @added + (select Top 1 var from #tN where var in ( Select Top (@i) VAR from #tN where Var in (Select Top (@i) var    From #tN order by VAR desc) order by var asc)) + ','
   End
   set @i=@i+1
  End

  If(len(@added) > 1) Begin; set @added = RTRIM(LEFT(@added,Len(@added) - 1)); End
  Select @added as Added

  drop table #tN;Drop table #tO
  End

【问题讨论】:

  • 请先考虑规范化您的数据。将逗号分隔的数据拆分为实列,可能还有一个表
  • 因此,一般来说,您需要将最后一行 (3) 与前一行 (2) 进行比较,并提取行 (2) 中添加的“新”内容。然后比较行 (2) 和行 (1) 并再次检查行 (1) 中添加了什么“新”?这是你想要的吗?
  • @gotqn - 介意给我们一个在 RDBMS 中存储逗号分隔字符串“非常实用”的实际示例吗?
  • @gotqn:存储逗号分隔值实际上可能会减少行数,但我非常怀疑它会提高性能。但我很高兴被证明错了。因此,如果您有一个完整的示例实际上表明使用逗号分隔值可以提高性能(而不 牺牲数据完整性),那么请向我们展示。
  • @gotqn 该表中将不会有 1500 万行,您将拥有另一个具有 1500 万行的表,只有在需要时才能访问。虽然可能存在 CSV 有用的情况,但您的示例并未显示它。

标签: sql sql-server tsql sql-server-2000


【解决方案1】:

这是一个可能的解决方案:

WITH CTE_Prep AS 
(
    SELECT *, DENSE_RANK() OVER (ORDER BY ID DESC) RN
    FROM phase
    CROSS APPLY dbo.DelimitedSplit8K(Phase,',')
)
,CTE_Result AS 
(
    SELECT ID, STUFF ((SELECT ', ' +Item 
                        FROM CTE_Prep c WHERE Item NOT IN (SELECT Item FROM CTE_Prep c2 WHERE c2.RN + 1 = c.RN)
                        AND c.Id = c3.ID
                        FOR XML PATH('')),1,2,'') AS Phase
    FROM CTE_Prep c3
    GROUP BY ID
)
SELECT r.Phase, p.[Updated By] FROM CTE_Result r
LEFT JOIN phase p ON r.id = p.id

这是使用SQLServerCentral 中的DelimitedSplit8K 函数进行拆分,但我相信您可以使用现有的。

SQLFiddle DEMO

【讨论】:

  • 我正在使用 sql 2000 生产。我认为这不适用于 sql 2000 :-(
  • 不,不会的。你应该在一开始就提到那个“小”的东西:)
  • 是的,我应该有,我们可以为这个@Nanad Zivkovic 提供任何其他解决方案
【解决方案2】:

我将尝试回答标准化问题。

Table PhaseTest 
PhaseID   int
TestID    int  
PK  PhaseID,  TestID
(this PK will enforce no duplicate TestID in a PhaseID  

Table PhaseUser
PhaseID   int PK
UserID    int

Table Test
TestID    int PK
TestName  varchar

Table User 
UserID    int PK
UserName  varchar

这在单独的行中显示结果(没有逗号)

select PT1.PhaseID, Test.TestName, User.UserName
  from PhaseTest PT1 
  left outer join PhaseTest PT2
    on PT2.PhaseID = PT1.PhaseID + 1 
   and PT2.TestID  = PT1.TestID
  join PhaseUser 
    on PhaseUser.UserID = PT1.UserID 
  join Test 
    on Test.TestID = PT1.UserID
 where PT2.PhaseID is null
 order by PT1.TestID
 union
select PT1.PhaseID, Test.TestName, User.UserName
  from PhaseTest PT1 
  join PhaseUser 
    on PhaseUser.UserID = PT1.UserID 
  join Test 
    on Test.TestID = PT1.UserID
 where PT1.PhaseID = (select max(PhaseID) from PhaseTest)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多