如何在一对多关系中有效地检索数据

时间:2013-06-14 10:54:11

标签: sql db2 sql-execution-plan

我遇到了一个问题,我需要运行一个Query,它应该从主表中获取一些行,并且如果主表的键存在于子表中(一对多关系),则有一个指示符。

查询可能是这样的:

select a.index, (select count(1) from second_table b where a.index = b.index) 
from first_table a;

这样我会得到我想要的结果(0 =在second_table中没有依赖记录,否则有),但我正在为从数据库中获取的每条记录运行一个子查询。我需要为至少三个类似的表得到这样一个指标,主要查询已经是至少两个表之间的一些内部联接......

我的问题是,是否有一些非常有效的方法来处理这个问题。我曾想过将记录保存在新列“first_table”中,但dbadmin不允许触发器并通过代码跟踪它是太冒险了。

解决这个问题的好方法是什么?

此查询的应用将包含两件事:

  1. 表示first_table中给定行中至少存在second_table中的一行。它是在列表中指出它。如果第二个表中没有行,我将不会打开此指示符。
  2. 搜索first_table中的所有行,其中second_table中至少有一行,或者第二个表中没有行。
  3. 我刚发现的另一个选择:

    select a.index, b.index 
    from first_table a 
    left join (select distinct(index) as index from second_table) b on a.index = b.index
    

    这样,如果b.index不存在,我将获得null(显示最终可以调整,我关注查询性能)。

    这个问题的最终目标是为这种情况找到合适的设计方法。它经常发生,真正的应用程序是一个POS系统,以显示所有客户端,并在列表中有一个图标作为指示客户端已打开订单。

7 个答案:

答案 0 :(得分:6)

尝试使用EXISTS,我认为,对于这种情况,它可能比连接表更好。在我的oracle db上,它提供了比示例查询更好的执行时间,但这可能是特定于数据库的。

SELECT first_table.ID, CASE WHEN EXISTS (SELECT * FROM second_table WHERE first_table.ID = second_table.ID) THEN 1 ELSE 0 END FROM first_table

答案 1 :(得分:2)

为什么不尝试这个

select a.index,count(b.[table id])  
from first_table a
left join second_table b
    on a.index = b.index
group by a.index

答案 2 :(得分:1)

或者你可以完全避免加入。

WITH comb AS (
SELECT index
     , 'N' as exist_ind
  FROM first_table
UNION ALL
SELECT DISTINCT 
       index
     , 'Y' as exist_ind
  FROM second_table
)
SELECT index
     , MAX(exist_ind) exist_ind
  FROM comb
 GROUP BY index

答案 3 :(得分:1)

两个想法:一个不涉及改变你的桌子而另一个想法。首先是使用现有表的那个:

SELECT
  a.index,
  b.index IS NOT NULL,
  c.index IS NOT NULL
FROM
  a_table a
LEFT JOIN
  b_table b ON b.index = a.index
LEFT JOIN
  c_table c ON c.index = a.index
GROUP BY
  a.index, b.index, c.index

值得注意的是,如果b_table.indexc_table.index是主键或以其他方式编入索引,则此查询(以及可能类似的查询)将会大有帮助。

现在是另一个想法。如果可以,而不是在b_tablec_table中插入一行来表明a_table中相应行的内容,请直接在a_table行上指明。将exists_in_b_tableexists_in_c_table列添加到a_table。每当您在b_table中插入一行时,请为a_table.exists_in_b_table = true中的相应行设置a_table。删除是更多的工作,因为为了更新a_table行,您必须检查b_table 中的任何行,而不是您刚删除的中具有相同索引的行。但是,如果删除很少,则可以接受。

答案 4 :(得分:0)

  

此查询的应用将包含两件事:

     
      
  1. 表示first_table中给定行中至少存在second_table中的一行。它是在列表中指出的。
  2.   
  3. 搜索first_table中second_table中至少有一行的所有行。
  4.   

你走了:

SELECT  a.index, 1 as c_check  -- 1: at least one row in second_table exists for a given row in first_table
FROM    first_table a
WHERE   EXISTS
        (
            SELECT  1
            FROM    second_table b
            WHERE   a.index = b.index
        );

答案 5 :(得分:0)

我假设您无法更改表格定义,例如对列进行分区。

现在,为了获得良好的性能,您需要考虑加入主表的其他表。

这完全取决于数据的人口统计数据。

  1. 如果其他连接将按高因子折叠行,则应考虑在第一个表和第二个表之间进行连接。这将允许优化器选择最佳连接顺序,即首先与其他表连接,然后与第二个表连接的结果行获得性能。

  2. 否则,您可以采用子查询方法(我建议使用exists,可能是Mikhail的解决方案)。

  3. 此外,如果您在同一会话中多次需要此类查询,则可以考虑创建临时表。

答案 6 :(得分:0)

我不是使用案例的专家,但会推荐加入......

即使您使用三张或更多桌子也能正常工作..

SELECT t1.ID,t2.name, t3.date
FROM  Table1 t1 
LEFT OUTER JOIN Table2 t2 ON t1.ID = t2.ID
LEFT OUTER JOIN Table3 t3 ON t2.ID = t3.ID
--WHERE t1.ID = @ProductID -- this is optional condition, if want specific ID details..

这将帮助您从规范化(BCNF)表中获取数据..因为它们总是在单独的表中对具有自然类型的数据进行分类..

我希望这会......