我有一个用户填写的InfoPath表单。它会被分配一个唯一的报告编号,并且在报告中他们可以选择零个或多个受影响的部分,每个部分都有一堆列。受影响的部件列表可以在处理报告时更改。向SharePoint提交或重新提交报表会调用SQL存储过程,其参数包括以分号分隔的列数据,其中一个NVARCHAR(MAX)
表示一列中的多行。存储过程解析以分号分隔的NVARCHAR
以填充表变量,然后将该表变量与将用于数据分析的主表合并。当用户每个报告只有一个具有给定部件号的受影响部件时,一切都很有效(因为我的MERGE
语句使用它来确定是否需要更新现有行或创建新行),最初是可接受的限制。粗略的SQL摘要:
CREATE TABLE [Report_to_Parts](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Report_ID] [nvarchar](255) NOT NULL,
[PartNumberOrdered] [nvarchar](255) NULL,
[OtherColumns] [nvarchar](255) NULL)
CREATE PROCEDURE [MergeReport_sp]
@paramReport_ID nvarchar(255),
@paramPartNumberString nvarchar(MAX) = NULL,
@paramOtherColumnsString nvarchar(MAX) = NULL
AS
BEGIN
DECLARE @tempPartTable TABLE (
[Report_ID] [nvarchar](255) NOT NULL,
[PartNumberOrdered] [nvarchar](255) NOT NULL,
[OtherColumns] [nvarchar](255) NULL)
DECLARE @WorkingPartNumberString nvarchar(255),
@WorkingOtherColumnsString nvarchar(255)
-- Magic to parse the semicolon delimited parameters omitted
WHILE (PartsRemainingToParse)
BEGIN
INSERT INTO @tempPartTable (
[Report_ID],
[PartNumberOrdered],
[OtherColumns])
VALUES (
@paramReport_ID,
@WorkingPartNumberString,
@WorkingOtherColumnsString)
END
MERGE [Report_to_Parts]
USING @tempPartTable AS [Source]
ON (
[Report_to_Parts].[Report_ID] = @paramReport_ID AND
[Report_to_Parts].[PartNumberOrdered] = [Source].[PartNumberOrdered])
WHEN NOT MATCHED BY TARGET
THEN INSERT(
[Report_ID],
[PartNumberOrdered],
[OtherColumns])
VALUES (
@paramReport_ID,
[Source].[PartNumberOrdered],
[Source].[OtherColumns])
WHEN MATCHED
THEN UPDATE SET [OtherColumns]=[Source].[OtherColumns]
WHEN NOT MATCHED BY SOURCE AND [Report_to_Parts].[Report_ID] = @paramReport_ID
THEN DELETE;
END
目前工作的输入和结果,假设[Report_ID]为123456的部分在[Report_to_Parts]中已经存在,但其他一些条目确实存在:
EXEC MergeReport_sp
@paramReport_ID = N'123456',
@paramPartNumberString = N'Part 1;abcd-efg;Part 3;'
@paramOtherColumnsString = N'There are many;other columns;but I simplified;'
SELECT * FROM [Report_to_Parts] WHERE [Report_ID] = N'123456'
---------------------------------------------------------
| ID | Report_ID | PartNumberOrdered | OtherColumns |
| 05 | 123456 | Part 1 | There are many |
| 06 | 123456 | abcd-efg | other columns |
| 07 | 123456 | Part 3 | but I simplified |
EXEC MergeReport_sp
@paramReport_ID = N'123456',
@paramPartNumberString = N'Part 1;Part 3;New Part;'
@paramOtherColumnsString = N'Updates;Work;Too;'
SELECT * FROM [Report_to_Parts] WHERE [Report_ID] = N'123456'
-----------------------------------------------------
| ID | Report_ID | PartNumberOrdered | OtherColumns |
| 05 | 123456 | Part 1 | Updates |
| 07 | 123456 | Part 3 | Work |
| 08 | 123456 | New Part | Too |
但是以下失败是因为它试图将PartNumberOrdered基于:
EXEC MergeReport_sp
@paramReport_ID = N'123456',
@paramPartNumberString = N'Part 1;Part 1;'
@paramOtherColumnsString = N'Thing 1;Thing 2;'
现在我需要它能够优雅地处理多个部件共享部件号的报告。下载InfoPath和/或SharePoint不是一个选项,也不是删除分号解析方面。选项我考虑:
SELECT
添加一列到@tempPartTable,以获取[Report_ID]表格中已有部分的[ID],设置@tempPartTable [ID] s那个,MERGE
和[ID]。我在提出3代码时遇到问题,而且我对其他想法也很开放。 Here's an earlier question I asked about this same system.
答案 0 :(得分:0)
写这个问题给了我一些想法,我能够用选项4来解决这个问题。我修改了[Report_to_Parts],以便[ID]不是一个身份,并且是一个复合主键和[Report_ID]。然后我更新了存储过程代码(还包括解析"魔法"万一有人在这篇文章中偶然发现试图解决解析问题):
ALTER PROCEDURE [MergeReport_sp]
@paramReport_ID nvarchar(255),
@paramPartNumberString nvarchar(MAX) = NULL,
@paramOtherColumnsString nvarchar(MAX) = NULL
AS
BEGIN
DECLARE @tempPartTable TABLE (
[ID] [int] NOT NULL,
[Report_ID] [nvarchar](255) NOT NULL,
[PartNumberOrdered] [nvarchar](255) NOT NULL,
[OtherColumns] [nvarchar](255) NULL)
DECLARE @WorkingPartNumberString nvarchar(255),
@WorkingOtherColumnsString nvarchar(255),
@PartNumberPos int = CHARINDEX(N';', @paramPartNumberString),
@OtherColumnsPos int = CHARINDEX(N';', @paramOtherColumnsString),
@PartTableID int = 1
WHILE (ISNULL(@PartNumberPos,0) > 0)
BEGIN
IF @OtherColumnsPos = 0 SET @OtherColumnsPos = 1
SET @WorkingPartNumberString = NULLIF(SUBSTRING(@paramPartNumberString,1,@PartNumberPos - 1), '')
SET @WorkingOtherColumnsString = NULLIF(SUBSTRING(@WorkingOtherColumnsString ,1,@OtherColumnsPos - 1), '')
INSERT INTO @tempPartTable (
[ID],
[Report_ID],
[PartNumberOrdered],
[OtherColumns])
VALUES (
@PartTableID,
@paramReport_ID,
@WorkingPartNumberString,
@WorkingOtherColumnsString)
SET @PartTableID = @PartTableID + 1
SET @paramPartNumberString = SUBSTRING(@paramPartNumberString, @PartNumberPos+1, LEN(@paramPartNumberString))
SET @paramOtherColumnsString = SUBSTRING(@paramOtherColumnsString, @OtherColumnsPos +1, LEN(@paramOtherColumnsString))
SET @PartNumberPos = CHARINDEX(N';',@paramPartNumberString)
SET @OtherColumnsPos = CHARINDEX(N';',@paramOtherColumnsString)
END
MERGE [Report_to_Parts]
USING @tempPartTable AS [Source]
ON (
[Report_to_Parts].[ID] = [Source].[ID] AND
[Report_to_Parts].[Report_ID] = @paramReport_ID)
WHEN NOT MATCHED BY TARGET
THEN INSERT(
[ID],
[Report_ID],
[PartNumberOrdered],
[OtherColumns])
VALUES (
[Source].[ID],
@paramReport_ID,
[Source].[PartNumberOrdered],
[Source].[OtherColumns])
WHEN MATCHED
THEN UPDATE SET
[PartNumberOrdered] = [Source].[PartNumberOrdered]
[OtherColumns]=[Source].[OtherColumns]
WHEN NOT MATCHED BY SOURCE AND [Report_to_Parts].[Report_ID] = @paramReport_ID
THEN DELETE;
END