【问题标题】:SQL Cross apply to rotate the comma separated valuesSQL Cross 适用于旋转逗号分隔值
【发布时间】:2020-08-14 08:55:43
【问题描述】:
declare @RuleTable table (RuleId int, Pattern varchar(max) , Frequency int )


insert into @RuleTable 
select 1, '3,5,4,6' , 2

 SELECT 
 ROW_NUMBER() OVER(PARTITION BY items ORDER BY (select 1)) - 1  AS Id,
 RuleId,
 items AS ShiftId 
FROM @RuleTable
    CROSS APPLY SplitNew(REPLICATE(REPLACE(','+ LTRIM(RTRIM(Pattern)) +',',',0,',',') +',', Frequency ), ',') as ss

当前的输出是这样的……

但在预期的输出中,我不应该丢失逗号分隔字符串的顺序

意味着输出应该是这样的

ShiftId 
3
3
5
5
4
4
6
6

注意:频率表示逗号分隔字符串中的每个 shiftid 应重复多少次。

【问题讨论】:

  • 什么是SplitNew?这不是内置的 TVF(我怀疑是问题所在,因为它不考虑序数位置)。但是,您的查询不包含 ORDER BY,因此行可以按 SQL Server 想要返回的任意顺序排列。如果您希望按特定顺序排列行,则需要包含 ORDER BY
  • 请注意,您的子句ORDER BY (SELECT 1) 是没有意义的,这也可能意味着“将行以任意顺序排列”,并且分区中的每一行都将具有相同的值,因此都可以相同地具有有机会出现在小组的开始、结束或中间。

标签: sql sql-server csv


【解决方案1】:

看来您在这里遇到了一些问题。首先,我猜你的分离器(我们缺少定义)没有观察/保留序数位置。因此,我们需要使用分离器。我推荐delimitedsplit8k_LEAD

然后我们需要看看你是如何重复这些行的。像这样使用REPLICATE 不是正确的方法。使用 Tally 会更好。我在这里使用了内联的,并假设Frequency 的值不能大于10。如果是这样,请使用 CTE 创建内联 Tally(有很多关于如何执行此操作的示例,并且不要使用使用 rCTE 的示例,因为它们是 )。

之后,你会得到这样的结果:

SELECT ROW_NUMBER() OVER (PARTITION BY DS.Item ORDER BY DS.ItemNumber) - 1 AS ID,
       RT.RuleId,
       DS.Item
FROM @RuleTable RT
     CROSS APPLY dbo.DelimitedSplit8K_LEAD(RT.Pattern,',') DS
     JOIN (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10))V(I) ON RT.Frequency >= V.I 
ORDER BY DS.ItemNumber,
         V.I;

【讨论】:

  • 只是想了解为什么我们需要 JOIN (VALUES(1),(2),(3),(4),(5),(6),(7),(8 ),(9),(10))V(I) ?它的作用以及我们为什么使用 V ?
  • 根据我的回答,@vijaysahu:“那么我们需要看看你是如何重复这些行的。像这样使用REPLICATE 不是正确的方法。你会过得更好有一个 Tally。我在这里使用了一个内联的" 如果没有 Tally,你会得到每个项目 1 行,而不是 2。
  • 至于为什么V,“V”代表“Values”;基本混叠。同样的原因,RuleTable 是“RT”,DelimitedSplit8k_LEAD 是“DS”。
【解决方案2】:

你可以在字符串中找到一个值的first位置:

SELECT ss.seqnum - 1  AS Id, RuleId, items AS ShiftId 
FROM @RuleTable CROSS APPLY
     (SELECT ss.*,
             ROW_NUMBER() OVER (ORDER BY CHARINDEX(',' + Frequency + ',', ',' + Pattern + ',')) as seqnum
      FROM SplitNew(REPLICATE(REPLACE(','+ LTRIM(RTRIM(Pattern)) +',', ',0,', ',') +',', Frequency ), ',') as ss
     ) ss;

我不明白您的搜索 - 但是您使用的是未记录的功能。这通常会写成:

SELECT (ss.seqnum - 1) as Id, rt.RuleId, ss.value as ShiftId 
FROM @RuleTable rt CROSS APPLY
     (SELECT ss.*,
             ROW_NUMBER() OVER (ORDER BY CHARINDEX(',' + rt.Frequency + ',', ',' + rt.Pattern + ',')) as seqnum
      FROM string_split(pattern, ',') ss
     ) ss;

请注意,这使用了内置的string_split() 函数。这种方法不需要用户自定义函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-06
    相关资源
    最近更新 更多