Rem*_*emy 3 database-design sql-server t-sql
我有一个Person表,其中有一created_by列引用了表本身的主 ID。因此,可能是一名员工将另一名员工添加到数据库中。它工作正常。
但People也可以自己添加(注册)。所以created_by列中的值应该是该列的自动递增值id。但该值显然在插入之后才可用。
所以我可以(a)使引用不检查值,(b)在开头添加一个默认值或(c)使列可以为空。所有的选择对我来说都不好。
MySQL的方言是这样的:
SET FOREIGN_KEY_CHECKS = 0;
INSERT INTO EMPLOYEE VALUES('12345','67890'),('67890','12345');
SET FOREIGN_KEY_CHECKS = 1;
Run Code Online (Sandbox Code Playgroud)
...但我找不到 SQL Server 的 T-SQL 类似的东西。
将自引用条目插入 SQL Server
对于标题中的一般问题,您可以在简单的插入中添加直接循环引用,例如
INSERT node
(id , name , parent_id)
VALUES (123, 'Test', 123 )
Run Code Online (Sandbox Code Playgroud)
因为考虑到所有新数据都会强制执行约束:只要语句完成后 FX 引用的值存在,一切都很好。这与在链表中插入多个值相同:
INSERT node
(id , name , parent_id)
VALUES (101, 'Test1', 100 )
, (102, 'Test2', 101 )
, (103, 'Test3', 102 )
Run Code Online (Sandbox Code Playgroud)
或间接循环引用:
INSERT node
(id , name , parent_id)
VALUES (201, 'Test5', 203 )
, (202, 'Test6', 201 )
, (203, 'Test7', 202 )
Run Code Online (Sandbox Code Playgroud)
所以 created_by 列中的值应该是 id 列的自增值
这带来了一个问题,因为在插入之前您不知道生成的是什么,实际上没有可靠的知道方法。对于插入单个行,您可以使用SCOPE_IDENTITY()立即更新新行:
INSERT node
(name )
VALUES ('Test')
-- and now make the circular reference
UPDATE node
SET parent_id = SCOPE_IDENTITY()
WHERE id = SCOPE_IDENTITY()
Run Code Online (Sandbox Code Playgroud)
在上面的例子中 ifparent_id是一个必需的列(NOT NULL用 no声明DEFAULT)那么你需要提供一个虚拟的临时有效值而不是把它放在初始INSERT语句之外,像这样:
INSERT node
(name , parent_id)
VALUES ('Test', 0 )
-- and now make the circular reference
UPDATE node
SET parent_id = SCOPE_IDENTITY()
WHERE id = SCOPE_IDENTITY()
Run Code Online (Sandbox Code Playgroud)
为了处理多行的插入(在您描述的情况下不太可能,但在其他地方很常见),您可以使用该OUTPUT子句读取为每行创建的 ID 以供进一步参考。我不会在这里讨论,因为它对当前问题来说太过分了,请参阅https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql了解更多详细信息.
所以 created_by 列中的值应该是 id 列的自增值
事实证明,SEQUENCE如果您拥有 2012 或更高版本,则可以使用 SQL Server 中的a 完成此操作,这是比上述多语句选项更简洁的解决方案,请参阅 SQLing4ever 的答案以获取有效示例。在 2012 年之前,此功能不可用,因此如果您需要支持较旧的 SQL Server 实例,则需要回退到此答案中的方法。
看起来您正在为主键使用身份。如果您需要灵活使用主键,我建议您使用序列。它看起来像这样。
CREATE SEQUENCE SQ_temp AS INT INCREMENT BY 1 START WITH 1
CREATE TABLE Users
( ID INT PRIMARY KEY DEFAULT NEXT VALUE FOR SQ_temp
, UserName VARCHAR(30)
, createdBy INT REFERENCES Users (ID)
)
INSERT INTO dbo.Users
(
ID
, UserName
, createdBy
)
VALUES
(NEXT VALUE FOR SQ_temp,'User1', NEXT VALUE FOR SQ_temp)
, (NEXT VALUE FOR SQ_temp,'User2', NEXT VALUE FOR SQ_temp)
, (NEXT VALUE FOR SQ_temp,'User3', NEXT VALUE FOR SQ_temp)
SELECT *
FROM dbo.Users AS u
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2236 次 |
| 最近记录: |