TSQL - 根据表行和单元格值创建视图

时间:2016-02-29 13:11:06

标签: sql sql-server tsql sql-server-2012 cursor

我坚持使用左下表结构(SQL Server 2012)来创建一个视图或函数,它将在屏幕截图中输出正确的表:

Input and Output

TestOutput 表包含每个 ID RowNumber 10 (Step0_Name1)开头的数据。在真实场景中,有比我在此处列出的步骤更多的步骤。

我希望有一些逻辑可以通过名称/数字识别或行编号将所有对写成lke Step0_Name1 Step0_Name1_Status

我猜测将需要游标来创建某种循环逻辑。

不幸的是,sqlfiddle.com抛出错误,所以我在这里粘贴了架构:

创建测试:

CREATE TABLE [dbo].[Test](
    [ID] [nchar](5) NOT NULL,
    [Version] [smallint] NOT NULL,
    [RowNumber] [int] NOT NULL,
    [COLUMN1] [nvarchar](max) NULL,
    [COLUMN2] [nvarchar](max) NULL,
    [COLUMN3] [nvarchar](max) NULL,
    [COLUMN4] [numeric](15, 3) NULL,
 CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(   [ID] ASC,
    [RowNumber] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

插入测试:

INSERT INTO [dbo].[Test]
           ([ID] ,[Version] ,[RowNumber],[COLUMN1],[COLUMN2],[COLUMN3],[COLUMN4])
Values 
('00010',1, 1, 'Sheet', 'Part',             'A',            NULL),
('00010',1, 2, 'Sheet', 'Name',             'PartName',     NULL),
('00010',1, 3, 'Sheet', 'Price',            NULL,           1.470),
('00010',1, 4, 'Sheet', 'Step0_SOP',        '2015 CW 09',   NULL),
('00010',1, 5, 'Sheet', 'Step1_SOP',        '2015 CW 10',   NULL),
('00010',1, 6, 'Sheet', 'Step2_SOP',        '2015 CW 11',   NULL),
('00010',1, 7, 'Sheet', 'Step0_Status',     'pending',      NULL),
('00010',1, 8, 'Sheet', 'Step1_Status',     'frozen',       NULL),
('00010',1, 9, 'Sheet', 'Step2_Status',     'released',     NULL),
('00010',1, 10,'Sheet', 'Step0_Name1',      'Auser',        NULL),
('00010',1, 11,'Sheet', 'Step0_Name2',       NULL,          NULL),
('00010',1, 12,'Sheet', 'Step0_Name3',      'Buser',        NULL),
('00010',1, 13,'Sheet', 'Step0_Name1_Status','started',     NULL),
('00010',1, 14,'Sheet', 'Step0_Name2_Status',NULL,          NULL),
('00010',1, 15,'Sheet', 'Step0_Name3_Status','pending',     NULL),
('00010',1, 16,'Sheet', 'Step1_Name1',      'Wuser',        NULL),
('00010',1, 17,'Sheet', 'Step1_Name2',      'Cuser',        NULL),
('00010',1, 18,'Sheet', 'Step1_Name3',      'Duser',        NULL),
('00010',1, 19,'Sheet', 'Step1_Name1_Status','released',    NULL),
('00010',1, 20,'Sheet', 'Step1_Name2_Status','pending',     NULL),
('00010',1, 21,'Sheet', 'Step1_Name3_Status','released',    NULL),

('00020',1, 1, 'Sheet', 'Part',             'B',            NULL),
('00020',1, 2, 'Sheet', 'Name',             'PartName',     NULL),
('00020',1, 3, 'Sheet', 'Price',            NULL,           2.190),
('00020',1, 4, 'Sheet', 'Step0_SOP',        '2016 CW 19',   NULL),
('00020',1, 5, 'Sheet', 'Step1_SOP',        '2016 CW 20',   NULL),
('00020',1, 6, 'Sheet', 'Step2_SOP',        '2015 CW 21',   NULL),
('00020',1, 7, 'Sheet', 'Step0_Status',     'released',     NULL),
('00020',1, 8, 'Sheet', 'Step1_Status',     'frozen',       NULL),
('00020',1, 9, 'Sheet', 'Step2_Status',     'pending',      NULL),
('00020',1, 10,'Sheet', 'Step0_Name1',      'Xuser',        NULL),
('00020',1, 11,'Sheet', 'Step0_Name2',       NULL,          NULL),
('00020',1, 12,'Sheet', 'Step0_Name3',      'Wuser',        NULL),
('00020',1, 13,'Sheet', 'Step0_Name1_Status','started',     NULL),
('00020',1, 14,'Sheet', 'Step0_Name2_Status',NULL,          NULL),
('00020',1, 15,'Sheet', 'Step0_Name3_Status','pending',     NULL),
('00020',1, 16,'Sheet', 'Step1_Name1',      'Auser',        NULL),
('00020',1, 17,'Sheet', 'Step1_Name2',      'Cuser',        NULL),
('00020',1, 18,'Sheet', 'Step1_Name3',      'Buser',        NULL),
('00020',1, 19,'Sheet', 'Step1_Name1_Status','frozen',      NULL),
('00020',1, 20,'Sheet', 'Step1_Name2_Status','pending',     NULL),
('00020',1, 21,'Sheet', 'Step1_Name3_Status','released',    NULL)

创建TestOutput:

CREATE TABLE [dbo].[TestOutput](
    [ID] [nchar](5) NOT NULL,
    [StepCount] [int] NULL
    [StepNo] [int] NULL,
    [Name] [nvarchar](max) NULL,
    [Status] [nvarchar](max) NULL   
    )

插入TestOutput:

INSERT INTO [dbo].[TestOutput]   ([ID] ,[StepCount] ,[StepNo],[Name],[Status])
Values 
('00010',1, 0, 'Auser', 'started'),
('00010',2, 0, NULL, NULL),
('00010',3, 0, 'Buser', 'pending'),
('00010',1, 1, 'Wuser', 'released'),
('00010',2, 1, 'Cuser', 'pending'),
('00010',3, 1, 'Duser', 'released'),

('00020',1, 0, 'Xuser', 'started'),
('00020',2, 0, NULL, NULL),
('00020',3, 0, 'Wuser', 'pending'),
('00020',1, 1, 'Auser', 'frozen'),
('00020',2, 1, 'Cuser', 'pending'),
('00020',3, 1, 'Buser', 'released')

我希望你能告诉我如何解决这个问题。

非常感谢。

2 个答案:

答案 0 :(得分:1)

试试这个:

select
  t.id
  ,row_number() over(
     partition by t.id,
                  substring(t.column2, 1, charindex('_', t.column2))
     order by t.column2
  ) StepCount
  ,substring(t.column2, 5, charindex('_', t.column2) - 5) [StepNo]
  ,t.column3 [Name]
  ,(
    select
      t1.column3
    from
      @test t1
    where
      t.column2 + '_Status' = t1.column2
      and t1.id = t.id
  ) [Status]
from
  @test t
where
  t.column2 like 'step[0-9]_name[0-9]'
;

答案 1 :(得分:1)

不需要光标。

您可以先获取StepNo,然后使用窗口函数计算StepCount并加入结果:

SELECT s1.ID,
       s1.StepCount,
       s1.StepNo,
       [Name]     = s1.Column3,
       [Status]   = s2.Column3 
FROM (SELECT *,
        [StepCount] =  ROW_NUMBER() OVER (PARTITION BY ID, StepNo ORDER BY RowNumber)
      FROM (SELECT *, 
               [StepNo] = SUBSTRING(Column2, 5, CHARINDEX('_', Column2)-5)
            FROM Test
            WHERE Column2 LIKE 'Step%_Name%' 
              AND Column2 NOT LIKE '%Status') AS sub) AS s1
JOIN (SELECT *, 
        [StepCount] =  ROW_NUMBER() OVER (PARTITION BY ID, StepNo ORDER BY RowNumber)
      FROM (SELECT *, 
             [StepNo] = SUBSTRING(Column2, 5, CHARINDEX('_', Column2)-5)
            FROM Test
            WHERE Column2 LIKE 'Step%_Name%_Status') AS sub) AS s2
  ON s1.ID = s2.ID
 AND s1.StepCount = s2.StepCount
 AND s1.StepNo = s2.StepNo
ORDER BY ID, StepNo, StepCount;

LiveDemo

输出:

╔═══════╦═══════════╦════════╦═══════╦══════════╗
║  ID   ║ StepCount ║ StepNo ║ Name  ║  Status  ║
╠═══════╬═══════════╬════════╬═══════╬══════════╣
║ 00010 ║         1 ║      0 ║ Auser ║ started  ║
║ 00010 ║         2 ║      0 ║       ║          ║
║ 00010 ║         3 ║      0 ║ Buser ║ pending  ║
║ 00010 ║         1 ║      1 ║ Wuser ║ released ║
║ 00010 ║         2 ║      1 ║ Cuser ║ pending  ║
║ 00010 ║         3 ║      1 ║ Duser ║ released ║
║ 00020 ║         1 ║      0 ║ Xuser ║ started  ║
║ 00020 ║         2 ║      0 ║       ║          ║
║ 00020 ║         3 ║      0 ║ Wuser ║ pending  ║
║ 00020 ║         1 ║      1 ║ Auser ║ frozen   ║
║ 00020 ║         2 ║      1 ║ Cuser ║ pending  ║
║ 00020 ║         3 ║      1 ║ Buser ║ released ║
╚═══════╩═══════════╩════════╩═══════╩══════════╝

与CTE相同:

;WITH cte_name AS
(
  SELECT *,
        [StepCount] =  ROW_NUMBER() OVER (PARTITION BY ID, StepNo ORDER BY RowNumber)
  FROM (SELECT *, 
          [StepNo] = SUBSTRING(Column2, 5, CHARINDEX('_', Column2)-5)
       FROM #Test
       WHERE Column2 LIKE 'Step%_Name%' 
         AND Column2 NOT LIKE '%Status') AS sub
), cte_status AS
(
  SELECT *, 
        [StepCount] =  ROW_NUMBER() OVER (PARTITION BY ID, StepNo ORDER BY RowNumber)
  FROM (SELECT *, 
             [StepNo] = SUBSTRING(Column2, 5, CHARINDEX('_', Column2)-5)
        FROM #Test
        WHERE Column2 LIKE 'Step%_Name%_Status') AS sub
)
SELECT s1.ID,
       s1.StepCount,
       s1.StepNo,
       [Name]     = s1.Column3,
       [Status]   = s2.Column3 
FROM cte_name s1
JOIN cte_status s2
  ON s1.ID = s2.ID
 AND s1.StepCount = s2.StepCount
 AND s1.StepNo = s2.StepNo
ORDER BY ID, StepNo, StepCount;