如何插入动态行数

时间:2015-12-16 18:15:04

标签: sql-server tsql cursor temp-tables

我有一个物料表作为源表,如下所示:

CREATE TABLE dbo.MATERIAL (
    ID int IDENTITY(1,1) NOT NULL,
    CATEGORY_ID int NOT NULL,
    SECTION_ID int NOT NULL,
    STATUS_ID int NOT NULL
)

我也有一个Order表作为目标表,如下所示:

CREATE TABLE dbo.ORDER (
    ID int IDENTITY(1,1) NOT NULL,
    MATERIAL_ID int NOT NULL
)

我将ome数据发送到SQL Server到存储过程并创建了以下临时表

DECLARE @temptable TABLE (
    CATEGORY_ID int NOT NULL,
    SECTION_ID int NOT NULL,
    STATUS_ID int NOT NULL,
    COUNT int NOT NULL
)

并填写了如下数据:

CATEGORY_ID    SECTION_ID    STATUS_ID    COUNT
-----------    ----------    ---------    -----
     3             8             1          10
     8             2             2          11 
     4             6             1           8

我想要的是匹配MATERIAL表中的COUNT个材料,这些材料匹配同一行的给定CATEGORY_ID,SECTION_ID和STATUS_ID三元组;然后将这些记录的ID插入目标表ORDER。

我该如何完成这项任务?

问候。

2 个答案:

答案 0 :(得分:1)

现在丢掉了一堆以前的工作,我认为我理解要求。

这是一个有效的SQL FIDDLE

这会生成一个名为GENROWS的数据集,其中包含的行数等于temptable中最大计数的计数。它通过使用递归公用表表达式(CTE)为temptable中的每个最大计数计数生成1行来实现此目的。 然后,它使用此数据集连接到temptable和material,以生成需要按顺序插入材料的次数。

我不喜欢使用保留字,所以我将order调整为morder,我建议调整列count,否则你将被困在[]中。不时。

注意:这假设材料表中不存在重复项(具有相同category_ID,Section_Id和Status_ID的记录)。如果有;然后这可能会或可能不会像预期的那样。

最后,现在我已经更好地理解了在你不肯定之后你会发现什么,与使用游标相比,你会看到很多性能提升。因为必须以某种方式生成行。这仍然可以更快一些,因为我们生成集合并一次插入所有而不是单独插入。但是产生存储和检索产生的数据集可能会抵消这种增益。只有测试才能证明。

WITH 
GenRows (RowNumber, Val) AS (
   -- Anchor member definition
   SELECT 1 AS RowNumber, (Select max(count) val from temptable) val
   UNION ALL
   -- Recursive member definition
   SELECT a.RowNumber + 1  AS RowNumber, a.val
   FROM   GenRows a
   WHERE  a.RowNumber < a.val
)
Insert into morder (Material_ID)  
SELECT A.ID
FROM material A
INNER JOIN temptable B
   on A.Category_ID = B.Category_ID
  and A.Section_Id = B.Section_Id
  and A.Status_Id = B.Status_ID
INNER JOIN GenRows
  on GenRows.RowNumber <= b.[count]

答案 1 :(得分:1)

我想我找到了解决方案。我应该使用CURSOR。以下代码可以解决这个问题:

DECLARE @MATERIAL_ID int
DECLARE @CATEGORY_ID int
DECLARE @SECTION_ID int
DECLARE @STATUS_ID int
DECLARE @COUNT int

DECLARE cur CURSOR LOCAL FOR
SELECT
    CATEGORY_ID,
    SECTION_ID,
    STATUS_ID,
    COUNT
FROM
    @temptable 

OPEN cur
FETCH NEXT FROM cur INTO @CATEGORY_ID, @SECTION_ID, @STATUS_ID, @COUNT
WHILE @@FETCH_STATUS = 0
    BEGIN
        INSERT INTO
            dbo.ORDER
            (MATERIAL_ID)
        SELECT
            TOP (@COUNT) ID
        FROM
            dbo.MATERIAL AS m
        WHERE
            m.CATEGORY_ID = @CATEGORY_ID
            AND m.SECTION_ID = @SECTION_ID
            AND m.STATUS_ID = @STATUS_ID

        FETCH NEXT FROM cur INTO @CATEGORY_ID, @SECTION_ID, @STATUS_ID, @COUNT
    END
CLOSE cur
DEALLOCATE cur