我已经阅读了大量处理表RBAR的信息是非常低效的,虽然我知道这不是SQL的优化,但我很想知道是否有办法可以完成这项任务,避免循环或一组嵌套的CASE语句(因为我一次只能嵌套10个)。
问题:我有一个主库存文件(mif表),其中包含我们所有的部件号,并带有一个标志,表示该部件是否已被另一部件取代/替换。还有另一个表包含该部分被替换的内容。问题在于,如果你愿意的话,代替的级别是一个独立的单元。例如,如果将部分123替换为456但将456替换为789,则到目前为止没有任何内容直接告诉我们部分123最终被部分789替换。
我正在尝试创建一个表格,告诉记录最初替换第123部分的初始编号和最终链接部件编号。
对不起,这很长,但这里有两个简化版本的查询都可以工作(一个LOOP和一个CASE语句),但两者都有局限性。有没有办法有效地做到这一点,并允许我扩展10个CASE陈述?
使用了两个表:mif和dc_dim:
mif结构:
mfr_code | part_number | superseded
ABC | 123 | Y
DEF | 456 | Y
GHI | 789 | N
dc_dim结构:
MFR_CODE | PART_NUM | REPLACED | REPLACED_MFR_CODE | REPLACED_PART_NUM
ABC | 123 | Y | DEF | 456
DEF | 456 | Y | GHI | 789
GHI | 789 | N | (null) | (null)
首先,使用LOOP:
/***Create dbo.MifSuperseded since such a large amount of records.
Dropped at end.
This table contains the next link for each part number that has been superseded.***/
SELECT id = IDENTITY(int,1,1)
,a.mfr_code, a.part_number
,b.REPLACED, b.REPLACED_MFR_CODE, b.REPLACED_PART_NUM
INTO dbo.MifSuperseded
FROM dbo.mif a
LEFT OUTER JOIN dc_dim b
ON a.mfr_code = b.MFR_CODE AND a.part_number = b.PART_NUM
LEFT OUTER JOIN mif c
ON b.REPLACED_MFR_CODE = c.mfr_code AND b.REPLACED_PART_NUM = c.PART_NUM
WHERE a.superseded = N'Y';
--Declare variables
DECLARE @id int = (SELECT MIN(id) FROM dbo.MifSuperseded);
DECLARE @Replaced nvarchar(3);
DECLARE @NumOfSupers int;
DECLARE @MfgCode nvarchar(5);
DECLARE @PartNum nvarchar(30);
DECLARE @ReplacedMfgCode nvarchar(5);
DECLARE @ReplacedPartNum nvarchar(30);
--Outside loop that goes row-by-row
WHILE @id IS NOT NULL
BEGIN
SET @ReplacedMfgCode = (SELECT REPLACED_MFR_CODE FROM dbo.MifSuperseded WHERE id = @id);
SET @ReplacedPartNum = (SELECT REPLACED_PART_NUM FROM dbo.MifSuperseded WHERE id = @id);
SET @Replaced = (SELECT REPLACED FROM dbo.MifSuperseded WHERE mfr_code = @MfgCode AND part_number = @PartNum);
SET @NumOfSupers = 1;
--Inside loop that discovers end-of-chain replacement
WHILE @Replaced = 'Y'
BEGIN
SET @MfgCode = @ReplacedMfgCode;
SET @PartNum = @ReplacedPartNum;
SET @ReplacedMfgCode = (SELECT REPLACED_MFR_CODE
FROM dbo.MifSuperseded
WHERE mfr_code = @MfgCode
AND part_number = @PartNum);
SET @ReplacedPartNum = (SELECT REPLACED_PART_NUM
FROM dbo.MifSuperseded
WHERE mfr_code = @MfgCode
AND part_number = @PartNum);
SET @Replaced = (SELECT REPLACED
FROM dbo.MifSuperseded
WHERE mfr_code = @ReplacedMfgCode
AND part_number = @ReplacedPartNum);
SET @MfgCode = @ReplacedMfgCode;
SET @PartNum = @ReplacedPartNum;
SET @NumOfSupers = @NumOfSupers + 1;
END
--Inserts final superseded part number into table
INSERT INTO dbo.SUPERSESSION_EOC
SELECT mfr_code
,part_number
,@NumOfSupers AS NUMBER_OF_SUPERSESSIONS
,@MfgCode AS REPLACED_MFR_CODE
,@PartNum AS REPLACED_PART_NUM
FROM dbo.MifSuperseded
WHERE id = @id
SELECT @id = MIN(id) FROM dbo.MifSuperseded WHERE id > @id;
END;
DROP TABLE dbo.MifSuperseded;
现在使用CASE语句:
/***Create dbo.MifSuperseded since such a large amount of records.
Dropped at end.
This table contains the next link for each part number that has been superseded.***/
SELECT id = IDENTITY(int,1,1)
,a.mfr_code, a.part_number
,b.REPLACED, b.REPLACED_MFR_CODE, b.REPLACED_PART_NUM
INTO dbo.MifSuperseded
FROM dbo.mif a
LEFT OUTER JOIN dc_dim b
ON a.mfr_code = b.MFR_CODE AND a.part_number = b.PART_NUM
LEFT OUTER JOIN mif c
ON b.REPLACED_MFR_CODE = c.mfr_code AND b.REPLACED_PART_NUM = c.PART_NUM
WHERE a.superseded = N'Y';
/***Select Into dbo.mif_supersession_final_replacement.***/
INSERT INTO dbo.SUPERSESSION_EOC
SELECT mif_1.mfr_code
,mif_1.part_number
,(CASE WHEN mif_10.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_9.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_8.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_7.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_6.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_5.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_4.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_3.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_2.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_1.REPLACED_MFR_CODE IS NULL THEN ''
ELSE 1 END
ELSE 2 END
ELSE 3 END
ELSE 4 END
ELSE 5 END
ELSE 6 END
ELSE 7 END
ELSE 8 END
ELSE 9 END
ELSE 10 END) AS NUMBER_OF_SUPERSESSIONS
,(CASE WHEN mif_10.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_9.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_8.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_7.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_6.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_5.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_4.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_3.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_2.REPLACED_MFR_CODE IS NULL THEN
CASE WHEN mif_1.REPLACED_MFR_CODE IS NULL THEN ''
ELSE mif_1.REPLACED_MFR_CODE END
ELSE mif_2.REPLACED_MFR_CODE END
ELSE mif_3.REPLACED_MFR_CODE END
ELSE mif_4.REPLACED_MFR_CODE END
ELSE mif_5.REPLACED_MFR_CODE END
ELSE mif_6.REPLACED_MFR_CODE END
ELSE mif_7.REPLACED_MFR_CODE END
ELSE mif_8.REPLACED_MFR_CODE END
ELSE mif_9.REPLACED_MFR_CODE END
ELSE mif_10.REPLACED_MFR_CODE END) AS REPLACED_MFR_CODE
,(CASE WHEN mif_10.REPLACED_PART_NUM IS NULL THEN
CASE WHEN mif_9.REPLACED_PART_NUM IS NULL THEN
CASE WHEN mif_8.REPLACED_PART_NUM IS NULL THEN
CASE WHEN mif_7.REPLACED_PART_NUM IS NULL THEN
CASE WHEN mif_6.REPLACED_PART_NUM IS NULL THEN
CASE WHEN mif_5.REPLACED_PART_NUM IS NULL THEN
CASE WHEN mif_4.REPLACED_PART_NUM IS NULL THEN
CASE WHEN mif_3.REPLACED_PART_NUM IS NULL THEN
CASE WHEN mif_2.REPLACED_PART_NUM IS NULL THEN
CASE WHEN mif_1.REPLACED_PART_NUM IS NULL THEN ''
ELSE mif_1.REPLACED_PART_NUM END
ELSE mif_2.REPLACED_PART_NUM END
ELSE mif_3.REPLACED_PART_NUM END
ELSE mif_4.REPLACED_PART_NUM END
ELSE mif_5.REPLACED_PART_NUM END
ELSE mif_6.REPLACED_PART_NUM END
ELSE mif_7.REPLACED_PART_NUM END
ELSE mif_8.REPLACED_PART_NUM END
ELSE mif_9.REPLACED_PART_NUM END
ELSE mif_10.REPLACED_PART_NUM END) AS REPLACED_PART_NUM
FROM dbo.MifSuperseded AS mif_1
LEFT OUTER JOIN dbo.MifSuperseded AS mif_2
ON mif_1.REPLACED_MFR_CODE = mif_2.mfr_code AND mif_1.REPLACED_PART_NUM = mif_2.part_number
LEFT OUTER JOIN dbo.MifSuperseded AS mif_3
ON mif_2.REPLACED_MFR_CODE = mif_3.mfr_code AND mif_2.REPLACED_PART_NUM = mif_3.part_number
LEFT OUTER JOIN dbo.MifSuperseded AS mif_4
ON mif_3.REPLACED_MFR_CODE = mif_4.mfr_code AND mif_3.REPLACED_PART_NUM = mif_4.part_number
LEFT OUTER JOIN dbo.MifSuperseded AS mif_5
ON mif_4.REPLACED_MFR_CODE = mif_5.mfr_code AND mif_4.REPLACED_PART_NUM = mif_5.part_number
LEFT OUTER JOIN dbo.MifSuperseded AS mif_6
ON mif_5.REPLACED_MFR_CODE = mif_6.mfr_code AND mif_5.REPLACED_PART_NUM = mif_6.part_number
LEFT OUTER JOIN dbo.MifSuperseded AS mif_7
ON mif_6.REPLACED_MFR_CODE = mif_7.mfr_code AND mif_6.REPLACED_PART_NUM = mif_7.part_number
LEFT OUTER JOIN dbo.MifSuperseded AS mif_8
ON mif_7.REPLACED_MFR_CODE = mif_8.mfr_code AND mif_7.REPLACED_PART_NUM = mif_8.part_number
LEFT OUTER JOIN dbo.MifSuperseded AS mif_9
ON mif_8.REPLACED_MFR_CODE = mif_9.mfr_code AND mif_8.REPLACED_PART_NUM = mif_9.part_number
LEFT OUTER JOIN dbo.MifSuperseded AS mif_10
ON mif_9.REPLACED_MFR_CODE = mif_10.mfr_code AND mif_9.REPLACED_PART_NUM = mif_10.part_number
DROP TABLE dbo.MifSuperseded;
这两个都会在SUPERSESSION_EOC表中正确插入ABC 123部分的记录:
mfr_code | part_number | NUMBER_OF_SUPERSESSIONS | REPLACED_MFR_CODE | REPLACED_PART_NUM
ABC | 123 | 2 | GHI | 789
使用CASE语句的插入查询只需2分钟就能插入358,000条记录。使用循环的插入运行20分钟,当我停止查询时只插入了9,000条记录。除非我嵌套嵌套的CASE语句一次获得10个以上的语句,否则使用CASE语句的插入限制为10个替换,而循环插入查询不能用。
关于如何使这个过程变得可扩展和有效的任何想法?任何帮助都将非常感谢。再一次,我很抱歉这么久了,但是想给你所有与我合作的人。
编辑:我刚尝试使用带有OUTER APPLY的递归CTE,但是效果很差:
/***Create dbo.MifSuperseded since such a large amount of records.
Dropped at end.
This table contains the next link for each part number that has been superseded.***/
SELECT id = IDENTITY(int,1,1)
,a.mfr_code, a.part_number
,b.REPLACED, b.REPLACED_MFR_CODE, b.REPLACED_PART_NUM
INTO dbo.MifSuperseded
FROM dbo.mif a
LEFT OUTER JOIN dc_dim b
ON a.mfr_code = b.MFR_CODE AND a.part_number = b.PART_NUM
LEFT OUTER JOIN mif c
ON b.REPLACED_MFR_CODE = c.mfr_code AND b.REPLACED_PART_NUM = c.PART_NUM
WHERE a.superseded = N'Y';
WITH cteMifSupersededRecursive AS
(
SELECT 1 AS NUMBER_OF_SUPERSESSIONS
,mfr_code, part_number
,REPLACED_MFR_CODE, REPLACED_PART_NUM
FROM dbo.MifSuperseded
UNION ALL
SELECT NUMBER_OF_SUPERSESSIONS + 1, cur.mfr_code, cur.part_number
,nxt.REPLACED_MFR_CODE, nxt.REPLACED_PART_NUM
FROM cteMifSupersededRecursive cur
INNER JOIN dbo.MifSuperseded nxt
ON cur.REPLACED_MFR_CODE = nxt.mfr_code AND cur.REPLACED_PART_NUM = nxt.part_number
)
SELECT a.mfr_code, a.part_number
,b.NUMBER_OF_SUPERSESSIONS ,b.REPLACED_MFR_CODE, b.REPLACED_PART_NUM
INTO dbo.SUPERSESSION_EOC
FROM dbo.MifSuperseded a
CROSS APPLY
(SELECT TOP 1 REPLACED_MFR_CODE, REPLACED_PART_NUM, NUMBER_OF_SUPERSESSIONS
FROM cteMifSupersededRecursive
WHERE mfr_code = a.mfr_code AND part_number = a.part_number
ORDER BY NUMBER_OF_SUPERSESSIONS DESC
) b
DROP TABLE dbo.MifSuperseded;