亲子关系表

时间:2018-02-23 21:21:59

标签: java sql sql-server tree

上下文:

  • 查询来自外部系统的事务表,以在本地系统上创建具有两个主要列的元素:
  • 尚未保留在本地数据库中的子项
  • 可能的多个父母分号分开(可以在本地保存或尚未创建)

我在排序看起来像这样的表时出现问题:

Child    Parents
A        B;C
B        C;E
C        F;X

我想要完成的是确保始终在子项之前创建Parent:

Child    Parents
C        F;X
B        C;E
A        B;C

F,X&此示例中的E表示本地数据库中可能存在于我的查询中的元素

我花了一些时间思考这个问题,似乎它与树木/图表有关,我几乎不知道......

知道我们在这里处理什么样的排序以及可能的java或SQL实现?

编辑:

  • 每个子元素都是一个尚未在数据库中保留的元素
  • 孩子可以有一个已经存在的父母列表(如F,X和E)或父母我仍然需要坚持(在这种情况下他们需要在所述孩子之前)或两者的混合(如B与C; E父母E已经坚持,C来自此交易,必须先于B)
  • 无法更改数据库,但可以在java中自由重新排序

提前致谢

部分解决方案 我已经改编了Joshua的解决方案,它似乎也是这样的:

(基本上使用like声明,因为我们可以有类似AA的东西; BB; CC作为父母)

SELECT DISTINCT
s1.child,
s1.parents,
    CASE
        WHEN s2.parents IS NULL THEN 0
        WHEN s2.parents LIKE '%' + s1.child + '%' THEN 1
        ELSE 3
    END
AS x
FROM
sample s1
LEFT JOIN sample s2 ON s2.parents LIKE '%' + s1.child + '%'
WHERE
s1.treateddate IS NULL
ORDER BY
CASE
    WHEN s2.parents IS NULL THEN 0
    WHEN s2.parents LIKE '%' + s1.child + '%' THEN 1
    ELSE 3
END
DESC

此解决方案并未考虑同时为父母的孩子!

解决方案Java 我在Java中找到了重新排序数据集的解决方案,这只是伪代码,因为我使用的是专有库...

private void sortByParentFirst(rows) {
for (int i = 0; i < rows.size(); i++) {
    for (int j = 0; j < rows.size(); j++) {
         boolean match = false;
         //parents comma seperated at j contain child i
         if (Parents[j].contains(Child[i]) ) {
             match = true;
         }
         //this means we found an occurrence of the child i at a previous position j
         if (match && j < i) {
            //swap rows i & j
            swap(i,j);
            break;
         }
     }
}
}

2 个答案:

答案 0 :(得分:0)

此处表格示例包含您的数据

select * from sample

chid parents
---- ----------
A    B;C
B    C;E
C    F;X
select * from sample

drop table #sample
drop table #sample2

select * into #sample from sample
select * into #sample2 from sample where 1=2

alter table #sample2 add counter int

declare @count int
select @count = count(1) from #sample

declare @child char(1)
declare @counter int = 1

while(@count > 0)
begin
    select @child = t1.chid
    from #sample t1
    inner join #sample t2 on CHARINDEX(t1.chid,t2.parents) = 0
    group by t1.chid
    having count( t1.chid) = 1

    insert into #sample2
    select *,@counter from #sample where chid = @child

    delete from #sample where chid = @child

    select @count = count(1) from #sample
    set @counter = @counter + 1
end

select chid, parents from #sample2 order by counter

答案 1 :(得分:0)

select distinct s1.*  ,
case when s2.parents is null and s3.parents is null then 0 
 when s1.child = left(s2.parents,1) and s3.parents is null  then 1
 when s1.child = right(s3.parents,1) and s2.parents is null  then 2
else 3 end as x
from sample s1
left join sample s2 on s1.child = left(s2.parents,1) 
left join sample s3 on s1.child = right(s3.parents,1)
order by 
case when s2.parents is null and s3.parents is null then 0 
 when s1.child = left(s2.parents,1) and s3.parents is null  then 1
 when s1.child = right(s3.parents,1) and s2.parents is null  then 2
else 3 end desc

SQL Fiddle Example

将表连接回自己两次寻找与父母的匹配。如果实际日期不仅仅是一个字符,那么您可以使用CHARINDEX根据返回的起始位置的位置,使用{{3}}来定位分隔符和每个表单的左侧或右侧。