Access从内部联接中删除有效记录

时间:2013-12-27 21:28:23

标签: ms-access inner-join greatest-n-per-group

我几乎确信这是MS Access内连接中的一个漏洞。这真是太可怕了,因为它是我应该用于app dev的东西。不,这不是内部联接的预期行为 - 我已经让3个不同的人(自己计算)来确认。

因此,查询正在实施"最大的n组"通过最大查询获得最高优先级,然后将该结果用作过滤回原始文件以检索所需的非组字段。 (附带问题 - 是"第一个"在一个有序的表上真的足够稳定,可以通过一次传递来完成吗?)所说的非分组字段是第三个表上一个键的一部分。

此查询的特定配置会丢弃我数据的特定子集中的一半记录(我已放大)。如果我将第三个表的连接切换到" max filter"表而不是基表,突然它正常工作。 (有问题的字段显示在所有3个表格中,并且已经从" base"加到" max过滤器"已经。)

我的小组确实超过了11个字段。并且交换已连接字段的哪个副本确实会改变我的查询执行计划。但是没有一种类型的版本似乎不起作用。我不知道内部联接和分组如何能够插入错误的查询计划,但我似乎已经设法了。

我知道没有实际的sql代码[现已发布],但它分布在多个查询中,可能还需要我得到的数据。有没有办法上传一个实际的.mdb文件,以便人们可以使用产生错误的副本?我刚刚发帖,但我还没有看到一个带有.mdb的帖子,所以我不确定如何最好地获得这个帖子所需的详细信息。

或者,如果有人知道可能发生的事情(未分类的联接有10个字段限制?)可能导致这种情况,我将在周一进一步查看。我以前在C中孤立的记忆没有泄漏,所以我想我知道一两件事,但是这个只是简单的迷惑 - 我真的不想以为我可能不得不在vba中实现内部联接,因为我不能信任Access(并且无法获得更好的工具)。

[进一步编辑:我是这个过程的唯一设计师,因此,一旦它不是别人的代码 - 我的问题本身就是我自己的问题。]

2013-12-30编辑 - 添加SQL墙 SQL之墙:

错误查询仅返回测试子集上16个结果中的8个:

SELECT 
    Allocations.Allocation_ID, 
    SLJ.Exp_Sign, 
    SLJ.Proj_ID,  
    SLJ.Doc_ID,  
    Allocations.Expense_Catagory,  
    SLJ.Prod_ID,  
    SLJ.OrigP_Type,  
    SLJ.OrigP,  
    SLJ.Class_ID,  
    Sum(SLJ.Total*[share]) AS Resposible_Doc_Count,  
    MP.MaxOfPriority,  
    SLJ.Priority,  
    MP.OrigP,  
    MP.Exp_Sign,  
    IIf(MP.exp_sign=SLJ.exp_sign,"true","false") AS What  
FROM  
    (MP INNER JOIN SLJ  
        ON (MP.Exp_Sign = SLJ.Exp_Sign)  
        AND (MP.E_Delivery = SLJ.E_Delivery)  
        AND (MP.Expense_Type = SLJ.Expense_Type)  
        AND (MP.Proj_ID = SLJ.Proj_ID)  
        AND (MP.Doc_ID = SLJ.Doc_ID)  
        AND (MP.Doc_Typ_ID = SLJ.Doc_Typ_ID)  
        AND (MP.Prod_ID = SLJ.Prod_ID)  
        AND (MP.OrigP_Type = SLJ.OrigP_Type)  
        AND (MP.Class_ID = SLJ.Class_ID)  
        AND (MP.OrigP = SLJ.OrigP)  
        AND (MP.MaxOfPriority = SLJ.Priority)  
        AND (MP.Invested = SLJ.Invested))  
    INNER JOIN Allocations  
        ON (SLJ.Alloc_ID = Allocations.Allocation_ID)   
        AND (SLJ.Invested = Allocations.Invested)   
        AND (SLJ.E_Delivery = Allocations.E_Delivery)   
        AND (SLJ.Expense_Type = Allocations.Expense_Type)  
GROUP BY   
    Allocations.Allocation_ID,    
    SLJ.Exp_Sign,    
    SLJ.Proj_ID,    
    SLJ.Doc_ID,    
    Allocations.Expense_Catagory,    
    SLJ.Prod_ID,    
    SLJ.OrigP_Type,    
    SLJ.OrigP,    
    SLJ.Class_ID,    
    MP.MaxOfPriority,    
    SLJ.Priority,    
    MP.OrigP,    
    MP.Exp_Sign,    
    IIf(MP.exp_sign=SLJ.exp_sign,"true","false");

良好的查询返回所有16个结果:

SELECT Allocations.Allocation_ID, 
    SLJ.Exp_Sign,  
    SLJ.Proj_ID,  
    SLJ.Doc_ID,  
    Allocations.Expense_Catagory,  
    SLJ.Prod_ID,  
    SLJ.OrigP_Type,  
    SLJ.OrigP,  
    SLJ.Class_ID,  
    Sum(SLJ.Total*[share]) AS Resposible_Doc_Count,  
    MP.MaxOfPriority,  
    SLJ.Priority,  
    MP.OrigP,  
    MP.Exp_Sign,  
    IIf(MP.exp_sign=SLJ.exp_sign,"true","false") AS What  
FROM  
    (MP INNER JOIN SLJ  
        ON (MP.Invested = SLJ.Invested)   
        AND (MP.MaxOfPriority = SLJ.Priority)    
        AND (MP.OrigP = SLJ.OrigP)    
        AND (MP.Class_ID = SLJ.Class_ID)    
        AND (MP.OrigP_Type = SLJ.OrigP_Type)    
        AND (MP.Prod_ID = SLJ.Prod_ID)    
        AND (MP.Doc_Typ_ID = SLJ.Doc_Typ_ID)    
        AND (MP.Doc_ID = SLJ.Doc_ID)    
        AND (MP.Proj_ID = SLJ.Proj_ID)    
        AND (MP.Expense_Type = SLJ.Expense_Type)    
        AND (MP.E_Delivery = SLJ.E_Delivery)    
        AND (MP.Exp_Sign = SLJ.Exp_Sign))    
    INNER JOIN Allocations    
        ON (Allocations.Expense_Type = MP.Expense_Type)    
        AND (Allocations.E_Delivery = MP.E_Delivery)    
        AND (Allocations.Invested = MP.Invested)    
        AND (SLJ.Alloc_ID = Allocations.Allocation_ID)  
GROUP BY Allocations.Allocation_ID,    
    SLJ.Exp_Sign,     
    SLJ.Proj_ID,     
    SLJ.Doc_ID,     
    Allocations.Expense_Catagory,     
    SLJ.Prod_ID,     
    SLJ.OrigP_Type,     
    SLJ.OrigP,     
    SLJ.Class_ID,     
    MP.MaxOfPriority,     
    SLJ.Priority,     
    MP.OrigP,     
    MP.Exp_Sign,     
    IIf(MP.exp_sign=SLJ.exp_sign,"true","false");

查询设计师的差异 - 加入"分配"针对两个存在的三个字段的MP而不是SLJ ... allocation_id仅在SLJ上。 (分别为Max_Priority和Stats_Loose_Join。)

底层查询/表格:

MP:

SELECT 
        Max(SLJ.Priority) AS MaxOfPriority,  
        SLJ.Exp_Sign,  
        SLJ.Invested,  
        SLJ.E_Delivery,  
        SLJ.Expense_Type,  
        SLJ.Proj_ID,  
        SLJ.Doc_ID,  
        SLJ.Doc_Typ_ID,  
        SLJ.Prod_ID,  
        SLJ.OrigP_Type,  
        SLJ.OrigP,  
        SLJ.Class_ID  
FROM SLJ  
GROUP BY  
        SLJ.Exp_Sign,  
        SLJ.Invested,  
        SLJ.E_Delivery,  
        SLJ.Expense_Type,  
        SLJ.Proj_ID,  
        SLJ.Doc_ID,  
        SLJ.Doc_Typ_ID,  
        SLJ.Prod_ID,  
        SLJ.OrigP_Type,  
        SLJ.OrigP,  
        SLJ.Class_ID;

SLJ - 过滤(通过哪里)到4个记录的测试集:

SELECT  
        KS.Alloc_ID,  
        KS.Priority,  
        KS.Exp_Sign,  
        StatsT.*  
FROM  
        KS,  
        StatsT  
WHERE  
        ( 
            ( 
                (KS.Proj_ID) Is Null  
                Or (KS.Proj_ID)=[StatsT].[proj_id] 
            )  
                AND ( 
                        (KS.Doc_ID) Is Null  
                        Or (KS.Doc_ID)=[StatsT].[doc_id] 
                    )  
                AND ( 
                        (KS.Doc_Typ_ID) Is Null  
                        Or (KS.Doc_Typ_ID)=[StatsT].[doc_typ_id] 
                    )  
                AND (
                        (KS.Prod_ID) Is Null  
                        Or (KS.Prod_ID)=[StatsT].[prod_id] 
                    )  
                AND ( 
                        (KS.OrigP_Type) Is Null  
                        Or (KS.OrigP_Type)=[StatsT].[OrigP_Type] 
                    )  
                AND ( 
                        (KS.OrigP) Is Null  
                        Or (KS.OrigP)=[StatsT].[OrigP] 
                    )  
                AND ( 
                        (KS.Class_ID) Is Null  
                        Or (KS.Class_ID)=[StatsT].[class_id] 
                    )  
                AND ((StatsT.Doc_ID)=10437)  
                AND ((StatsT.Prod_ID)=104));

SLJ结果:

Alloc_ID  Priority  Exp_Sign  Invested  E_Delivery  Expense_Type  Proj_ID   Doc_ID  Doc_Typ_ID  Prod_ID OrigP_Type  OrigP   Class_ID    Total  
1         10    Gross     Y     N           Inforce       2013_199  10437   5   104 Fund_Doc    40  -1  1  
1         10    Gross     Y     N           Inforce       2013_199  10437   5   104 Fund_Doc    43  -1  1  
-1        10    Reimb     Y     N           Inforce       2013_199  10437   5   104 Fund_Doc    40  -1  1  
-1        10    Reimb     Y     N           Inforce       2013_199  10437   5   104 Fund_Doc    43  -1  1

StatsT:

SELECT 
    E2_In__Bound_Stats__Long.Invested,  
    E2_In__Bound_Stats__Long.E_Delivery,  
    E2_In__Bound_Stats__Long.Expense_Type,  
    E2_In__Bound_Stats__Long.Proj_ID,  
    E2_In__Bound_Stats__Long.Doc_ID,  
    E2_In__Docs_List__Doc.Doc_Typ_ID,  
    E2_In__Bound_Stats__Long.Prod_ID,  
    E2_In__Bound_Stats__Long.OrigP_Type,  
    E2_In__Bound_Stats__Long.OrigP,  
    E2_In__Bound_Stats__Long.Class_ID,  
    E2_In__Bound_Stats__Long.Total  
FROM  
    E2_In__Bound_Stats__Long  
INNER JOIN  
    E2_In__Docs_List__Doc  
ON  
    E2_In__Bound_Stats__Long.Doc_ID = E2_In__Docs_List__Doc.Doc_ID;

KS表(Kitchen_Sink) - 119行 - 空条目阻止主键:

Alloc_ID    Priority    Exp_Sign    Proj_ID Doc_ID  Doc_Typ_ID  Prod_ID OrigP_Type  OrigP   Class_ID

Docs_List表 - 12465行 - 主键是Doc_ID:

Doc_ID  Doc_Typ_ID

Bound_Stats表 - 1289行(或100k左右),只有4个在SLJ上存活过滤 - 主键最初未设置,应该是除Total之外的所有内容,设置没有删除bug:

Invested    E_Delivery  Expense_Type    Proj_ID Doc_ID  Prod_ID OrigP_Type  OrigP   Class_ID    Total

访问查询计划:

糟糕的计划:
--- Matrix_Math_AAA ---

查询输入

Table 'KS'  
Table 'E2_In__Bound_Stats__Long'  
Table 'E2_In__Docs_List__Doc'  
    Using index 'PrimaryKey'  
    Having Indexes:  
    PrimaryKey 12465 entries, 22 pages, 12465 values  
      which has 1 column, fixed, unique, primary-key, no-nulls  
    Doc_Type_ID1 12465 entries, 15 pages, 14 values  
      which has 1 column, fixed  
    Doc_ID1 12465 entries, 22 pages, 12465 values  
      which has 1 column, fixed  
Table 'KS'  
Table 'E2_In__Bound_Stats__Long'  
Table 'E2_In__Docs_List__Doc'  
    Using index 'PrimaryKey'  
    Having Indexes:  
    PrimaryKey 12465 entries, 22 pages, 12465 values  
      which has 1 column, fixed, unique, primary-key, no-nulls  
    Doc_Type_ID1 12465 entries, 15 pages, 14 values  
      which has 1 column, fixed  
    Doc_ID1 12465 entries, 22 pages, 12465 values  
      which has 1 column, fixed  
Table 'Allocations'

结束对查询的输入

  1. 通过扫描测试限制表E2_In__Bound_Stats__Lont的行 表达式" StatsT.Prod_ID = 104和StatsT.Doc_ID = 10437"
  2. 内部加入结果' 01)'到表' E2_In__Docs_List__Doc'运用 index' E2_In__Docs_List__Doc!PrimaryKey'加入表达式 " E2_In__Bound_Stats__Long.Doc_ID = E2_In__Docs_List__Doc.Doc_ID"
  3. 排序表'分配'
  4. 内部加入结果' 02)'结果是' 03)'使用临时索引 join expression" SLJ.Expense_Type = Allocations.Expense_Type And SLJ.E_Delivery = Allocations.E_Delivery And SLJ.Invested = Allocations.Invested"
  5. 排序结果' 04)'
  6. 内部加入表' KS'结果' 05)'使用临时索引连接 表达式" SLJ.Alloc_ID = Allocations.Allocation_ID"然后测试 表达式"(KS.Class_ID是Null或KS.Class_ID = StatsT.class_id)和 ((KS.OrigP是Null或KS.OrigP = StatsT.OrigP)和((KS.OrigP_Type是 Null或KS.OrigP_Type = StatsT.OrigP_Type)和((KS.Prod_ID是空的或者 KS.Prod_ID = StatsT.prod_id)和((KS.Doc_Typ_ID是空的或者 KS.Doc_Typ_ID = StatsT.doc_typ_id)和((KS.Doc_I"
  7. 通过扫描测试限制表E2_In__Bound_Stats__Lont的行 表达式" StatsT.Prod_ID = 104和StatsT.Doc_ID = 10437"
  8. 内部加入结果' 07)'到表' E2_In__Docs_List__Doc'运用 index' E2_In__Docs_List__Doc!PrimaryKey'加入表达式 " E2_In__Bound_Stats__Long.Doc_ID = E2_In__Docs_List__Doc.Doc_ID"商店 导致临时表
  9. 内部加入表' KS'结果是' 08)'使用X-Prod加入然后测试 表达式"(KS.Class_ID是Null或KS.Class_ID = StatsT.class_id)和 ((KS.OrigP是Null或KS.OrigP = StatsT.OrigP)和((KS.OrigP_Type是 Null或KS.OrigP_Type = StatsT.OrigP_Type)和((KS.Prod_ID是空的或者 KS.Prod_ID = StatsT.prod_id)和((KS.Doc_Typ_ID是空的或者 KS.Doc_Typ_ID = StatsT.doc_typ_id)和((KS.Doc_I"
  10. ' 09)'
  11. 的分组结果
  12. 内部加入结果' 06)'结果' 10)'使用临时索引  加入表达式" SLJ.Exp_Sign = MP.Exp_Sign和  SLJ.Invested = MP.Invested和SLJ.E_Delivery = MP.E_Delivery And  SLJ.Expense_Type = MP.Expense_Type和SLJ.Proj_ID = MP.Proj_ID And  SLJ.Doc_ID = MP.Doc_ID和SLJ.Doc_Typ_ID = MP.Doc_Typ_ID和  SLJ.Prod_ID = MP.Prod_ID和SLJ.OrigP_Type = MP.OrigP_Type"然后测试  表达" MP.Class_ID = SLJ.Class_ID和(MP.OrigP = SLJ.OrigP And  MP.MaxOfPriority = SLJ.Priority)"
  13. ' 11)'
  14. 的小组结果

    好计划:
    --- Matrix_Math_AAA_Good ---

    查询输入

    Table 'KS'  
    Table 'E2_In__Bound_Stats__Long'  
    Table 'E2_In__Docs_List__Doc'  
        Using index 'PrimaryKey'  
        Having Indexes:  
        PrimaryKey 12465 entries, 22 pages, 12465 values  
          which has 1 column, fixed, unique, primary-key, no-nulls  
        Doc_Type_ID1 12465 entries, 15 pages, 14 values  
          which has 1 column, fixed  
        Doc_ID1 12465 entries, 22 pages, 12465 values  
          which has 1 column, fixed  
    Table 'KS'  
    Table 'E2_In__Bound_Stats__Long'  
    Table 'E2_In__Docs_List__Doc'  
        Using index 'PrimaryKey'  
        Having Indexes:  
        PrimaryKey 12465 entries, 22 pages, 12465 values  
          which has 1 column, fixed, unique, primary-key, no-nulls  
        Doc_Type_ID1 12465 entries, 15 pages, 14 values  
          which has 1 column, fixed  
        Doc_ID1 12465 entries, 22 pages, 12465 values  
          which has 1 column, fixed  
    Table 'Allocations'  
        Using index 'PrimaryKey'  
        Having Indexes:  
        PrimaryKey 312 entries, 4 pages, 312 values  
          which has 5 columns, fixed, unique, primary-key, no-nulls  
        Allocation_ID 312 entries, 1 page, 6 values  
          which has 1 column, fixed
    

    结束对查询的输入

    1. 通过扫描测试表达式限制表E2_In__Bound_Stats__Long的行" StatsT.Prod_ID = 104和StatsT.Doc_ID = 10437"
    2. 通过扫描测试表达式限制表E2_In__Bound_Stats__Long的行" StatsT.Prod_ID = 104和StatsT.Doc_ID = 10437"
    3. 内部加入结果' 02)'到表' E2_In__Docs_List__Doc'使用索引' E2_In__Docs_List__Doc!PrimaryKey' join表达式" E2_In__Bound_Stats__Long.Doc_ID = E2_In__Docs_List__Doc.Doc_ID"将结果存储在临时表中
    4. 内部加入表' KS'结果是' 03)'使用X-Prod join然后测试表达式"(KS.Class_ID是Null或KS.Class_ID = StatsT.class_id)和((KS.OrigP是Null或KS.OrigP = StatsT.OrigP)和((KS.OrigP_Type是Null或KS.OrigP_Type = StatsT.OrigP_Type)和((KS.Prod_ID是Null或KS.Prod_ID = StatsT.prod_id)和((KS.Doc_Typ_ID是Null或KS.Doc_Typ_ID = StatsT.doc_typ_id)和((KS。 Doc_I"
    5. ' 04)'
    6. 的分组结果
    7. 内部加入表' KS'结果' 05)'使用临时索引连接表达式" SLJ.Exp_Sign = MP.Exp_Sign"然后测试表达式" MP.MaxOfPriority = SLJ.Priority"
    8. 排序结果' 06)'
    9. 内部加入结果' 01)'结果' 07)'使用临时索引连接表达式" SLJ.E_Delivery = MP.E_Delivery和SLJ.Expense_Type = MP.Expense_Type和SLJ.Proj_ID = MP.Proj_ID和SLJ.Doc_ID = MP.Doc_ID和SLJ.Prod_ID = MP.Prod_ID和SLJ .OrigP_Type = MP.OrigP_Type和SLJ.Class_ID = MP.Class_ID和SLJ.OrigP = MP.OrigP和SLJ.Invested = MP.Invested"然后测试表达式"(KS.Class_ID是Null或KS.Class_ID = StatsT.class_id)和((KS.OrigP是Null或KS.OrigP = StatsT.OrigP)和((KS.OrigP_Type是Null或KS。 OrigP_Type = StatsT.OrigP_Type)和((KS.Prod_ID为空或KS.Prod_ID = StatsT.prod_id)和((KS.Doc_ID为空或KS.Doc_ID = StatsT.doc_id)和(KS.Proj_ID为空或&#34 ;
    10. 内部加入结果' 08)'表格'分配'使用索引'分配!PrimaryKey'联接表达式" SLJ.Alloc_ID = Allocations.Allocation_ID而MP.Invested = Allocations.Invested而MP.E_Delivery = Allocations.E_Delivery而MP.Expense_Type = Allocations.Expense_Type"
    11. 内部加入结果' 09)'到表' E2_In__Docs_List__Doc'使用索引' E2_In__Docs_List__Doc!PrimaryKey' join表达式" E2_In__Bound_Stats__Long.Doc_ID = E2_In__Docs_List__Doc.Doc_ID"然后测试表达式" MP.Doc_Typ_ID = SLJ.Doc_Typ_ID And(KS.Doc_Typ_ID是Null或KS.Doc_Typ_ID = StatsT.doc_typ_id)"
    12. ' 10)'
    13. 的分组结果

      结束2013-12-30编辑

1 个答案:

答案 0 :(得分:0)

建议的答案 - 任何人都可以证实这是有道理的吗?

bound_stats表有一个11字段主键。 “松散”连接为SLJ提供了最多12个字段的概念键。 MP是一个获得最大游击(最大组数)的组具有11个字段键,但也必须以优先级(最大n)连接回SLJ。因此,有一个12字段连接,其中第11个字段碰巧有一些distingushing数据(我认为错误)。

在错误查询计划的情况下,步骤11是:
11)使用临时索引

将“06)'的内部连接结果与'10)'的结果联系起来

我认为这个临时索引受到10个字段的访问限制。因此,前10个之后的字段产生不正确的结果。好的查询计划使用排序,虽然可能较慢,但可能绕过索引的10字段限制(或者只是幸运)。

解决方案:重新设计系统以避免键大于长度8 可能的替代方案:使用显式排序+“第一”访问功能来实现单通道解决方案到最大n组。取决于“排序依据”避免10场限制 - 我不知道这是否属实。

那么 - 我确实找到了解决方案,还是因为不重要的事情而分心?如果访问在连接上抛出错误而不是错误地执行错误,那肯定会很好。