Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否可以让SQL输出子句返回未插入的列?_Sql_Sql Server - Fatal编程技术网

是否可以让SQL输出子句返回未插入的列?

是否可以让SQL输出子句返回未插入的列?,sql,sql-server,Sql,Sql Server,我对数据库做了一些修改,需要将旧数据迁移到新表中。为此,我需要填充一个表(ReportOptions),从原始表(Practice)获取数据,然后填充第二个中间表(PracticeReportOption) 我进行了一次查询,以获取从Practice到ReportOptions所需的所有数据,但在填充中间表时遇到了问题 --Auxiliary tables DECLARE @ReportOption TABLE (PracticeId int /*This field is not on the

我对数据库做了一些修改,需要将旧数据迁移到新表中。为此,我需要填充一个表(ReportOptions),从原始表(Practice)获取数据,然后填充第二个中间表(PracticeReportOption)

我进行了一次查询,以获取从Practice到ReportOptions所需的所有数据,但在填充中间表时遇到了问题

--Auxiliary tables
DECLARE @ReportOption TABLE (PracticeId int /*This field is not on the actual ReportOption table*/, field1, field2...)
DECLARE @PracticeReportOption TABLE (PracticeId int, ReportOptionId int, field1, field2)

--First I get all the data I need to move
INSERT INTO @ReportOption
SELECT P.practiceId, field1, field2...
  FROM Practice P

--I insert it into the new table, but somehow I need to have the repation PracticeId / ReportOptionId
INSERT INTO ReportOption (field1, field2...)
OUTPUT @ReportOption.PracticeId, --> this is the field I don't know how to get
       inserted.ReportOptionId
  INTO @PracticeReportOption (PracticeId, ReportOptionId)
SELECT field1, field2
  FROM @ReportOption

--This would insert the relationship, If I knew how to get it!
INSERT INTO @PracticeReportOption (PracticeId, ReportOptionId)
SELECT PracticeId, ReportOptionId
  FROM @ReportOption

如果我可以引用一个不在OUTPUT子句的目标表上的字段,那就太好了(我想我不能,但我不确定)。关于如何满足我的需要,您有什么想法吗?

您可以使用
合并
而不是插入:

所以换掉这个

INSERT INTO ReportOption (field1, field2...)
OUTPUT @ReportOption.PracticeId, --> this is the field I don't know how to get
       inserted.ReportOptionId
  INTO @PracticeReportOption (PracticeId, ReportOptionId)
SELECT field1, field2
  FROM @ReportOption

关键是使用一个在合并搜索条件下永远不会为true(1=0)的谓词,因此您将始终执行插入,但可以访问源表和目标表中的字段


下面是我用来测试它的全部代码:

CREATE TABLE ReportOption (ReportOptionID INT IDENTITY(1, 1), Field1 INT, Field2 INT)
CREATE TABLE Practice (PracticeID INT IDENTITY(1, 1), Field1 INT, Field2 INT)
CREATE TABLE PracticeReportOption (PracticeReportOptionID INT IDENTITY(1, 1), PracticeID INT, ReportOptionID INT, Field1 INT, Field2 INT)

INSERT INTO Practice VALUES (1, 1), (2, 2), (3, 3), (4, 4)


MERGE INTO ReportOption r USING Practice p ON 1 = 0
WHEN NOT MATCHED THEN
    INSERT (field1, field2)
    VALUES (p.Field1, p.Field2)
    OUTPUT p.PracticeId, inserted.ReportOptionId, inserted.Field1, inserted.Field2
    INTO PracticeReportOption (PracticeId, ReportOptionId, Field1, Field2);

SELECT  *
FROM    PracticeReportOption

DROP TABLE ReportOption
DROP TABLE Practice
DROP TABLE PracticeReportOption 


更多阅读,我所知道的关于这个主题的所有信息的来源是

也许使用MS SQL Server 2005或更低版本的人会发现这个答案很有用


合并仅适用于SQL Server 2008或更高版本。 对于rest,我发现了另一种解决方法,它将使您能够创建某种映射表

以下是SQL 2005的分辨率:

DECLARE @ReportOption TABLE (ReportOptionID INT IDENTITY(1, 1), Field1 INT, Field2 INT)
DECLARE @Practice TABLE(PracticeID INT IDENTITY(1, 1), Field1 INT, Field2 INT)
DECLARE @PracticeReportOption TABLE(PracticeReportOptionID INT IDENTITY(1, 1), PracticeID INT, ReportOptionID INT, Field1 INT, Field2 INT)

INSERT INTO @Practice (Field1, Field2) VALUES (1, 1)
INSERT INTO @Practice (Field1, Field2) VALUES (2, 2)
INSERT INTO @Practice (Field1, Field2) VALUES (3, 3)
INSERT INTO @Practice (Field1, Field2) VALUES (4, 4)

INSERT INTO @ReportOption (field1, field2)
    OUTPUT INSERTED.ReportOptionID, INSERTED.Field1, INSERTED.Field2 INTO @PracticeReportOption (ReportOptionID, Field1, Field2)
    SELECT Field1, Field2 FROM @Practice ORDER BY PracticeID ASC;


WITH CTE AS ( SELECT PracticeID, ROW_NUMBER() OVER ( ORDER BY PracticeID ASC ) AS ROW FROM @Practice )
UPDATE M SET M.PracticeID = S.PracticeID 
    FROM @PracticeReportOption AS M
    JOIN CTE AS S ON S.ROW = M.PracticeReportOptionID

    SELECT * FROM @PracticeReportOption
主要的技巧是,我们用来自源表和目标表的有序数据填充映射表两次。
有关此处的详细信息:

您可以在
输出
子句中返回插入行的表的任何列。因此,即使在
INSERT
语句中没有为给定列提供值,也可以在
OUTPUT
子句中指定该列。但是,您不能从其他表返回SQL变量或列。@marc_感谢您的回复,但我在目标表中没有需要的字段(我需要PracticeId,它不在ReportOption上)。谢谢,这就成功了!我本来打算用一个假的临时字段,但这个要优雅得多。太棒了!这个把戏是一粒金子!已添加到集合的第一行!苏威特!我希望它不必使用偶尔出现错误的MERGE命令,但它在其他方面非常优雅。请注意。我使用了一个merge语句,它在过去的一年中随着使用量的增加而增加。我们在保存过程中开始超时,结果是因为merge语句总是锁定表,所以每4分钟就有35-160秒的表锁定时间。我必须重新构造几个merge语句来使用insert/updates,并将每次insert/update更新的行数限制为500,以避免表锁定。我估计这个非常重要的表每天被锁定将近2个半小时,这导致了从缓慢保存到超时的一切。此外,许多人的交易失败之处在于MERGE中有大量未修复的bug,这些bug在奇怪的条件下出现。例如,请参见亚伦·伯特朗的著作。微软拒绝修复其中一些漏洞,我的秘密怀疑是微软不推荐他们的整个服务只是为了让我们忘记合并声明中所有他们不想修复的漏洞。这并不能解决我的问题。我需要
Output
my
Insert
到一个输出
,该表包含来自目标
标识
值,以及来自源
的非
插入值(PK)(顺便说一句,这样我就可以(在不同的批次中)使用该输出
标识
值填充源
中的
)。如果没有
合并
,我想我必须:a)开始
事务
,b)获得下一个
身份
,c)使用计算的
身份
,d)设置
身份
,e)将
插入目标
,从temp
,f)清除
标识\u插入
CREATE TABLE ReportOption (ReportOptionID INT IDENTITY(1, 1), Field1 INT, Field2 INT)
CREATE TABLE Practice (PracticeID INT IDENTITY(1, 1), Field1 INT, Field2 INT)
CREATE TABLE PracticeReportOption (PracticeReportOptionID INT IDENTITY(1, 1), PracticeID INT, ReportOptionID INT, Field1 INT, Field2 INT)

INSERT INTO Practice VALUES (1, 1), (2, 2), (3, 3), (4, 4)


MERGE INTO ReportOption r USING Practice p ON 1 = 0
WHEN NOT MATCHED THEN
    INSERT (field1, field2)
    VALUES (p.Field1, p.Field2)
    OUTPUT p.PracticeId, inserted.ReportOptionId, inserted.Field1, inserted.Field2
    INTO PracticeReportOption (PracticeId, ReportOptionId, Field1, Field2);

SELECT  *
FROM    PracticeReportOption

DROP TABLE ReportOption
DROP TABLE Practice
DROP TABLE PracticeReportOption 
DECLARE @ReportOption TABLE (ReportOptionID INT IDENTITY(1, 1), Field1 INT, Field2 INT)
DECLARE @Practice TABLE(PracticeID INT IDENTITY(1, 1), Field1 INT, Field2 INT)
DECLARE @PracticeReportOption TABLE(PracticeReportOptionID INT IDENTITY(1, 1), PracticeID INT, ReportOptionID INT, Field1 INT, Field2 INT)

INSERT INTO @Practice (Field1, Field2) VALUES (1, 1)
INSERT INTO @Practice (Field1, Field2) VALUES (2, 2)
INSERT INTO @Practice (Field1, Field2) VALUES (3, 3)
INSERT INTO @Practice (Field1, Field2) VALUES (4, 4)

INSERT INTO @ReportOption (field1, field2)
    OUTPUT INSERTED.ReportOptionID, INSERTED.Field1, INSERTED.Field2 INTO @PracticeReportOption (ReportOptionID, Field1, Field2)
    SELECT Field1, Field2 FROM @Practice ORDER BY PracticeID ASC;


WITH CTE AS ( SELECT PracticeID, ROW_NUMBER() OVER ( ORDER BY PracticeID ASC ) AS ROW FROM @Practice )
UPDATE M SET M.PracticeID = S.PracticeID 
    FROM @PracticeReportOption AS M
    JOIN CTE AS S ON S.ROW = M.PracticeReportOptionID

    SELECT * FROM @PracticeReportOption