我需要比较两个MysQL表,并报告对部分结果的更改。
假设我有这两个表:
表A:
id name supplier value
-----------------------------------------
1 Alice X 100
2 Bob Y 200
3 Clare Z 300
4 Desmond X 400
表B:
id name supplier value
-----------------------------------------
1 Alice X 150
2 Bob X 200
3 Clare Z 350
4 Desmond X 400
5 Emily X 500
我对涉及供应商X的任何行的更改感兴趣。鉴于以上所述,我想返回:
我对ID 3不感兴趣,因为尽管值已更改,但更改不涉及供应商X。我也不感兴趣 在ID 4中,因为根本没有变化。
我可以使用UNION ALL
来计算差异:
SELECT *
FROM
(
SELECT a.id, a.name, a.supplier, a.value, 'a' as tbl
FROM a
UNION ALL
SELECT b.id, b.name, b.supplier, b.value, 'b' as tbl
FROM b
) t
GROUP BY id, name, supplier, value
HAVING COUNT(*) = 1
ORDER BY id
这将返回数据已更改的所有行:
id name supplier value tbl
---------------------------------------------------
1 Alice X 100 a
1 Alice X 150 b
2 Bob Y 200 a
2 Bob X 200 b
3 Clare Z 300 a
3 Clare Z 350 b
5 Emily X 500 b
但是,它也包含我不感兴趣的ID 3,因为表A或B中的行都没有供应商X。
所以最后,我的问题是-如何返回差异行之一是供应商X的结果?我当然可以在代码中过滤结果,但是在单个查询中执行此操作就很棒。
答案 0 :(得分:1)
我会使用两个input[type="number"]:-webkit-outer-spin-button,
input[type="number"]:-webkit-inner-spin-button
和一个LEFT JOINS
来实现它:
UNION
首先,将表CREATE TABLE `a` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL DEFAULT '0',
`supplier` VARCHAR(50) NOT NULL DEFAULT '0',
`value` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=5
;
CREATE TABLE `b` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL DEFAULT '0',
`supplier` VARCHAR(50) NOT NULL DEFAULT '0',
`value` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=6
;
INSERT INTO `a` (`id`, `name`, `supplier`, `value`) VALUES (1, 'Alice', 'X', 100);
INSERT INTO `a` (`id`, `name`, `supplier`, `value`) VALUES (2, 'Bob', 'Y', 200);
INSERT INTO `a` (`id`, `name`, `supplier`, `value`) VALUES (3, 'Clare', 'Z', 300);
INSERT INTO `a` (`id`, `name`, `supplier`, `value`) VALUES (4, 'Desmond', 'X', 400);
INSERT INTO `b` (`id`, `name`, `supplier`, `value`) VALUES (1, 'Alice', 'X', 150);
INSERT INTO `b` (`id`, `name`, `supplier`, `value`) VALUES (2, 'Bob', 'X', 200);
INSERT INTO `b` (`id`, `name`, `supplier`, `value`) VALUES (3, 'Clare', 'Z', 350);
INSERT INTO `b` (`id`, `name`, `supplier`, `value`) VALUES (4, 'Desmond', 'X', 400);
INSERT INTO `b` (`id`, `name`, `supplier`, `value`) VALUES (5, 'Emily', 'X', 500);
SELECT a.name AS name, a.supplier AS a_supplier, a.value AS a_value, b.supplier AS b_supplier, b.value AS b_value FROM a
LEFT JOIN b ON a.name = b.name
WHERE (a.supplier ='X' OR b.supplier = 'X') AND (a.value <> b.value OR a.supplier <> b.supplier OR b.name IS NULL)
UNION
SELECT b.name AS name, a.supplier AS a_supplier, a.value AS a_value, b.supplier AS b_supplier, b.value AS b_value FROM b
LEFT JOIN a ON b.name = a.name
WHERE (a.supplier ='X' OR b.supplier = 'X') AND (a.value <> b.value OR a.supplier <> b.supplier OR a.name IS NULL)
连接到表A
,然后进行反向连接。
我不确定是否可以通过表的ID联接表,因此在此示例中,我将名称用作联接列。
每个联接都包含一个B
子句,该子句使用您的条件过滤行:“更改为涉及供应商X的任何行” 。
这里是一个SQLFiddle:http://sqlfiddle.com/#!9/46f213/1
答案 1 :(得分:0)
您可以在原始查询中添加一些where子句以检查Supplier X,但我认为我会采用略有不同的方法并使用联接:
SELECT a.id, a.name, a.supplier, a.value, b.name, b.supplier, b.value
FROM a
INNER JOIN b ON (a.id = b.id AND (a.name != b.name OR a.value != b.value OR a.supplier != b.supplier))
WHERE a.supplier = 'X' OR b.supplier = 'X'
GROUP BY a.id;
这将获取已更改的行,但仅包含与X相关的行。请注意,这假设每个表中始终只有一个匹配的ID。
答案 2 :(得分:0)
扩展lldar的答案,您还可以通过对列进行散列然后寻找更改来获得区别。
md5(concat(A.`Name`,A.`Supplier`, A.`Value`)) <> md5(concat(b.`Name`,b.`Supplier`,b.`Value`))
如果您有很多列,这将很有帮助。从长远来看,理想情况下,您可以编辑表并将散列添加为“计算/计算”列。
那么它就是A.hash <> b.hash
答案 3 :(得分:0)
仅通过使用LEFT JOIN即可实现要求
SELECT b.NAME AS NAME,
a.supplier AS a_supplier,
a.value AS a_value,
b.supplier AS b_supplier,
b.value AS b_value
FROM b
LEFT JOIN a
ON ( a.id = b.id )
WHERE ( b.supplier = 'X'
OR a.supplier = 'X' )
AND ( a.supplier != b.supplier
OR a.value != b.value
OR a.id IS NULL )
ORDER BY b.id;