因为它在酸和语法方面都不容易处理。
如果存在则更新的条件尚不清楚。
例如,将以下查询中的“插入”替换为 upsert
insert into t_something
select * from t_whatever
没有外键,没有主键。
你想怎么更新?
where 条件是选择还是更新?
最终,您必须编写条件,然后您也可以执行“update/insert if”...
通常,当您问自己 upsert 问题时,您处理的插入/更新错误。
你在考虑对象而不是固定的术语。
你想遍历一个对象数组,然后插入 if count(*) on exists is 0 else update。
这就是面向对象的命令式编程的工作原理,但 SQL 不是这样工作的。
在 SQL 中,您使用 SET 进行操作。
您可以轻松地进行内部连接 - 更新 SET
和一个左连接,其中 null 在同一个 SET 上插入。
这就像合并一样舒适,而且可读性更高,调试也更简单。
而且它可能会更快。
您已经可以通过将更新和插入放入事务中来确保它是原子的。
想到 upsert,你接下来想要哪个白痴? “UpSertLeteTrunc”?默德尔?
或者可能是 truncsert ?
到目前为止,还有更重要的事情要做。
这就是我在 SQL-Server 上使用 MERGE 进行 Upsert 的方式:
-- How to create the XML
/*
DECLARE @xml XML
SET @xml = ( SELECT (SELECT * FROM T_Benutzer FOR XML PATH('row'), ROOT('table'), ELEMENTS xsinil) AS outerXml )
-- SELECT @xml
*/
DECLARE @xml xml
SET @xml = '<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
<PLK_UID>7CA68E6E-E998-FF92-BE70-126064765EAB</PLK_UID>
<PLK_Code>A2 Hoch</PLK_Code>
<PLK_PS_UID>6CF3B5AB-C6C8-4A12-8717-285F95A1084B</PLK_PS_UID>
<PLK_DAR_UID xsi:nil="true" />
<PLK_Name_DE>Mit Legende</PLK_Name_DE>
<PLK_Name_FR>Avec Légende</PLK_Name_FR>
<PLK_Name_IT>Con Leggenda</PLK_Name_IT>
<PLK_Name_EN>With Legend</PLK_Name_EN>
<PLK_IsDefault>0</PLK_IsDefault>
<PLK_Status>1</PLK_Status>
</row>
</table>'
DECLARE @handle INT
DECLARE @PrepareXmlStatus INT
EXEC @PrepareXmlStatus = sp_xml_preparedocument @handle OUTPUT, @XML
;WITH CTE AS
(
SELECT
PLK_UID
,PLK_Code
,PLK_PS_UID
,PLK_DAR_UID
,PLK_Name_DE
,PLK_Name_FR
,PLK_Name_IT
,PLK_Name_EN
,PLK_IsDefault
,PLK_Status
FROM OPENXML(@handle, '/table/row', 2) WITH
(
"PLK_UID" uniqueidentifier 'PLK_UID[not(@*[local-name()="nil" and . ="true"])]'
,"PLK_Code" character varying(10) 'PLK_Code[not(@*[local-name()="nil" and . ="true"])]'
,"PLK_PS_UID" uniqueidentifier 'PLK_PS_UID[not(@*[local-name()="nil" and . ="true"])]'
,"PLK_DAR_UID" uniqueidentifier 'PLK_DAR_UID[not(@*[local-name()="nil" and . ="true"])]'
,"PLK_Name_DE" national character varying(255) 'PLK_Name_DE[not(@*[local-name()="nil" and . ="true"])]'
,"PLK_Name_FR" national character varying(255) 'PLK_Name_FR[not(@*[local-name()="nil" and . ="true"])]'
,"PLK_Name_IT" national character varying(255) 'PLK_Name_IT[not(@*[local-name()="nil" and . ="true"])]'
,"PLK_Name_EN" national character varying(255) 'PLK_Name_EN[not(@*[local-name()="nil" and . ="true"])]'
,"PLK_IsDefault" bit 'PLK_IsDefault[not(@*[local-name()="nil" and . ="true"])]'
,"PLK_Status" int 'PLK_Status[not(@*[local-name()="nil" and . ="true"])]'
) AS tSource
WHERE (1=1)
-- AND NOT EXISTS
-- (
-- SELECT * FROM T_VWS_Ref_PdfLegendenKategorie
-- WHERE T_VWS_Ref_PdfLegendenKategorie.PLK_UID = tSource.PLK_UID
--)
)
-- SELECT * FROM CTE
MERGE INTO T_VWS_Ref_PdfLegendenKategorie AS A
USING CTE ON CTE.PLK_UID = A.PLK_UID
WHEN MATCHED
THEN UPDATE
SET A.PLK_Code = CTE.PLK_Code
,A.PLK_PS_UID = CTE.PLK_PS_UID
,A.PLK_DAR_UID = CTE.PLK_DAR_UID
,A.PLK_Name_DE = CTE.PLK_Name_DE
,A.PLK_Name_FR = CTE.PLK_Name_FR
,A.PLK_Name_IT = CTE.PLK_Name_IT
,A.PLK_Name_EN = CTE.PLK_Name_EN
,A.PLK_IsDefault = CTE.PLK_IsDefault
,A.PLK_Status = CTE.PLK_Status
WHEN NOT MATCHED BY TARGET THEN
INSERT
(
PLK_UID
,PLK_Code
,PLK_PS_UID
,PLK_DAR_UID
,PLK_Name_DE
,PLK_Name_FR
,PLK_Name_IT
,PLK_Name_EN
,PLK_IsDefault
,PLK_Status
)
VALUES
(
CTE.PLK_UID
,CTE.PLK_Code
,CTE.PLK_PS_UID
,CTE.PLK_DAR_UID
,CTE.PLK_Name_DE
,CTE.PLK_Name_FR
,CTE.PLK_Name_IT
,CTE.PLK_Name_EN
,CTE.PLK_IsDefault
,CTE.PLK_Status
)
-- WHEN NOT MATCHED BY SOURCE THEN DELETE
;
EXEC sp_xml_removedocument @handle