繁体   English   中英

查询树结构

[英]Query tree structure

我正在使用EntityFramework,但如果需要可以使用其他方式

就是这种情况:我有一个SQL Server数据库,其方案类似于:

A           B           C           AhasB         AhasC
________    ________    ________    __________    ___________
AId         BId         CId         AId           AId
...         Btxt        Ctxt        BId           CId
            BParent     ...
            ...

其中...表示对问题不重要的其他列。

CAhasC会在一个漫长的过程中保留数据,并在过程完成时清除它们,因此我总是从两个空开始。现在,该过程从在线资源中获取大量数据(1000多个记录)并将其存储在C 填充C后,我想基于以下内容填充表AhasC

INSERT INTO C (AId, CId) VALUES (
    SELECT A.AId, C.CId
    FROM A, B, C, AhasB
    WHERE A.AId = AhasB.AId AND B.BId = AhasB.BId AND
        C.CTxt IN (
            SELECT D.BTxt
            FROM B AS D
            WHERE D.BId = B.BId OR ??
        )
)

在我解释我需要什么之前?? 让我浏览一下我在这里的内容:

我想在表AhasC中插入A.AId,C.CId对,以便在所有对中C.CTxt都与在B.Btxt中连接到A的AhasB

此外(在这里输入?? ),我也希望它与B的任何父代的B.Btxt匹配。

例:

A            B
_______      ____________________________________
AId = 1      BId = 1, BTxt = 'a', BParent = Null
AId = 2      BId = 2, BTxt = 'b', BParent = 1
AId = 3      Bid = 3, BTxt = 'c', BParent = 2
AId = 4      BId = 4, BTxt = 'x', BParent = Null

C                       AahsB
_____________________   _________
CId = 1, Ctxt = 'b'     AId = 1, BId = 3
CId = 2, CTxt = 'z'     AId = 3, BId = 4

这应导致:

AhasC
____________
AId = 1, CId = 1

如此反复, AhasC必须连接A ,如果和C A连接到B ,要么有BTxt等于CTxt ,或者谁的父母(或盛大的父母等)具有BTxt是一样CTxt

希望我不会在这里给我过多的解释:p

编辑1:根据@dotctor的评论,这是我真正的shema的图像(不是我认为这会增加很多问题)

我的真实模式

A = Contatos
B = Termos
C = ConcursosPublicos
AhasB = TermosContatos
AhasC = ConcursosContatos
A.AId = Contatos.Id
B.BId = Termos.Id
C.CId = ConcursosPublicos.Id
B.BTxt = Termos.Area
C.CTxt = ConcursosPublicos.Area
B.BParent = Termos.Pai

这是我目前正在执行此工作的真实代码:

public static void Connect(ProgressBar progress)
{
    lock (Locker)
        using (var ctx = new ConcursosContainer())
        {
            int i = 0;
            IList<Contatos> contatos = ctx.Contatos.ToList();
            progress.Invoke((MethodInvoker) (() =>
            {
                progress.Value = 0;
                progress.Maximum = contatos.Count;
            }));
            foreach (Contatos contato in contatos)
            {
                Console.WriteLine(contato.Id);
                List<Termos> tree = GetTree(ctx, contato.Id).SelectMany(x => x.ToArray()).ToList();
                List<int> attr = ctx.ConcursosContatos.Where(x => x.ContatoId == contato.Id).Select(x => x.ConcursoId).ToList();
                IList<ConcursosPublicos> concursosPublicos = ctx.ConcursosPublicos.Where(x => !attr.Contains(x.Id)).ToList();
                foreach (ConcursosPublicos concursosPublico in concursosPublicos)
                {
                    if (tree.Any(termo => (termo.Tipo == concursosPublico.TipoConc) && concursosPublico.Area.Trim().EndsWith(termo.Area)))
                    {
                        ctx.ConcursosContatos.Add(new ConcursosContatos
                        {
                            ContatoId = contato.Id,
                            ConcursoId = concursosPublico.Id
                        });
                        i++;
                    }
                    if (i == 9)
                    {
                        ctx.SaveChanges();
                        i = 0;
                    }
                }
                progress.Invoke((MethodInvoker) (progress.PerformStep));
            }
            if (i > 0)
                ctx.SaveChanges();
        }
}

private static IEnumerable<Stack<Termos>> GetTree(ConcursosContainer ctx, int id)
{
    var res = new List<Stack<Termos>>();
    IQueryable<Termos> terms = ctx.Termos.Where(x => ctx.TermosContatos.Any(y => (y.ContatoId == id) && (y.TermoId == x.Id)));
    foreach (Termos term in terms)
    {
        var stack = new Stack<Termos>();
        if (term.Pai.HasValue)
            AddParent(ctx, stack, term);
        stack.Push(term);
        res.Add(stack);
    }
    return res;
}

private static void AddParent(ConcursosContainer ctx, Stack<Termos> stack, Termos term)
{
    Termos pai = ctx.Termos.First(x => x.Id == term.Pai.Value);
    if (pai.Pai.HasValue)
        AddParent(ctx, stack, pai);
    stack.Push(pai);
}

该代码可以完成工作,但是对于1000+的ConcursosPublicos成员和7000+的Contatos成员(将来还会有contatos成长),它可能需要15到20个小时才能完成。 由于这是日常工作,因此我需要一种更有效的方式来填写ConcursosContatos

您需要进行一些递归才能将族谱添加到B表中。 在SQL Server中,您可以使用CTE执行此操作:

;with chld as (
    select B.BId, B.BTxt, B.BParent 
    from dbo.B as B
    union all
    select chld.BId , b1.BTxt, b1.BParent  
    from dbo.B as B1
    inner join chld 
    on B1.BId = chld.BParent
)
select BId, BTxt from chld option(maxrecursion 32767)

结果集:

BId BTxt
1   a
2   b
3   c
4   x
3   b
3   a
2   a

如果这是不正确的,则无需进一步。 否则,您可以根据需要将其连接到其他表以填充AhasC表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM