【问题标题】:Common syntax in MySQL and MSSQL for IF INSERT ELSE UPDATEMySQL 和 MSSQL 中用于 IF INSERT ELSE UPDATE 的通用语法
【发布时间】:2020-01-14 09:31:45
【问题描述】:

我有一个 PHP 7.3 项目,它通过 PDO 连接到 MySQL 数据库或 MSSQL 数据库,具体取决于在 Linux 或 Windows 上运行。

如果唯一值尚未在该表中,我想将新值插入表中。如果它已经在表中,我想更新非唯一值。

我也搜索了很多文档和 SO 帖子,但我找不到一种语法,它在一个查询中针对两种数据库类型

SQL Server 查询:

IF (EXISTS (SELECT * FROM failed_logins_ip_address WHERE ip_address = 'xxx'))
  BEGIN
    UPDATE failed_logins_ip_address
    SET attempts_count = attempts_count + 1, attempt_datetime = CURRENT_TIMESTAMP
    WHERE ip_address = 'xxx'
  END
  ELSE
  BEGIN
    INSERT INTO failed_logins_ip_address (ip_address, attempts_count, attempt_datetime)
    VALUES ('xxx', 1, CURRENT_TIMESTAMP)
  END

MySQL 查询:

INSERT INTO failed_logins_ip_address (ip_address, attempts_count, attempt_datetime)
  VALUES ('xxx', 1, CURRENT_TIMESTAMP)
  ON DUPLICATE KEY
  UPDATE attempts_count = attempts_count + 1, attempt_datetime = CURRENT_TIMESTAMP

'ip_addess' 列是唯一的,MSSQL 和 MySQL 的表结构相同。

是否有可以在两种数据库类型中执行 IF INSERT ELSE UPDATE 的语法?


是的,我做(PDO)参数绑定,xxx只是为了缩短代码sn-p。

是的,如果我在两个查询(首先选择,然后插入或更新)中执行相同的语法,我可以使用相同的语法,但我想避免(希望)不必要的查询。

不,我不想插入每次登录尝试,因此我不再需要更新,因为我不需要这些数据。

如果 REPLACE 方法可行:这不会更新,它会删除和插入,这也是我不想要的。

我当前的解决方案:我在 PHP 中检查当前数据库类型并切换/大小写查询字符串。它很干净,但一根绳子更不臭;-)


更新:

我改变了 MSSQL 查询:从 IF NOT EXISTS 到 IF EXISTS 以提高效率。 UPDATE 会比 INSERT 更频繁地发生,因此在大多数情况下,只会执行第一个(子)查询。

【问题讨论】:

  • 您搜索了很多,但没有找到任何关于 MERGE 的信息?
  • @Sami MERGE 在 MySQL 中不存在。我认为 OP 试图在 MySQL 和 SQL Server 之间找到一个共同的功能。
  • 在 MySQL 和 SQL Server AFAIK 中都没有通用的方法。
  • 与其寻找通用语法,不如在两者上创建同名的存储过程?
  • @jasie 您可以使用 MySQL / SQL 服务器的相应语法创建存储过程(例程),并立即将其定义到服务器中。您可以确保两个存储过程具有相同的名称。现在对SQL Server不太熟悉,不过好像支持CALL ..语句,MySQL也支持。所以你可以简单地用通用名称调用存储过程

标签: php mysql sql sql-server insert-update


【解决方案1】:

如果您使用的是 PHP,那么您就是通过接口调用代码。您可以执行以下操作:

  1. ip_address 上创建唯一索引。
  2. 尝试插入新行。如果该行已经存在,这将失败。
  3. 如果插入失败(尤其是重复键错误),则更新现有行。

但是,您尝试在两个数据库中使用相同代码的目标是 . . .只是不会很好地工作。这两个数据库是相当不同的。也许您应该考虑在每个数据库中构建存储过程来做您想做的事情,然后调用这些存储过程。

【讨论】:

  • 谢谢。正如我所写, ip_adress 已经具有唯一索引。并没有不尊重,但我也写了,我不想做两个查询。我已经有了一个干净的解决方案(也有描述),但我没有看到您提出的解决方案如何添加任何新内容,没有冒犯:-/
  • 另外,您在 2. 和 3. 中描述的内容可以在一个查询(存在/重复)或两个单独的查询(第一次插入,然后(最终更新))中完成 - 您的文本不清楚你到底是什么意思——至少对我来说不是,对不起。
  • @jasie 除非您使用重复键更新,否则无论如何您都会执行两个查询。子查询是单独的查询。这个解决方案是所有解决方案中最直接的,并且插入/更新语法在两个产品之间是通用的。
  • @Shadow 感谢您指出这一点,确实,if else 有子查询。但是 else 并不总是被执行。不过,我应该从 IF NOT 切换到 IF,因为 UPDATE 比 INSERT 更有可能发生,因为它会更频繁地发生 - 感谢您的启发。无论如何,由于这个限制,总是执行两个查询(首先是 SELECT,然后是 INSERT 或 UPDATE)的效率仍然较低。
  • Gordon 的解决方案不需要选择。你运行一个插入,如果它失败,你运行更新。
【解决方案2】:

深入挖掘后,我发现了 Derek Dieter 的这篇文章,其中描述了如何将 SQL Server 的 IF EXISTS ELSE 替换为 WHERE EXISTS

https://sqlserverplanet.com/optimization/avoiding-if-else-by-using-where-exists

MySQLMSSQL 中的 WHERE EXISTS 语法似乎相同

Derek Dieter 的例子,如果存在的话:

IF NOT EXISTS (SELECT 1 FROM customer_totals WHERE cust_id = @cust_id)
BEGIN
INSERT INTO customer_totals
(
cust_id,
order_amt
)
SELECT
cust_id = @cust_id
,order_amt = @order_amt
END
ELSE

UPDATE customer
SET order_amt = order_amt + @order_amt
WHERE cust_id = @cust_id

END

Derek Dieter 的例子,WHERE EXISTS:

INSERT INTO customer_totals
(
cust_id,
order_amt
)
SELECT TOP 1 — important since we’re not constraining any records
cust_id = @cust_id
,order_amt = @order_amt
FROM customer_totals ct
WHERE NOT EXISTS — this replaces the if statement
(
SELECT 1
FROM customer_totals
WHERE cust_id = @cust_id
)

SET @rowcount = @@ROWCOUNT — return back the rows that got inserted

UPDATE customer
SET order_amt = order_amt + @order_amt
WHERE @rowcount = 0
AND cust_id = @cust_id — if no rows were inserted, the cust_id must exist, so update

不过,我仍然需要在 MySQL 中对其进行测试。如果可行,我会更新这篇文章并添加代码。

【讨论】:

  • 不了解 MySQL,但使用 WHERE EXISTS 不会让您在 SQL Server 中执行 INSERT 和 UPDATE 之间进行选择。您必须使用 2 个查询来替换当前的 IF EXISTS 逻辑。
  • @TabAlleman 检查 Derek 的代码转换。似乎他找到了一种方法,但我不太希望这能在 MySQL 中发挥作用......
  • 他的代码确实只使用了一次 EXISTS,但它总是运行两个查询:一个 INSERT 和一个 UPDATE,而不是使用 IF 来确定要运行哪个单个查询。我怀疑这在任何方面都比你已经在做的“更好”。顺便说一句,我也怀疑你会在 MySQL 和 SQL Server 中找到任何这样做的语法。
猜你喜欢
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
  • 1970-01-01
  • 2013-11-26
  • 1970-01-01
  • 2014-04-27
  • 1970-01-01
相关资源
最近更新 更多