SQL Server 2008:复杂的插入

时间:2011-04-13 18:53:35

标签: sql sql-server-2008 ssis database-cursor

我有一个名为Employees的表格:

BeginYear  |   EndYear   |    Name
1974           1983           Robert

对于Employees中的每条记录,我需要将每年插入一个名为EmployeeYears

的新表中

所以:

For Each Record in Employees
    For i as int = Begin Year to End year
        INSERT i, Name into EmployeeYears

任何方法在SQL中执行此操作...可能使用游标?

6 个答案:

答案 0 :(得分:3)

如果你有一个数字表,你可以加入它来获取单独的年份记录并避免使用光标。我只是用1965年到968年的数字表编号,但是一个实数数字表(也不是一个临时表,如下所示,但是存在于你的模式中)可能有几百万个记录,因为它对于大量的比较很有用。

create table #Numbers (Number int)
insert into #Numbers
select 1965
union
select 1966
union 
select 1967
union 
select 1968

create table #employees (name varchar (50), beginyear int, endyear int)
insert into #employees
select 'Dick', 1966, 1968
union all 
select 'harry', 1965, 1967
union all 
select 'tom', 1955, 1966

insert into EmployeeYears (Name, [Year])
select Name, n.number 
from #Employees e
join #Numbers n on  n.number between e.beginyear and e.endyear
order by name

答案 1 :(得分:3)

它的要点是使用WITH语句创建所有记录并使用它们插入到最终表中。

;WITH q AS (
  SELECT Year = BeginYear
         , Name
  FROM   Employees
  UNION ALL
  SELECT q.Year + 1
         , q.Name
  FROM   q
         INNER JOIN Employees e ON e.Name = q.Name
                                   AND e.EndYear > q.Year
)
INSERT INTO EmployeeYears
SELECT * FROM q
OPTION(MAXRECURSION 0)

<强> TESTDATA

CREATE TABLE Employees (BeginYear INTEGER, EndYear INTEGER, Name VARCHAR(32))
CREATE TABLE EmployeeYears (Year INTEGER, Name VARCHAR(32))

INSERT INTO Employees
  SELECT 1974, 1976, 'Robert'
  UNION ALL SELECT 1972, 1975, 'Lieven'

<强>结果

SELECT  *
FROM    EmployeeYears
ORDER BY Name, Year

1972    Lieven
1973    Lieven
1974    Lieven
1975    Lieven
1974    Robert
1975    Robert
1976    Robert

答案 2 :(得分:1)

是的,你实际上必须做一个循环...我不想使用CURSORS,但这种情况sorta是有意义的......无论如何,这里的代码只是一个直接的循环来向你展示你可以做到这一点SQL中的代码类型:

DECLARE @Employee VARCHAR(100)
DECLARE @BeginYear INT, @EndYear INT, @i INT

SET @Employee = ''

WHILE (1=1)
BEGIN
    SET @Employee = (SELECT TOP 1 Name FROM Employees ORDER BY Name WHERE Name > @Employee)

    IF @Employee IS NULL BREAK

    SELECT @BeginYear = BeginYear, @EndYear = EndYear FROM Employees WHERE Name = @Employee

    SET @i = @BeginYear

    WHILE (@i <= @EndYear)
    BEGIN
        INSERT INTO EmployeeYears (Year, Name) VALUES (@i, @Employee)
        SET @i = @i + 1
    END
END

答案 3 :(得分:1)

您可以使用递归CTE:

;WITH CTE AS
(
    SELECT BeginYear, EndYear, Name
    FROM Employees
    UNION ALL
    SELECT BeginYear+1, EndYear, Name
    FROM CTE 
    WHERE BeginYear < EndYear
)  
INSERT INTO EmployeeYears (Year, Name)
SELECT BeginYear, Name
FROM CTE 
ORDER BY Name, BeginYear
OPTION(MAXRECURSION 0)

答案 4 :(得分:0)

您可以使用递归过程。如下所示:

CREATE Procedure InsertYear
    @Name ....
    @BeginYear ...
    @EndYear ...
AS
{
     INSERT INTO  EmployeeYears  VALUES(@BeginYear, @Name);
     SET  @BeginYear = @BeginYear + 1
     IF @BeginYear < @EndYear
     BEGIN
         InsertYear(@Name, @BeginYear, @EndYear)
     END

     RETURN
}

答案 5 :(得分:0)

您可以这样做但如果开始或结束超过2047

则会失败
INSERT INTO EmployeeYears (number, name)
SELECT v.number, e.name
FROM 
    Employees e
    INNER JOIN master..spt_values v on 
    v.number between beginYear and endYear