可能与游标/加入有关的问题
这是我的情况:
表一包含一组使用ID作为唯一标识符的数据。该表与约6个其他表具有一对多的关系。
给定表ID为001的表1:
表2可能有3行带有外键:001
表3可能有12行带有外键:001
表4可能有0行带有外键:001
表5可能有28行带有外键:001
我需要编写一个报告,列出指定时间范围内表1中的所有行,然后列出一些引用该表的表中包含的所有数据。
我当前的伪代码方法如下所示:
select * from table 1 foreach(result) { print result; select * from table 2 where id = result.id; foreach(result2) { print result2; } select * from table 3 where id = result.id foreach(result3) { print result3; } //continued for each table }
这意味着单个报告可以在1000个查询中运行。我知道这太过分了,但是我的sql-fu有点弱,我可以使用一些帮助。
解决方案
左外连接Table1上的Tables2-N
SELECT Table1.*, Table2.*, Table3.*, Table4.*, Table5.* FROM Table1 LEFT OUTER JOIN Table2 ON Table1.ID = Table2.ID LEFT OUTER JOIN Table3 ON Table1.ID = Table3.ID LEFT OUTER JOIN Table4 ON Table1.ID = Table4.ID LEFT OUTER JOIN Table5 ON Table1.ID = Table5.ID WHERE (CRITERIA)
啊!程序!如果我们需要在第一个表的结果之后对其他表的结果进行排序,则我的SQL将看起来像这样。
Insert Into #rows Select id from Table1 where date between '12/30' and '12/31' Select * from Table1 t join #rows r on t.id = r.id Select * from Table2 t join #rows r on t.id = r.id --etc
如果要按初始ID对结果进行分组,请使用左外连接,如前所述。
如果我们感觉胆大,最好使用Crystal或者Jasper之类的报告工具,甚至使用XSL-FO。他们内置了专门处理此问题的东西。这不是在原始SQL中能很好地工作的东西。
如果所有行的格式(标题和所有详细信息)都相同,那么将其作为存储过程也将非常容易。
我将要做的事情:将其作为联接进行,这样我们将在每一行上都有标头数据,然后使用报告工具进行分组。
将所有表连接在一起。
select * from table_1 left join table_2 using(id) left join table_3 using(id);
然后,我们需要汇总代码中的列,以根据需要设置报告格式。
SELECT * FROM table1 t1 INNER JOIN table2 t2 ON t1.id = t2.resultid -- this could be a left join if the table is not guaranteed to have entries for t1.id INNER JOIN table2 t3 ON t1.id = t3.resultid -- etc
或者,如果数据全部采用相同的格式,则可以这样做。
SELECT cola,colb FROM table1 WHERE id = @id UNION ALL SELECT cola,colb FROM table2 WHERE resultid = @id UNION ALL SELECT cola,colb FROM table3 WHERE resultid = @id
这实际上取决于我们需要将数据输出到报表的格式。
如果我们可以提供有关输出结果的示例,我可能会提供更多帮助。
加入对我不利。我讨厌不得不纠缠客户端上的数据。左连接的所有这些空值。
这是一个不使用联接的基于集合的解决方案。
INSERT INTO @LocalCollection (theKey) SELECT id FROM Table1 WHERE ... SELECT * FROM Table1 WHERE id in (SELECT theKey FROM @LocalCollection) SELECT * FROM Table2 WHERE id in (SELECT theKey FROM @LocalCollection) SELECT * FROM Table3 WHERE id in (SELECT theKey FROM @LocalCollection) SELECT * FROM Table4 WHERE id in (SELECT theKey FROM @LocalCollection) SELECT * FROM Table5 WHERE id in (SELECT theKey FROM @LocalCollection)
我要做的是打开以下查询的游标:
SELECT * from table1 order by id SELECT * from table1 r, table2 t where t.table1_id = r.id order by r.id SELECT * from table1 r, table3 t where t.table1_id = r.id order by r.id
然后,我将平行移动这些光标,打印出结果。我们可以这样做,因为它们都以相同的顺序出现。 (请注意,我建议尽管table1的主要ID可以命名为id,但在其他表中不会使用该名称。)
所有表格的格式都一样吗?如果不是,则必须拥有一个可以显示n种不同类型的行的报告。如果我们只对相同的列感兴趣,那么它会更容易。
大多数数据库都有某种形式的动态SQL。在这种情况下,我们可以执行以下操作:
create temporary table from select * from table1 where rows within time frame x integer sql varchar(something) x = 1 while x <= numresults { sql = 'SELECT * from table' + CAST(X as varchar) + ' where id in (select id from temporary table' execute sql x = x + 1 }
但我的意思是,基本上,我们要在主表上运行一个查询以获取所需的行,然后为每个子表运行一个查询以获取与主表匹配的行。
如果报告要求每个表具有相同的2列或者3列,则可以将select * from tablex更改为" insert into",然后在末尾获得单个结果集...