我正在尝试计算返回表中的最大值,以及该表中的其他值。但是,我正在执行此操作的表不是“真正的”表,它是由子查询生成的表。这给了我一些问题,因为我不认为我可以加入它两次,而不重新指定整个子查询。
我目前有一个SQL Server解决方案,使用ROW_NUMBER() OVER (PARTITION BY providerId ORDER BY partnershipSetScore DESC) rnk
,但我正在寻找一个DBMS不可知版本,如果可能的话,因为项目的单元测试在没有这个的Sqlite DB中运行功能。
以下是架构和我的SQL Server特定查询,以防它们有用:
课程:
学校:
伙伴关系:
SchoolPartnership:
以下是查询:
SELECT
schoolId,
partnershipId AS bestPartnershipSetId,
partnershipScore AS bestPartnershipScore
FROM
(
SELECT
pp.schoolId,
partnershipScores.partnershipId,
partnershipScores.partnershipScore,
ROW_NUMBER() OVER (PARTITION BY schoolId ORDER BY partnershipScore DESC) rnk
FROM schoolPartnership pp
INNER JOIN (
SELECT
pp.partnershipId,
(
(CASE WHEN SUM(CASE WHEN c.name LIKE '%French%' THEN 1 ELSE 0 END) > 0 THEN 1 ELSE 0 END)
+ (CASE WHEN SUM(CASE WHEN c.name LIKE '%History%' THEN 1 ELSE 0 END) > 0 THEN 1 ELSE 0 END)
) AS partnershipScore
FROM schoolPartnership pp
INNER JOIN course c ON c.schoolId = pp.schoolId
GROUP BY partnershipId
) AS partnershipScores ON partnershipScores.partnershipId = pp.partnershipId
) AS schoolPartnershipScores
WHERE rnk = 1
如果您需要有关我正在尝试实现的内容的更多信息,请参阅Custom sorting algorithm for a large amount of data:此查询将是一个较大查询的子查询,该查询通过最合适的合作关系对学校进行排序。
答案 0 :(得分:1)
也许,当谈到加入子查询两次时,你会想到这种技巧:
SELECT a.*
FROM atable a
INNER JOIN (
SELECT
col1,
MAX(col2) AS max_col2
FROM atable
GROUP BY col1
) m
ON a.col1 = m.col1 AND a.col2 = m.max_col2
;
使用DBMS不可知的方式(至少在SQL Server和SQLite中工作)来完成这项工作如果这是关于单个表的话,那就完全没问题了
相反,你有一个子查询。但是,我看不到其他任何方法可以完成您的要求。因此,在这种情况下,我可以看到两个选项(一个可能在您的特定情况下不适用,但通常仍然是一个选项):执行您要避免的操作,即专门为查找每个组的聚合值复制子查询,然后将其连接回相同的子查询,如上所述。
暂时保留子查询的结果,然后将上述技术应用于临时结果集。
第一种选择确实非常有吸引力,所以不那么好,因为希望第二种选择可能有效。
第二个选项的一个问题是临时数据集在SQL Server和SQLite中的实现方式不同。在SQLite中,您使用CREATE TEMPORARY TABLE
语句。 SQL Server在TEMPORARY
语句的上下文中不支持CREATE TABLE
关键字,而是在表名的开头使用特殊字符(#
)来表示表实际上是临时表。
因此,我能看到的唯一解决方法是使用普通表作为临时存储。您可以创建一次,然后在每次运行查询时删除其内容,就在插入临时结果集之前:
DELETE FROM TempTable;
INSERT INTO TempTable (
schoolId,
bestPartnershipSetId,
bestPartnershipScore
)
SELECT
pp.schoolId,
partnershipScores.partnershipId,
partnershipScores.partnershipScore,
FROM
...
;
SELECT ...
FROM TempTable
...
;
或者你可以创造&每次运行查询时都将其删除:
CREATE TABLE TempTable (
...
);
INSERT INTO TempTable (...)
SELECT ...
FROM ...
;
SELECT ...
FROM TempTable
...
;
DROP TABLE TempTable;
请注意,在SQL Server中使用普通表作为临时存储不是并发友好的。如果这可能会造成问题,您可能不得不放弃此选项并最终获得第一个选项。 (但是,当您需要独立于平台的解决方案时,这可能是您必须支付的成本,尤其是当平台与SQL Server和SQLite不同时。)
答案 1 :(得分:0)
这是你想要的结构:
with t as (<subquery goes here>)
select t.*,
max(col) over () as MaxVal
from t
有点难以看出它如何适合您的查询,因为我无法分辨基本子查询是什么。
对于不止一次加入子查询,可以使用SQL Server调用的“公用表表达式” - 上面的with
子句来实现。大多数其他合理的数据库都支持这一点(MySQL和MS Access开始有两个值得注意的例外)。
答案 2 :(得分:0)
最与SQL无关的方法是使用'NON EXISTS':
SELECT * FROM schoolPartnership t1
WHERE NOT EXISTS
(SELECT * FROM schoolPartnership t2
WHERE t1.schoolId = t2.schoolId
AND t1.partnershipScore < t2.partnershipScore)
这将为您提供来自schoolPartnership的行,每个schoolId具有max partnershipScore。
答案 3 :(得分:0)
我无法找到解决方案(除了重复子查询,这是我试图避免的),因此我刚刚在PHP中为每个partnershipScore确定了MAX行,并抛弃了任何其他行。不是一个理想的解决方案,但由于我需要一个跨平台的方法,因此我没有太多其他选择。