看起来这应该是一个简单解决方案的常见问题,但我还没有找到它。
我想计算child_order
,这是不同子表行的出现顺序,如下面的数据所示:
child_order PK1 PK2 ACCESS ACCESS_ID
1 99 Al NULL NULL
2 55 Charles Accounts 1
2 55 Charles Desktop 2
2 55 Charles Printer 3
2 55 Charles Servers 4
2 55 Charles VMs 5
3 66 Charles Desktop 2
3 66 Charles VMs 5
4 22 Chris Desktop 2
4 22 Chris Printer 3
4 22 Chris Servers 4
5 89 Evan Desktop 2
通过以下查询检索:
SELECT sub1.*
FROM (
SELECT ??? as child_order, sub2.*
FROM (
SELECT ct.PK1, ct.PK2, pt1.ACCESS, pt1.ACCESS_ID
FROM child_table ct
LEFT JOIN some_linktable lt ON lt.child_id = ct.id
LEFT JOIN parent_table1 pt1 ON lt.parent_id = pt1.id
WHERE ct.PK2 IN ('Charles', 'Evan', 'Al', 'Chris')
ORDER BY ct.PK2, pt1.ACCESS -- Order must be preserved
) sub2
) sub1
WHERE child_order < 10 AND (other_conditions)
我可以使用子查询,聚合,分析等,但不能使用CTE /&#34; WITH&#34;语句或临时表,因为动态生成SQL的复杂性。
具体来说,我正在为连接多个表的查询生成搜索结果的分页SQL(针对多个DBMS)。
我试图弄清楚如何简单地显示前N行,不计算由于连接而重复(例如,Chris只计算一行。Access
显示&#34;桌面,打印机,服务器&#34;)
我已经尝试了DENSE_RANK() OVER (ORDER BY PK1, PK2)
,但当然我获得了PK1 PK2顺序的排名,这对于WHERE子句来说是无用的。例如,Al的值将大于1。
我已尝试过DENSE_RANK() OVER (ORDER BY PK2, ACCESS)
,但它只列举了搜索字词,而不是子表格行。
我已经尝试DENSE_RANK() OVER (PARTITION BY PK2, ACCESS ORDER BY (SELECT NULL))
(让DENSE_RANK使用它给出的行顺序,这就是我想要对值进行排名的方式),但只有&#34; 1&#34;归还。
我会省略我的其他&#34; 尝试随机的东西&#34; - 阶段尝试。
我想避免使用SELECT DISTINCT PK1, PK2 WHERE (search) ORDER BY (sortorder)
子查询,因为可能存在零个或非常多个主键字段,因此动态SQL生成会很棘手,另外,我怀疑性能会因所有{{1检查。
答案 0 :(得分:1)
尽管您对SELECT DISTINCT
存有疑虑,但这可能是子查询的最佳选择:
SELECT row_number() OVER (ORDER BY PK2) AS child_order, PK1, PK2
FROM (
SELECT DISTINCT PK1, PK2
FROM child_table
WHERE PK2 IN ('Charles', 'Evan', 'Al', 'Chris')
ORDER BY PK2
LIMIT 9) sub2
child_order
字段仅取决于表child_table
,并且您只需要9行,因此仅在该表的子查询中计算child_order
。完成后,您可以加入其他表。如果您在child_table(PK1, PK2)
上有索引,那么这应该是一个非常快速的索引搜索。它需要一些过滤和内部限制,因此包络查询更简单:
SELECT sub1.child_order, PK1, PK2, pt1.ACCESS, pt1.ACCESS_ID
FROM child_table ct
JOIN (
SELECT row_number() OVER (ORDER BY PK2) AS child_order, PK1, PK2
FROM (
SELECT DISTINCT PK1, PK2
FROM child_table
WHERE PK2 IN ('Charles', 'Evan', 'Al', 'Chris')
ORDER BY PK2
LIMIT 9) sub2
) sub1 USING (PK1, PK2)
LEFT JOIN some_linktable lt ON lt.child_id = ct.id
LEFT JOIN parent_table1 pt1 ON lt.parent_id = pt1.id
WHERE <other conditions>
ORDER BY sub1.child_order, pt1.ACCESS; -- Faster to order by int