如何将(合并和删除孤立行)合并到@Controller
@RequestMapping(path="/demo")
public class HomeController {
@Autowired
private JobListRepository jobListRepository;
@GetMapping(path="/add")
public @ResponseBody String addNewJobs () {
JobList jobList = new JobList();
jobList.setLimit(50);
JobListRepository.save(jobList);
return "Saved";
}
@GetMapping(path="/all")
public @ResponseBody Iterable<JobList> getAllJobs() {
return JobListRepository.findAll();
}
}
?
tableA
:
tableA
+---------+--------+----------+-------+
| company | option | category | rates |
+---------+--------+----------+-------+
| a | f | null | 2.5 |
+---------+--------+----------+-------+
| a | f | d | 2 | *
+---------+--------+----------+-------+
| a | g | e | 3 | **
+---------+--------+----------+-------+
| c | g | e | 4 |
+---------+--------+----------+-------+
| d | f | d | 1 |
+---------+--------+----------+-------+
表示孤立行*。
*
表示要更改的值( 3 -> 4 )。
仅触摸**
中现有的公司(在示例中为tableB
和a
,不理会c
)。
d
:
tableB
两个表中+---------+--------+----------+-------+
| company | option | category | rates |
+---------+--------+----------+-------+
| a | f | null | 2.5 |
+---------+--------+----------+-------+
| a | g | e | 4 |
+---------+--------+----------+-------+
| c | g | e | 4 |
+---------+--------+----------+-------+
上都有一个唯一索引。
所需的结果(company, option, category)
:
tableA
仅+---------+--------+----------+-------+
| company | option | category | rates |
+---------+--------+----------+-------+
| a | f | null | 2.5 |
+---------+--------+----------+-------+
| a | g | e | 4 | <-
+---------+--------+----------+-------+
| c | g | e | 4 |
+---------+--------+----------+-------+
| d | f | d | 1 |
+---------+--------+----------+-------+
的第二行(a,f,d,2)
被删除,rates
从 3 更改为 4 。
这里是一个小提琴:https://rextester.com/QUVC30763
我正在考虑首先使用以下方法删除孤立行:
(a,g,e)
然后使用以下方法进行修饰:
DELETE from tableA
USING tableB
WHERE
-- ignore rows with IDs that don't exist in tableB
tableA.company = tableB.company
-- ignore rows that have an exact all-column match in tableB
AND NOT EXISTS
(select * from tableB
where tableB.company is not distinct from tableA.company
AND tableB.option is not distinct from tableA.option
AND tableB.category is not distinct from tableA.category );
但是upsert函数的问题在于它无法处理可为空的字段。我必须将 INSERT INTO tableA (company, option, category, rates)
SELECT company, option, category, rates
FROM tableB
ON CONFLICT (company, option, category)
DO update
set rates= EXCLUDED.rates
WHERE
tableA.rates IS DISTINCT FROM
EXCLUDED.rates;
设置为-1
的位置,否则该函数将无法知道是否存在重复项。我觉得将null
设置为-1
会在将来创建许多变通办法,所以我想避免这种情况。
注意:我发现null
可能是解决方法:
但是我没有看到适合我的情况的查询。而且我不确定是否可以使用可空字段。因此,问题是
有没有一种干净的方法可以合并可为空的字段?
答案 0 :(得分:1)
我认为您在正确的道路上。但是NULL
与UNIQUE
的设计存在问题:
列option
和category
可以是NULL
。在这些情况下,NULL
被认为是相等的。您当前的唯一索引不会 不 认为NULL
的值相等,因此不会执行您的要求。这甚至在您开始合并之前就产生了歧义。 NULL
的值对您尝试实现的内容不利。解决此问题将产生更多的工作和更多的故障点。考虑使用特殊值代替NULL
,一切都准备就绪。您正在考虑-1
。对于您的实际数据类型和属性的性质而言,任何自然有意义的事情。
也就是说, DELETE
还有一个细微的隐藏问题:它将尝试删除孤立行,其次数与{{ 1}}。一切都没有中断,因为过多的尝试无济于事,但是它不必要地昂贵。两次使用company
:
tableB
如果您坚持使用EXISTS
值,则将UPSERT分为DELETE FROM tableA a
WHERE EXISTS (
SELECT FROM tableB b
WHERE a.company = b.company
)
AND NOT EXISTS (
SELECT FROM tableB b
WHERE (a.company, a.option, a.category) IS NOT DISTINCT FROM
(b.company, b.option, b.category)
);
,然后是NULL
。如果您没有并发写入表,则更简单,更便宜。 UPDATE
可以在不指定冲突目标的情况下工作,因此您可以使用多个部分索引来实现您的需求并使它生效。 The manual:
对于
INSERT ... ON CONFLICT DO NOTHING
,可以选择指定一个ON CONFLICT DO NOTHING
;如果省略,则与所有可用约束冲突 (和唯一索引)得到处理。对于ON CONFLICT DO NOTHING
,a 必须提供conflict_target
。
但是,如果您使用 working ON CONFLICT DO UPDATE
索引或约束来修复架构,那么您已经拥有的UPSERT会很好地发挥作用。
并确保没有对表的并发写入,否则您可能会面临竞争条件和/或死锁,除非您执行更多操作...