是否可以在创建时插入外键值?

时间:2012-12-10 17:29:44

标签: sql sql-server foreign-keys

SQL Server的示例表。

  • MainRecords id, record
  • AuxRecords mainRecords_id, record
  • SourceRecords record1, record2

MainRecords.id是一个自我递增的主要身份密钥。

是否可以从SourceRecords中选择并同时插入MainRecordsAuxRecords,以便MainRecords.record = record1AuxRecords.record = record2和{{1所有在一个声明中?

编辑:

根据下面的提示,我试过了......

AuxRecords.mainRecords_id = MainRecords.id

但不幸的是得到错误:

DECLARE @MainRecords table(id int PRIMARY KEY IDENTITY, record varchar(5))
DECLARE @AuxRecords table(mainRecords_id int, record varchar(5))
DECLARE @SourceRecords table(record1 varchar(5), record2 varchar(5))

INSERT @SourceRecords VALUES ('a', 'a')
INSERT @SourceRecords VALUES ('a', 'b')
INSERT @SourceRecords VALUES ('a', 'c')
INSERT @SourceRecords VALUES ('b', 'a')
INSERT @SourceRecords VALUES ('b', 'b')
INSERT @SourceRecords VALUES ('b', 'c')
INSERT @SourceRecords VALUES ('c', 'a')
INSERT @SourceRecords VALUES ('c', 'b')
INSERT @SourceRecords VALUES ('c', 'c')

INSERT INTO @MainRecords (record)
  OUTPUT inserted.id, @SourceRecords.record2
  INTO @AuxRecords (mainRecords_id, record)
SELECT record1 FROM @SourceRecords

select * from @MainRecords
select * from @AuxRecords

如果我将这些表类型变量更改为实际表,我会收到错误:

Msg 137, Level 16, State 1, Line 16
Must declare the scalar variable "@SourceRecords".

以下工作正常,但显然它不是一个完整的解决方案。我只是展示它来证明我的语法是正确的。

Msg 4104, Level 16, State 1, Line 3
The multi-part identifier "SourceRecords.record2" could not be bound.

所以...除非有一些我不知道的技巧,似乎INSERT INTO @MainRecords (record) OUTPUT inserted.id --, @SourceRecords.record2 INTO @AuxRecords (mainRecords_id) --, record) SELECT record1 FROM @SourceRecords 是这个问题的死胡同解决方案。

使用触发器创建视图或空表的其他建议不是问题的“单一语句”解决方案。此外,它们增加了默默无闻,而添加一些额外的列和使用存储过程同样复杂,但更明显和直接。

3 个答案:

答案 0 :(得分:1)

社区维基

问题中没有足够的信息来编写代码来解决问题。所以,这里是一个“通用”输出子句示例,除了显示如何使用OUTPUT之外,它与此问题完全无关:

这将在单个语句中删除,插入和返回多行

DECLARE @OldTable table(col1 int, col2    varchar(5), col3 char(5), col4     datetime)
DECLARE @NewTable table(col1 int, column2 varchar(5), col3 int    , col_date char(23), extravalue int, othervalue varchar(5))
INSERT @OldTable VALUES (1 , 'AAA' ,'A'  ,'1/1/2010'           )
INSERT @OldTable VALUES (2 , 'BBB' ,'12' ,'2010-02-02 10:11:22')
INSERT @OldTable VALUES (3 , 'CCC' ,null ,null                 )
INSERT @OldTable VALUES (4 , 'B'   ,'bb' ,'2010-03-02'         )

DELETE @OldTable           --<<<alter table 1
    OUTPUT DELETED.col1    --<<<alter table 2
          ,DELETED.col2
          ,CASE
               WHEN ISNUMERIC(DELETED.col3)=1 THEN DELETED.col3 
               ELSE NULL END
          ,DELETED.col4
          ,CONVERT(varchar(5),DELETED.col1)+'!!'
        INTO @NewTable (col1, column2, col3, col_date, othervalue)
    OUTPUT 'Rows Deleted: ', DELETED.* --<<<returns a result set
    WHERE col1 IN (2,4)

SELECT * FROM @NewTable

输出:

               col1        col2  col3  col4
-------------- ----------- ----- ----- -----------------------
Rows Deleted:  2           BBB   12    2010-02-02 10:11:22.000
Rows Deleted:  4           B     bb    2010-03-02 00:00:00.000

(2 row(s) affected)

col1        column2 col3        col_date                extravalue  othervalue
----------- ------- ----------- ----------------------- ----------- ----------
2           BBB     12          Feb  2 2010 10:11AM     NULL        2!!
4           B       NULL        Mar  2 2010 12:00AM     NULL        4!!

(2 row(s) affected)

答案 1 :(得分:0)

@DG您无法在单个语句中修改多个表。正如@RBarryYoung建议你应该使用存储过程和事务来做这种事情。另一个更极端的选择是在MainRecords和AuxRecords上创建一个将行连接在一起的视图,然后在视图上创建一个before触发器,将其分成两个插入,一个针对每个基表。然后,您的客户端可以对视图执行单个插入操作。总而言之,我认为存储过程/事务方法更加明显。

答案 2 :(得分:0)

从实际角度来看,@ BStateham和@RarryYoung为您提供了正确而完整的答案。但是,如果这是一个技术问题,你只想知道是否可能,我会说:是的。

引入一个包含两列的伪表:record1,record2。

然后在此表上创建一个INSTEAD OF INSERT触发器,它只是将信息添加到其他两个表中。

执行单个语句'INSERT INTO MyBogusTable(record1,record2)VALUES(1,2)'时,您实际上会使用一个语句将值插入两个不同的表中。

无论如何,这是丑陋的,不推荐。这是愚蠢和令人困惑的(必须使用translate.google这个词)。

但是:对于'是否可能'这个问题,回答“是”是一种可能性。 好的,调用存储过程也是“单一语句”,但是...... aehm ......好吧。