【问题标题】:Using CROSS APPLY for more than one column对不止一列使用 CROSS APPLY
【发布时间】:2013-04-28 01:23:50
【问题描述】:

第 3 天使用 SQL Server。

我正在尝试将 2 列分隔数据合并到一个表值函数的输出中。这是我的数据:

我希望将数据处理并放入以下格式的表格中:

我目前尝试使用这个 CROSS APPLY TSQL 语句,但我不知道我在做什么。

USE [Metrics]
INSERT INTO dbo.tblSplitData(SplitKey, SplitString, SplitValues)
SELECT d.RawKey, c.*, e.*
FROM dbo.tblRawData d
CROSS APPLY dbo.splitstringcomma(d.DelimitedString) c, dbo.splitstringcomma(d.DelimitedValues) e

我对 CROSS APPLY 的研究具有广泛的背景,我不明白在这种情况下应该如何应用它。我是否需要一个带有额外 CROSS APPLY 和一个连接的子查询来组合来自两个表值函数的返回?

这是我最初使用的拆分功能(我不记得作者归功于他们):

CREATE FUNCTION [dbo].[splitstring] ( @stringToSplit VARCHAR(MAX), @Delimiter CHAR(1))
RETURNS
 @returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN

 DECLARE @name NVARCHAR(255)
 DECLARE @pos INT

 WHILE CHARINDEX(@Delimiter, @stringToSplit) > 0
 BEGIN
  SELECT @pos  = CHARINDEX(@Delimiter, @stringToSplit)  
  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
 END

 INSERT INTO @returnList
 SELECT @stringToSplit

 RETURN
END

编辑和修改查询

USE [Metrics] 
INSERT INTO dbo.tblSplitData(SplitKey, SplitString, SplitValues)
SELECT s.RawKey, s.SplitString, v.SplitValues
FROM (
SELECT d.RawKey, d.DelimitedString,
 c.item SplitString, c.rn
FROM dbo.tblRawData d
CROSS APPLY dbo.splitstring(d.DelimitedString, ',') c
) s

INNER JOIN

(
SELECT d.RawKey, d.DelimitedValues,
 c.item SplitValues, c.rn
FROM dbo.tblRawData d
CROSS APPLY dbo.splitstring(d.DelimitedValues, ',') c
) v
on s.RawKey = v.RawKey
and s.rn = v.rn;

【问题讨论】:

    标签: sql-server-2008 tsql ssms csv cross-apply


    【解决方案1】:

    由于您使用的是 Sql Server 2008。您可以在没有使用 XML 的 UDF 的情况下执行此操作。

    ;WITH CTE1 AS
    ( 
        SELECT *
        ,RN= Row_Number() OVER( Partition BY DelemitedString,DelimitedValues,RawKey,TableID ORDER BY TableID)
         FROM 
        (
        SELECT *
        ,DelimitedStringXML = CAST('<d>'+REPLACE(DelemitedString,',','</d><d>')+'</d>' AS XML)
        ,DelimitedValueXML = CAST('<d>'+REPLACE(DelimitedValues,',','</d><d>')+'</d>' AS XML)
    
         FROM dbo.tblRawData
        ) as t
        Cross Apply
        (
        SELECT y.value('.', 'VARCHAR(30)') AS SplitString FROM DelimitedStringXML.nodes('//d') as  x(y)
    
        ) as b
    )
    ,CTE2 AS 
    (
        SELECT *
        ,RN= Row_Number() OVER( Partition BY DelemitedString,DelimitedValues,RawKey,TableID ORDER BY TableID)
         FROM 
        (
        SELECT *
        ,DelimitedStringXML = CAST('<d>'+REPLACE(DelemitedString,',','</d><d>')+'</d>' AS XML)
        ,DelimitedValueXML = CAST('<d>'+REPLACE(DelimitedValues,',','</d><d>')+'</d>' AS XML)
    
         FROM dbo.tblRawData
        ) as t
        CROSS APPLY
        (
        SELECT h.value('.', 'VARCHAR(30)') AS SplitValue FROM DelimitedValueXML.nodes('//d') as  g(h)
    
        ) as c
    )
    
    
    SELECT a.RawKey,a.SplitString,b.SplitValue 
    FROM CTE1 as a
    INNER JOIN CTE2 as b
        on  a.TableID= b.TableID
        AND a.RN = b.RN
    

    这里是SQLFiddle Demo

    【讨论】:

      【解决方案2】:

      如果我们能看到您的拆分字符串函数,可能会更容易回答这个问题。我的答案是使用我拥有的拆分函数的一个版本。

      我将在您的拆分函数中包含一个行号,您可以使用该行号来连接拆分字符串和拆分值。

      分割功能:

      CREATE FUNCTION [dbo].[Split](@String varchar(MAX), @Delimiter char(1))       
      returns @temptable TABLE (items varchar(MAX), rn int)       
      as       
      begin      
          declare @idx int       
          declare @slice varchar(8000)   
          declare @rn int = 1 -- row number that increments with each value in the delimited string
      
          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, rn) values(@slice, @rn)       
      
              set @String = right(@String,len(@String) - @idx)       
              set @rn = @rn +1
      
              if len(@String) = 0 break       
          end   
      return 
      end;
      

      然后,如果要拆分多个列,则可以使用类似于以下的查询:

      INSERT INTO dbo.tblSplitData(SplitKey, SplitString, SplitValues)
      select s.rawkey,
        s.splitstring,
        v.splitvalues
      from
      (
        SELECT d.RawKey, d.delimitedstring, d.delimitedvalues, 
          c.items SplitString, 
          c.rn
        FROM dbo.tblRawData d
        CROSS APPLY dbo.Split(d.DelimitedString, ',') c
      ) s
      inner join
      (
        SELECT d.RawKey, d.delimitedstring, d.delimitedvalues, 
          c.items SplitValues, 
          c.rn
        FROM dbo.tblRawData d
        CROSS APPLY dbo.Split(d.DelimitedValues, ',') c
      ) v
        on s.rawkey = v.rawkey
        and s.delimitedstring = v.delimitedstring
        and s.rn = v.rn;
      

      SQL Fiddle with Demo

      这使用两个子查询来生成拆分值列表,然后使用拆分函数创建的行号将它们连接起来。

      【讨论】:

      • 无法告诉您我多么感谢您的帮助 - 我会看看我是否无法立即调整此代码 :)
      • 好的 - 我创建了一个简单版本的查询,只是为了测试函数的各种返回。它似乎只返回两行;好像它无法运行拆分函数的最后一次迭代...USE [410_Metrics] INSERT INTO dbo.tblSplitData(SplitKey, SplitString, RowNumber) SELECT d.RawKey, c.items, c.rn FROM dbo.tblRawData d CROSS APPLY dbo.Split(d.DelimitedString, ',') c
      • @Chris 这很难说,因为我看不到你在使用什么,你能用你正在使用的确切代码和数据编辑 sql fiddle 吗?
      • 好的,我将右侧的 SQL(模式?)替换为以下行:SELECT d.RawKey, c.items, c.rn FROM dbo.tblRawData d CROSS APPLY dbo.Split(d.DelimitedString, ',') c。它似乎在小提琴中工作得很好......当我在 SQL Server 2008 Management Studio 中运行完全相同的查询时,它只返回 2 行。小提琴返回所有 6... SQL Server 只返回 John 和 Sandy。 John 的 RawKey 值为 1,Sandy 的 RawKey 值为 2。
      • @Chris 查看此演示,更改您的函数并返回正确的结果 -- sqlfiddle.com/#!3/f7370/3
      猜你喜欢
      • 2017-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-10
      • 2011-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多