【发布时间】:2017-12-03 15:17:03
【问题描述】:
我编写了一个存储过程,它将采用父部件,检查该部件的物料清单记录并有条件地连接匹配的子记录(即包含在该部件的 BOM 中的部件),但是仅满足特定条件的子记录(使用我们的命名约定,以“.”、“E”或“ZG”开头的任何内容)。
我创建了 SP,它运行良好,但只有当我传入 [可选] 父部件号时。我需要为所有部分运行这个 SP,所以我的想法是在游标内执行 SP,并继续传递下一个部分,直到没有剩下要处理的部分。我无法弄清楚如何做到这一点,或者是否有可能,因为在游标的 SELECT 语句中(我正在使用存储过程代码)我需要传入一个变量才能使其工作。
这是存储过程的代码:
CREATE PROCEDURE dbo.usp_BuildBOMLit
@item_no CHAR(8) = NULL
AS
BEGIN
WITH CTE AS (
SELECT DISTINCT
LTRIM(RTRIM(lvl1.item_no)) as item_no, LTRIM(RTRIM(lvl1.comp_item_no)) as comp_item_no,
CASE
WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE '.%'
THEN
LTRIM(RTRIM(lvl1.comp_item_no))
WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE 'E%'
THEN
(SELECT TOP 1 LTRIM(RTRIM(comp_item_no)) FROM bmprdstr_sql WHERE LTRIM(RTRIM(item_no))=LTRIM(RTRIM(lvl1.comp_item_no)) AND LTRIM(RTRIM(comp_item_no)) LIKE '.%')
WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE 'ZG%'
THEN
(SELECT TOP 1 LTRIM(RTRIM(comp_item_no)) FROM bmprdstr_sql WHERE LTRIM(RTRIM(item_no))=LTRIM(RTRIM(lvl1.comp_item_no)) AND LTRIM(RTRIM(comp_item_no)) LIKE '.%')
ELSE
NULL
END as lvl_2_comp_item_no
FROM
bmprdstr_sql as lvl1
LEFT JOIN bmprdstr_sql lvl2 ON lvl1.comp_item_no=lvl2.item_no
WHERE
(lvl1.item_no = @item_no)
AND (lvl1.comp_item_no LIKE '.%' OR lvl1.comp_item_no LIKE 'ZG%' OR lvl1.comp_item_no LIKE 'E%')
)
SELECT DISTINCT
CASE
WHEN LEFT(item_no,1)='.'
THEN STUFF(item_no,1,1,'')
ELSE
item_no
END as item_no,
part_no =
STUFF((SELECT DISTINCT ',' +
CASE
WHEN LEFT(lvl_2_comp_item_no,1)='.'
THEN STUFF(lvl_2_comp_item_no,1,1,'')
ELSE lvl_2_comp_item_no
END
FROM CTE where item_no=@item_no FOR XML PATH('')),1,1,'')
FROM
CTE
WHERE
lvl_2_comp_item_no IS NOT NULL AND item_no IS NOT NULL
END
输出正是我需要的格式:
item_no | part_no
JM9027 | GS10702,LB2391,LB2704,LB2834,LB2896,LB6996
当我创建游标时,我在游标的SELECT 语句中使用相同的代码,但是您可以看到是否需要传入父级 (@itemno)。我已经尝试过了,没有有效:
SET NOCOUNT ON;
DECLARE @itemno CHAR(15);
DECLARE @partno VARCHAR(254);
DECLARE @outside_cursor AS CURSOR;
SET @outside_cursor = CURSOR FAST_FORWARD FOR
WITH CTE AS
(SELECT DISTINCT
LTRIM(RTRIM(lvl1.item_no)) AS item_no,
LTRIM(RTRIM(lvl1.comp_item_no)) AS comp_item_no,
CASE
WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE '.%'
THEN LTRIM(RTRIM(lvl1.comp_item_no))
WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE 'E%'
THEN
(SELECT TOP 1
LTRIM(RTRIM(comp_item_no))
FROM
bmprdstr_sql
WHERE
LTRIM(RTRIM(item_no))=LTRIM(RTRIM(lvl1.comp_item_no))
AND LTRIM(RTRIM(comp_item_no)) LIKE '.%'
)
WHEN LTRIM(RTRIM(lvl1.comp_item_no)) LIKE 'ZG%'
THEN
(SELECT TOP 1
LTRIM(RTRIM(comp_item_no))
FROM
bmprdstr_sql
WHERE
LTRIM(RTRIM(item_no))=LTRIM(RTRIM(lvl1.comp_item_no))
AND LTRIM(RTRIM(comp_item_no)) LIKE '.%'
)
ELSE NULL
END AS lvl_2_comp_item_no
FROM
bmprdstr_sql AS lvl1
LEFT JOIN bmprdstr_sql lvl2 ON lvl1.comp_item_no=lvl2.item_no
WHERE
(lvl1.item_no = @itemno) -- <-- problem
AND (lvl1.comp_item_no LIKE '.%' OR lvl1.comp_item_no LIKE 'ZG%'
OR lvl1.comp_item_no LIKE 'E%')
)
SELECT DISTINCT
CASE
WHEN LEFT(item_no,1)='.'
THEN STUFF(item_no,1,1,'')
ELSE item_no
END AS item_no,
part_no =
STUFF(
(SELECT DISTINCT ',' +
CASE
WHEN LEFT(lvl_2_comp_item_no,1)='.'
THEN STUFF(lvl_2_comp_item_no,1,1,'')
ELSE lvl_2_comp_item_no
END
FROM
CTE
WHERE
item_no=@itemno FOR XML PATH('')),1,1,'')
-- ^ problem
FROM
CTE
WHERE
lvl_2_comp_item_no IS NOT NULL
AND item_no IS NOT NULL
OPEN @outside_cursor;
FETCH NEXT FROM @outside_cursor INTO @itemno, @partno;
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO items_parts (item_no, part_no)
VALUES (@itemno, @partno)
FETCH NEXT FROM @outside_cursor INTO @itemno, @partno
END
CLOSE @outside_cursor
DEALLOCATE @outside_cursor
关于如何实现这一点的任何建议?
【问题讨论】:
-
不确定为什么要使用游标插入数据。我没有尝试解析这个大查询来真正了解它在做什么,但这可以重写为基于单个集合的插入。这是一个很好的起点。 spaghettidba.com/2015/04/24/…
-
@SeanLange 每个关于 SQL 游标的问题都会以一种或另一种形式出现此评论。在找到光标之前,我尝试使用基于集合的方法。
-
这是因为几乎每个游标都可以使用基于集合的方法而不是 RBAR 来解决。
标签: sql-server sql-server-2008 tsql stored-procedures cursor