MSSQL插入n次,其中n来自select

时间:2016-11-25 08:50:06

标签: sql-server tsql

我有一个表格,其中包含一个列中的数字,用于定义一个属性有多少个车库。现在我需要向所有车库添加额外的信息(大小,停车位数量,租赁费等),所以我必须通过插入与车库一样多的记录为不同的表中的每个车库创建记录。

我想要完成的事情:

  

SELECT ID,GarageCount FROM Properties

     

- 运行下一个语句GarageCount次

     

INSERT INTO Garages(PropertyID)VALUES(Property.ID)

我需要在属性表中的所有属性中运行它,其中GarageCount> 0

Properties.ID是PK,Garages.PropertyID是FK。

2 个答案:

答案 0 :(得分:3)

你不需要在循环中运行""样式。您可以使用公用表表达式生成行,每个属性的行数与该属性中的车库一样多:

with GarageRows as (
select id
    , garagecount
    , 0 [counter]
from Properties
union all
select p.id
    , 1
    , gr.counter + 1
from GarageRows gr
    inner join Properties p on gr.id = p.id
where gr.counter + 1 < p.garagecount)
insert into Garages(PropertyID)
select gr.ID
from GarageRows gr
where gr.garagecount > 0

如果您只想测试上面的CTE结果,您可以运行以下查询,该查询生成两个属性的行,一个有2个车库,另一个有4个车库。

declare @properties table (id int, garagecount int)
insert @properties values (1, 2), (2, 4)

;with GarageRows as (
select id
    , garagecount
    , 0 [counter]
from @Properties
union all
select p.id
    , 1
    , gr.counter + 1
from GarageRows gr
    inner join @Properties p on gr.id = p.id
where gr.counter + 1 < p.garagecount)
select gr.ID
from GarageRows gr
where gr.garagecount > 0
order by gr.ID

答案 1 :(得分:2)

您可以使用Numbers表来避免循环和复杂查询。 Numbers是一个简单的表,包含0以上的数字。

如果您使用Numbers表加入,您的查询将变得微不足道:

INSERT INTO Garages (PropertyID) 
Select Property.ID
From Property inner join Numbers on Numbers.Number<Property.GarageCount
where garagecount>0 

这将重复相同的行,与定义的GarageCount重复多次。

Numbers表可用于许多场景,包括日期计算,字符串拆分,识别范围中的间隙以及将循环转换为无限快的设置操作。 Aaron Bertrand撰写了许多文章that explain how to generate and how to use Numbers table

Aaron Bertrand的文章展示了一种生成带索引和压缩的Numbers表的快速方法(即使在带有SQL Server 2016 SP1的Express版本中也可用):

DECLARE @UpperBound INT = 1000000;

;WITH cteN(Number) AS
(
  SELECT ROW_NUMBER() OVER (ORDER BY s1.[object_id]) - 1
  FROM sys.all_columns AS s1
  CROSS JOIN sys.all_columns AS s2
)
SELECT [Number] INTO dbo.Numbers
FROM cteN WHERE [Number] <= @UpperBound;

CREATE UNIQUE CLUSTERED INDEX CIX_Number ON dbo.Numbers([Number])
WITH 
(
  FILLFACTOR = 100,      
  DATA_COMPRESSION = ROW -- if the table is large enough to matter
);