如何/可以在T-SQL中执行此操作?

如何/可以在T-SQL中执行此操作?,sql,sql-server,tsql,stored-procedures,database-design,Sql,Sql Server,Tsql,Stored Procedures,Database Design,所以我有一张桌子 CREATE TABLE Versions ( id INT IDENTITY(1,1), title NVARCHAR(100), PRIMARY KEY (id) ) 还有一张桌子 CREATE TABLE Questions ( id INT IDENTITY(1,1), subsection_id INT NOT NULL, qtext NVARCHAR(400) NOT NULL, version_id INT

所以我有一张桌子

CREATE TABLE Versions (
    id INT IDENTITY(1,1),
    title NVARCHAR(100),
    PRIMARY KEY (id)
)
还有一张桌子

CREATE TABLE Questions (
    id INT IDENTITY(1,1),
    subsection_id INT NOT NULL,
    qtext NVARCHAR(400) NOT NULL,
    version_id INT NOT NULL,
    viewtype INT NOT NULL DEFAULT 1,
    PRIMARY KEY (id),
    FOREIGN KEY (subsection_id) REFERENCES Subsections(id),
    FOREIGN KEY (version_id) REFERENCES Versions(id)
);
它的视觉表现像

--                                            Questions
-- ============================================================================================================================
--   id  |                 qtext                                              |  subsection_id  |  version_id   |    viewtype
-- =============================================================================================================================
--    1  | 'Does Hillary Clinton look good in orange?'                        |      1          |       1       |        1
--    2  | 'How many prime numbers are there?'                                |      1          |       1       |        1
--    3  | 'What do I suck at writing SQL?'                                   |      1          |       1       |        1
--    4  | 'Would Jon Skeet beat Mark Zuckerberg in a programming contest?'   |      1          |       1       |        1
我需要的是一个过程,既向Versions表中插入新行,又向Questions表中添加所有当前行,并适当增加ID,版本ID等于刚刚创建的版本的ID

例如:

如果版本来自

id | title 
-----------
 1 | "V1" 
 2 | "V2" 
然后问题就来了

利用我有限的数据库技能的最佳尝试:

CREATE PROCEDURE OntoNewVersion
    @new_title NVARCHAR(100) 
AS  
    INSERT INTO Versions (title) VALUES (@new_title)
    SET @versid = SCOPE_IDENTITY()
    SET @qrows = SELECT COUNT(*) FROM Questions; -- this is wrong, I know
    SET @i = 1;
    WHILE @i <= @qrows
        BEGIN
            SET @thisq = SELECT * FROM Questions WHERE id=@i
            INSERT INTO Questions (qtext,subsection_id,version_id,viewtype) VALUES (@thisq.qtext,@thisq.subsection_id,@versid,@thisq.viewtype);
        END

这接近正确吗?什么需要改变?有没有更好的方法呢?

您可以尝试下面的查询

CREATE PROCEDURE OntoNewVersion
    @new_title NVARCHAR(100) 
AS 
BEGIN 
 BEGIN TRY
  BEGIN TRANSACTION T1
    DECLARE @versid INT
    INSERT INTO Versions (title) VALUES (@new_title)
    SET @versid = SCOPE_IDENTITY()


    INSERT INTO Questions 
        (qtext,subsection_id,version_id,viewtype)  
    SELECT qtext, subsection_id,@versid,viewtype 
    FROM Questions  
  COMMIT TRANSACTION T1
 END TRY

 BEGIN CATCH
  IF(@@TRANCOUNT>0)
    BEGIN 
        ROLLBACK TRANSACTION T1
    END
  ;THROW    
 END CATCH
END

那是行不通的。事实上,这里根本不需要循环。您应该看看如何使用输出。请看一看我的答案,为什么你要创建多个问题的副本?似乎您在这里遇到了一些规范化问题。@SeanLange否。我不想详细介绍业务逻辑,但基本上,这个过程相当于将问题移到一个新版本上,初始化为旧问题,并将旧问题存储起来以供报告之用。然后,您需要确定要复制哪一组问题。你把它编码的方式会成倍地增加问题的数量。第一次用4个问题运行此程序时,您将有8个问题,下一次将有16个问题,等等…除非您包含where子句以将问题限制在某个组。为什么建议使用MAXId而不是您发布的内容?你发布的是正确的方法。使用MAXId容易出现竞争条件和并发性。这不是一个好方法。这纯粹是因为一个无关的个人经历,一个失败的交易导致我的身份值仍然增加,并持有一个实际上不存在的假值。哈???SCOPE_IDENTITY将返回当前作用域中的最后一个标识值。如果插入失败,仍将返回该值,但未插入该行。处理这个问题的方法是把整个事情放在一个事务中。这样,如果“插入到版本”失败,则“插入到问题”也将回滚。@SeanLange您是对的!在像这个问题这样的情况下,SCOPE_标识将是添加事务和TRY/CATCH的方式,这是坚如磐石的。
CREATE PROCEDURE OntoNewVersion
    @new_title NVARCHAR(100) 
AS 
BEGIN 
 BEGIN TRY
  BEGIN TRANSACTION T1
    DECLARE @versid INT
    INSERT INTO Versions (title) VALUES (@new_title)
    SET @versid = SCOPE_IDENTITY()


    INSERT INTO Questions 
        (qtext,subsection_id,version_id,viewtype)  
    SELECT qtext, subsection_id,@versid,viewtype 
    FROM Questions  
  COMMIT TRANSACTION T1
 END TRY

 BEGIN CATCH
  IF(@@TRANCOUNT>0)
    BEGIN 
        ROLLBACK TRANSACTION T1
    END
  ;THROW    
 END CATCH
END