SQL Server 多值列问题

标签 sql sql-server

我需要将多值列分为单个值

SOS_ID ALLOCATED_PART_NBR   ALLOCATED_SALES_ITM   ALLOCATED_QTY
523    500~5008~038~5008    2302~~007~5û005       1~1~~~1~2

注意:如果 ~ 分隔符之间没有值,则应插入空字符串。

我想要这样的输出:

SOS_ID   ALLOCATED_PART_NBR  ALLOCATED_SALES_ITM    ALLOCATED_QTY
523      500                 2302                   1
523      5008                ''                     1
523      038                 007                    ''
523      5008                5û005                  ''
523      ''/NULL             ''/NULL                1
523      ''/NULL             ''/NULL                2

最佳答案

所以......这是我为你想要的东西工作的方法。首先,您需要一个表值函数,该函数将根据分隔符将字符串拆分为字段,并将返回的行数填充为指定长度:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SplitString]') AND type IN (N'FN', N'IF', N'TF', N'FS', N'FT'))
    DROP FUNCTION [dbo].[SplitString]
GO

SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION [dbo].[SplitString] ( 
        @delimitedString nvarchar(4000),
        @delimiter nvarchar(100),
        @padRows int 
        )
/**************************************************************************
DESCRIPTION: 
        Accepts a delimited string and splits it at the specified
        delimiter points.  Returns the individual items as a table data
        type with the ElementID field as the array index and the Element
        field as the data

PARAMETERS:
        @delimitedString  - The string to be split
        @delimiter        - String containing the delimiter where
                            delimited string should be split
        @padRows          - Any rows less than this value will be padded
                            with empty rows (NULL means no padding)

RETURNS:
        Table data type containing array of strings that were split with
        the delimiters removed from the source string

USAGE:
        SELECT ElementID, Element 
        FROM asi_SplitString('11111,22222,3333', ',', NULL) 
        ORDER BY ElementID

***************************************************************************/
RETURNS @tblArray TABLE 
   (
    ElementID int IDENTITY(1,1),
    Element nvarchar(1000)
   )
AS
BEGIN

    DECLARE @index int
    DECLARE @siStart int
    DECLARE @siDelSize int
    DECLARE @count int

    SET @count = 1;
    SET @siDelSize  = LEN(@delimiter);
    --loop through source string and add elements to destination table array
    WHILE LEN(@delimitedString) > 0
    BEGIN
        SET @index = CHARINDEX(@delimiter, @delimitedString);
        IF @index = 0
        BEGIN
            INSERT INTO @tblArray VALUES (@delimitedString);
            BREAK;
        END
        ELSE
        BEGIN
            INSERT INTO @tblArray VALUES(SUBSTRING(@delimitedString, 1,@index - 1));
            SET @siStart = @index + @siDelSize;
            SET @delimitedString = SUBSTRING(@delimitedString, @siStart , LEN(@delimitedString) - @siStart + 1);
        END
        SET @count += 1;
    END

    IF (@padRows IS NOT NULL)
        WHILE (@count < @padRows)
        BEGIN
            SET @count += 1;
            INSERT INTO @tblArray VALUES ('');
        END

    RETURN;
END

GO

现在您需要一个包含数据的示例表来测试它(根据您的问题):

CREATE TABLE TestTable (SOS_ID nvarchar(10), 
                        ALLOCATED_PART_NBR nvarchar(400), 
                        ALLOCATED_SALES_ITM nvarchar(400), 
                        ALLOCATED_QTY nvarchar(400))

INSERT INTO TestTable (SOS_ID, ALLOCATED_PART_NBR, ALLOCATED_SALES_ITM, ALLOCATED_QTY)
VALUES ('523', '500~5008~038~5008', '2302~~007~5û005', '1~1~~~1~2')

现在,一些代码会将上面的数据转换为您想要的结果:

DECLARE @fieldCount int;
WITH TildeCounts AS (
    SELECT LEN(ALLOCATED_PART_NBR) - LEN(REPLACE(ALLOCATED_PART_NBR, '~', '')) AS TildeCount
      FROM TestTable t
    UNION ALL
    SELECT LEN( ALLOCATED_SALES_ITM) - LEN(REPLACE( ALLOCATED_SALES_ITM, '~', '')) AS TildeCount
      FROM TestTable t
    UNION ALL
    SELECT LEN(ALLOCATED_QTY) - LEN(REPLACE(ALLOCATED_QTY, '~', '')) AS TildeCount
      FROM TestTable t
) SELECT @fieldCount = MAX(TildeCount) + 1 FROM TildeCounts;

SELECT t.SOS_ID, a.Element AS [ALLOCATED_PART_NBR], b.Element AS [ALLOCATED_SALES_ITM], c.Element AS [ALLOCATED_QTY]
  FROM TestTable t
  CROSS APPLY dbo.SplitString(ALLOCATED_PART_NBR, '~', @fieldCount)  a
  CROSS APPLY dbo.SplitString(ALLOCATED_SALES_ITM, '~', @fieldCount)  b 
  CROSS APPLY dbo.SplitString(ALLOCATED_QTY, '~', @fieldCount)  c
WHERE a.ElementID = b.ElementID AND b.ElementID = c.ElementID  

它的作用是首先获取所有字符串中的最大字段数(因此它可以填充较短的字段)。然后,它从表中进行选择,将函数交叉应用到每一列,仅过滤所有 ID 匹配(排列)的行。

关于SQL Server 多值列问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29040430/

相关文章:

sql - 按多个维度成员进行 MDX 过滤

sql - 我应该使用 sp_executesql 还是 EXEC 来运行存储过程?

sql - 如何从 Oracle SQL 中的科学计数法转换?

sql - SQL Server中的主键设计

java - Hibernate Criteria 连接到包含外键的表

sql-server - sql查询中的多个计数

sql - 将单个触发器应用于相同的表

c# - 处理 DBNull 的最佳方法是什么

java.sql.SQLRecoverableException : Connection has been administratively disabled by console/admin command 错误

sql - 我的代码有效,但我不知道为什么