php - INSERT 中的子查询在 PDO 中的执行方式与 SQL 不同
问题描述
我想将一个新的数据集插入到一个tab
带有外部数据的 MySQL 表中,但也可以otherTab
使用其他表的主键和另一个条件从另一个表中插入数据。但是,可能是请求的行根本不存在(不再存在),或者由于其他提供的数据不匹配而导致结果集为空。然后,原来的 INSERT 应该会失败。所有列都禁止为 NULL。
我的第一次尝试是:
INSERT INTO tab (id, extid1, extid2, value)
SELECT 1,
(SELECT id FROM otherTab WHERE id = 12 AND data = 'TXT'),
(SELECT id FROM otherTab WHERE id = 34 AND data = 'JPG'),
1234
但它的问题是返回的空结果集被强制转换为 in 列的类型tab
,导致 a0
作为条目数据。
查询要高效,避免不必要的查询。这就是我通过四个子查询实现它的方式:
INSERT INTO tab (id, extid1, extid2, value)
SELECT 1,
(SELECT id FROM otherTab WHERE id = 12 AND data = 'TXT'),
(SELECT id FROM otherTab WHERE id = 34 AND data = 'JPG'),
1234
WHERE EXISTS (SELECT id FROM otherTab WHERE id = 12 AND data = 'TXT')
AND EXISTS (SELECT id FROM otherTab WHERE id = 34 AND data = 'JPG')
我尝试使用其他构造,例如(SELECT IFNULL(SELECT id FROM otherTab WHERE id = 12 AND data = 'TXT', NULL))
强制NULL
甚至将字符串放入目标列,但它也被强制转换为一个0
或某个值。
这是 dbFiddle 的代码:
代码CREATE TABLE `tab` (
`id` int NOT NULL,
`seUuid4` binary(16) NOT NULL,
`rxUuid4` binary(16) NOT NULL,
`text` varchar(16)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `otherTab` (
`uuid4` binary(16) NOT NULL,
`lgUuid4` binary(16) NOT NULL,
`data` varchar(16)
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
ALTER TABLE `otherTab`
ADD PRIMARY KEY(`uuid4`);
ALTER TABLE `tab`
ADD CONSTRAINT `tab_ibfk_1` FOREIGN KEY (`rxUuid4`) REFERENCES `otherTab` (`uuid4`) ON DELETE RESTRICT ON UPDATE RESTRICT,
ADD CONSTRAINT `tab_ibfk_2` FOREIGN KEY (`seUuid4`) REFERENCES `otherTab` (`uuid4`) ON DELETE RESTRICT ON UPDATE RESTRICT;
INSERT INTO `otherTab` (uuid4, lgUuid4, data) VALUES
(UNHEX("22224444aaaa49c782408b2fe8c4dee0"), UNHEX("00001234aaaa4444aaaa432187654321"), "JPG"),
(UNHEX("11113333aaaa49c782408b2fe8c4dee0"), UNHEX("12340000bbbb6666bbbb432187654321"), "TXT");
INSERT INTO tab (id, seUuid4, rxUuid4, text)
SELECT
1,
(SELECT uuid4 FROM otherTab WHERE lgUuid4 = UNHEX('00001234aaaa4444aaaa432187654321') AND data = 'JPK' LIMIT 0,1),
(SELECT uuid4 FROM otherTab WHERE lgUuid4 = UNHEX('12340000bbbb6666bbbb432187654321') AND data = 'TXT' LIMIT 0,1),
'some text'
有趣的是,这完全符合预期:注意JPK
代替JPG
. 我验证了我的代码,并且 PDO 准备好的语句触发了完全相同的命令,但它INSERT INTO tab (id, seUuid4, rxUuid4) VALUES (1, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 'datatext');
在 SQL 客户端和 phpMyadmin 传递预期的cannot insert null
错误消息时被插入。
我在 PDO 选项中找不到任何内容。如果有帮助,我将 PDO 与模拟的准备好的语句一起使用,但也尝试过没有任何变化。
PS:我已经发布在 dba.stackexchange.com/posts/276868
解决方案
您可以使用子查询:
INSERT INTO tab (id, extid1, extid2, value)
SELECT
FROM (
SELECT
1 id,
(SELECT id FROM otherTab WHERE id = 12 AND data = 'TXT') extid1,
(SELECT id FROM otherTab WHERE id = 34 AND data = 'JPG') extid2
1234 value
) t
WHERE extid1 IS NOT NULL and extid2 IS NOT NULL
或者,可能更好的是,您可以CROSS JOIN
使用两个子查询:
INSERT INTO tab (id, extid1, extid2, value)
SELECT 1, t1.id, t2.id, 1234
FROM (SELECT id FROM otherTab WHERE id = 12 AND data = 'TXT') t1,
CROSS JOIN (SELECT id FROM otherTab WHERE id = 34 AND data = 'JPG') t2
实际上,由于您重新使用与过滤相同的值,因此两个exists
子查询可能就足够了:
INSERT INTO tab (id, extid1, extid2, value)
SELECT t.*
FROM (SELECT 1 id, 12 extid1, 34 extid2, 1234 value) t
WHERE EXISTS (SELECT 1 FROM otherTab t1 WHERE t1.id = t.extid1 AND t1.data = 'TXT')
AND EXISTS (SELECT 1 FROM otherTab t1 WHERE t1.id = t.extid2 AND t1.data = 'JPG')
推荐阅读
- arrays - React 中表格为空时不显示结果
- installation - 安装 Talend 时出现问题,无响应
- c++ - 在回调(ROS)中执行 PCL 代码失败
- .net - 在哪里可以找到独立的 .NET Framework 4.7.2 Developer Pack 离线安装程序?
- javascript - 使用 send_data 下载 Rails 文件并执行后续操作
- mongodb - mongodb中集合大小小于N时如何获取N个随机文档
- sql - 为什么更新查询每次都更新两条记录?
- c# - 对象引用未设置为 con.Open() 上的对象实例;
- reactjs - 如何解决 React+Material UI 中的这个错误
- amazon-web-services - Kubectl 不适用于 AWS EC2 实例