【问题标题】:Is it possible to have a view in sql-server 2008 that splits one row into many?是否有可能在 sql-server 2008 中有一个将一行拆分为多行的视图?
【发布时间】:2015-04-28 20:28:23
【问题描述】:

背景故事是我正在尝试编写一个视图,该视图采用一个表,该表的每一行都是一个 ID,并且该 ID 的序列化数据在一个 clob 中,并以 sql 可导航形式呈现。基本上我的代码看起来像:

CREATE VIEW UNSERIALIZED_TABLE_VIEW AS 
SELECT
    SOURCE_TABLE.ID SOURCE_ID,
    a.*
FROM
    SOURCE_TABLE,
    FUNCTION_WHICH_UNSERIALIZES((SELECT DATA FROM SOURCE_TABLE WHERE ID = SOURCE_ID)

我尝试将函数放在 select 语句中,但这只是给出了一个关于它未定义的语法错误。当它运行时,错误通常是关于返回太多值的子查询。我可以批量反序列化数据,但现在我真的很好奇出了什么问题。

示例数据

@0History:23:ALPHANUMERICSTUFF1234567ID:11:ACCT1234567SourceMode:6:ANNUAL.ModeChanges:UniqueIndex:23:ALPHANUMERICSTUFF1234567ID:11:ACCT1234567OldValue:1:+NewValue:6:ANNUALChangeType:1:AChangeDate:20:6/03/2013 2:49:32 AM.
@0History:UniqueIndex:95:NOTTHESAME0987654|ALPHANUMERIC534|PRETEND349235|95CHARACTERSID:47:GNR44718500|PNR48CDQ704|PGP48090798|FGDS2345236SourceMode:26:ANNUAL|C-P-D|ANNUAL|ANNUALLoan:3:|||ModeChanges:UniqueIndex:95:00487SOMETHING4264500ORD|992581PROBABLY04ORD|0048SHOULD238BET|0095CHARS436PR638FGP07VDCID:47:GNR44718500|PNR48CDQ704|PGP48090798|FGDS2345236OldValue:7:+|+|+|+NewValue:26:ANNUAL|C-P-D|ANNUAL|ANNUALChangeType:7:A|A|A|AChangeDate:91:12/22/2013 11:53:11 PM|4/22/2013 11:53:11 PM|12/22/2013 11:53:11 PM|12/22/2013 11:53:11 PM.

数据是COLUMN_NAME:LENGTH_OF_ENTRY:DATA_FOR_COLUMN_ROW_1|DATA_FOR_COLUMN_ROW2|....NEXT_COLUMN_NAME...形式的序列化表数据

函数示例:

CREATE FUNCTION FUNCTION_THAT_UNSERIALIZES (@clob varchar(max),@colname varchar(max)) RETURNS @NewValue TABLE (ID INT,value varchar(max)) AS
BEGIN
    DECLARE @colstart INT,@lenstart INT,@lenend INT,@collen VARCHAR(MAX),@lngth INT,@tmp VARCHAR(MAX), @rowid INT,@value VARCHAR(max),@next INT;
SELECT 
   @colstart = CHARINDEX(@colname,@tmp)+1,
   @lenstart = CHARINDEX(':',@tmp,@colstart)+1,
   @lenend   = CHARINDEX(':',@tmp,@lenstart),
   @collen   = SUBSTRING(@tmp,@lenstart,@lenend - @lenstart),
   @lngth    = CAST (@collen AS INT),
   @tmp      = SUBSTRING(@tmp,@lenend,@lngth);
WHILE LEN(@tmp) > 0 BEGIN
    SET @next = CHARINDEX('|',@tmp);
    IF @next > 0 BEGIN
        SET @value = SUBSTRING(@tmp,0,@next);     
        SET @tmp   = SUBSTRING(@tmp,@next+1,LEN(@tmp) - @next);
    END ELSE BEGIN
        SET @value = @tmp;    
        SET @tmp   = '';
 END
 INSERT INTO @NewValue VALUES(@rowid,@value)
 SET @rowid = @rowid+1;
 END
 RETURN 

示例错误

Msg 512, Level 16, State 1, Line 7

子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。

Msg 4104, Level 16, State 1, Line 15

无法绑定多部分标识符“SOURCE_TABLE.SOURCE_ID”。

.. 我认为可能还有另一个,但现在无法弄清楚如何重现它。

【问题讨论】:

  • 你有数据的例子吗?
  • 另外,还有一个函数示例,以及运行它时遇到的确切错误。
  • 抱歉,认为这无关紧要。现在添加。
  • 你是否意识到多语句表值函数对性能来说很糟糕?这个函数有什么作用?
  • 不,我不知道多语句表值函数对性能来说很糟糕,@SeanLange 感谢您指出这一点。该函数接受两个输入,一行数据链接相同的数据,以及一个列标题。它解析文本并吐出一个表格,每个单独的值都在自己的行上。

标签: sql-server sql-server-2008 views


【解决方案1】:

我认为这可能是您完成我认为您正在尝试做的事情所需的语法。

CREATE VIEW UNSERIALIZED_TABLE_VIEW AS 
SELECT
    SOURCE_TABLE.ID SOURCE_ID,
    a.*
FROM SOURCE_TABLE
CROSS APPLY FUNCTION_WHICH_UNSERIALIZES(DATA, @colname) a

我不确定你的@colname 参数应该是什么;它被排除在问题中的代码之外。

【讨论】:

  • 谢谢,这很有帮助,但我遇到了问题,因为我需要调用该函数四次,它给了我一个 Msg 4104, Level 16, State 1, Line 20无法绑定标识符“SOURCE_TABLE.DATA”。在第 2、3 和 4 次实例中。 \@colname 是“列名”的缩写,它是数据中的文本,表示特定列的条目开始的位置。例如,'StartDate' 的 \@colname 将对应于序列化数据的 StartDate 列中的条目。
  • 我不确定,你能把代码贴在你调用它四次的地方吗?
  • 各种排列:SELECT SOURCE_TABLE.ID SOURCE_ID, a.value, b.value, c.value, d.value FROM SOURCE_TABLE CROSS APPLY FUNCTION_WHICH_UNSERIALIZES(DATA, @colname1) a, CROSS APPLY FUNCTION_WHICH_UNSERIALIZES( DATA, @colname2) b, 交叉应用函数_WHICH_UNSERIALIZES(DATA, @colname3) c, 交叉应用函数_WHICH_UNSERIALIZES(DATA, @colname4) d 其中a.id =b.id AND b.id=c.id AND c.id = d .id
  • 你不应该把逗号放在交叉应用语句之间。
  • 是的,如果您用逗号分隔它们,则相当于指定交叉连接。在这种情况下,您需要交叉应用,以便函数调用可以访问 SOURCE_TABLE 中的 DATA 字段的参数。
猜你喜欢
  • 2020-11-26
  • 2022-01-18
  • 2016-10-11
  • 2016-11-18
  • 2020-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-11
相关资源
最近更新 更多