我有两个表:TableA和TableB。两者都有“日期”和“费率”字段。我想要最低价格的TableA及其日期;以及TableB的最大费率及其日期。另外,我喜欢列出每个月和每年的内容。
我使用下面的查询从一张表中获取最低和最高利率。但是我不知道如何从TableA中获得最低利率,而从TableB中获得最高利率。
SELECT
MIN(rate) AS minRate,
(SELECT date FROM TableA WHERE rate = min(t2.rate) and month(date) = month(t2.date) and year(date) = year(t2.date) limit 1 ) as minDate,
MONTHNAME(date) as MN, YEAR(date) as YN,
MAX(rate) AS maxRate,
(SELECT date FROM TableAs WHERE rate = max(t2.rate) and month(date) = month(t2.date) and year(date) = year(t2.date) limit 1) as maxDate
FROM TableA t2
GROUP BY YEAR(date) , MONTH(date)";
编辑1:我结束了这一点。
SELECT a.MinYear AS Year, a.MinMonth AS Month, a.MinRate, b.MaxRate, a.MinDate, b.MaxDate
FROM (SELECT YEAR(date) AS MinYear, MONTH(date) AS MinMonth, MIN(rate) AS MinRate,
(SELECT date FROM $TableA WHERE rate = MIN(t2.rate) AND YEAR(date) = YEAR(t2.date) AND MONTH(date) = MONTH(t2.date) limit 1) AS MinDate
FROM $TableA t2
GROUP BY MinYear, MinMonth
) AS a
JOIN (SELECT YEAR(date) AS MaxYear, MONTH(date) AS MaxMonth, MAX(rate) AS MaxRate,
(SELECT date FROM $TableB WHERE rate = MAX(t3.rate) AND YEAR(date) = YEAR(t3.date) AND MONTH(date) = MONTH(t3.date) limit 1) AS MaxDate
FROM $TableB t3
GROUP BY MaxYear, MaxMonth
) AS b
ON a.MinYear = b.MaxYear AND a.MinMonth = b.MaxMonth
ORDER BY Year, Month
编辑2
Jonathan Leffler的查询(测试后有微小变化)执行得更好:
SELECT a.MinYear AS Year, a.MinMonth AS Month, a.MinDate, a.MinRate, b.MaxDate, b.MaxRate
FROM (SELECT n.MinYear, n.MinMonth, a.Date AS MinDate, n.MinRate
FROM $TableA AS a
JOIN (SELECT YEAR(date) AS MinYear, MONTH(date) AS MinMonth, MIN(rate) AS MinRate
FROM $TableA
GROUP BY MinYear, MinMonth
) AS n
ON a.Rate = n.MinRate AND YEAR(a.Date) = n.MinYear AND MONTH(a.Date) = n.MinMonth
) AS a
JOIN (SELECT x.MaxYear, x.MaxMonth, b.Date AS MaxDate, x.MaxRate
FROM $TableB AS b
JOIN (SELECT YEAR(date) AS MaxYear, MONTH(date) AS MaxMonth, MAX(rate) AS MaxRate
FROM $TableB
GROUP BY MaxYear, MaxMonth
) AS x
ON b.Rate = x.MaxRate AND YEAR(b.Date) = x.MaxYear AND MONTH(b.Date) = x.MaxMonth
) AS b
ON a.MinYear = b.MaxYear AND a.MinMonth = b.MaxMonth
ORDER BY Year, Month";
最佳答案
原始答案
您需要创建两个结果集,一个来自tableA,一个来自TableB,然后将它们联接。与任何复杂的SQL查询一样,我将结果分为几部分。首先,我们需要TableA中每个月的最低费率:
SELECT YEAR(date) AS MinYear, MONTH(date) AS MinMonth, MIN(rate) AS MinRate
FROM TableA
GROUP BY MinYear, MinMonth;
从TableB中查询最大速率的类似查询是:
SELECT YEAR(date) AS MaxYear, MONTH(date) AS MaxMonth, MAX(rate) AS MaxRate
FROM TableB
GROUP BY MaxYear, MaxMonth;
现在,您需要在“年”和“月”列上加入这两个结果:
SELECT a.MinYear AS Year, a.MinMonth AS Month, a.MinRate, b.MaxRate
FROM (SELECT YEAR(date) AS MinYear, MONTH(date) AS MinMonth, MIN(rate) AS MinRate
FROM TableA
GROUP BY MinYear, MinMonth
) AS a
JOIN (SELECT YEAR(date) AS MaxYear, MONTH(date) AS MaxMonth, MAX(rate) AS MaxRate
FROM TableB
GROUP BY MaxYear, MaxMonth
) AS b
ON a.MinYear = b.MaxYear AND a.MinMonth = b.MaxMonth
ORDER BY Year, Month;
扩展以管理丢失的数据
如果您不得不担心TableA或TableB中的数据丢失,那么生活会更加复杂。然后,您确实需要FULL OUTER JOIN,但某些DBMS不提供此功能。如果您要担心两个表中都没有显示月份,则需要生成一个表,该表指定您感兴趣的日期(月和年),然后可以将这两个表分别左上面的表达式。
SELECT c.RefYear AS Year, c.RefMonth AS Month, a.MinRate, b.MaxRate
FROM MonthYearTable AS c
LEFT JOIN
(SELECT YEAR(date) AS MinYear, MONTH(date) AS MinMonth, MIN(rate) AS MinRate
FROM TableA
GROUP BY MinYear, MinMonth
) AS a
ON c.RefYear = a.MinYear AND c.RefMonth = a.MinMonth
LEFT JOIN
(SELECT YEAR(date) AS MaxYear, MONTH(date) AS MaxMonth, MAX(rate) AS MaxRate
FROM TableB
GROUP BY MaxYear, MaxMonth
) AS b
ON c.RefYear = b.MaxYear AND c.RefMonth = b.MaxMonth
ORDER BY Year, Month;
如果需要,您可以从MonthYearTable中指定感兴趣的日期范围。
查找发生极值利率的日期
如果按照评论中的建议,如果答案应包括出现最高或最低利率的每个月内的确切日期,则“查找极值”子查询将更为复杂:
SELECT n.MinYear, n.MinMonth, a.Date AS MinDate, n.MinRate
FROM TableA AS a
JOIN (SELECT YEAR(date) AS MinYear, MONTH(date) AS MinMonth, MIN(rate) AS MinRate
FROM TableA
GROUP BY MinYear, MinMonth
) AS n
ON a.Rate = n.MinRate AND YEAR(a.Date) = n.MinYear AND MONTH(a.Date) = n.MinMonth
对于针对TableB的查询类似:
SELECT x.MaxYear, x.MaxMonth, b.Date AS MaxDate, x.MaxRate
FROM TableB AS b
JOIN (SELECT YEAR(date) AS MaxYear, MONTH(date) AS MaxMonth, MAX(rate) AS MaxRate
FROM TableB
GROUP BY MaxYear, MaxMonth
) AS x
ON b.Rate = x.MinRate AND YEAR(b.Date) = x.MaxYear AND MONTH(b.Date) = x.MaxMonth
结合这些导致查询:
SELECT a.MinYear AS Year, a.MinMonth AS Month, a.MinDate, a.MinRate, b.MinDate, b.MaxRate
FROM (SELECT n.MinYear, n.MinMonth, a.Date AS MinDate, n.MinRate
FROM TableA AS a
JOIN (SELECT YEAR(date) AS MinYear, MONTH(date) AS MinMonth, MIN(rate) AS MinRate
FROM TableA
GROUP BY MinYear, MinMonth
) AS n
ON a.Rate = n.MinRate AND YEAR(a.Date) = n.MinYear AND MONTH(a.Date) = n.MinMonth
) AS a
JOIN (SELECT x.MaxYear, x.MaxMonth, b.Date AS MaxDate, x.MaxRate
FROM TableB AS b
JOIN (SELECT YEAR(date) AS MaxYear, MONTH(date) AS MaxMonth, MAX(rate) AS MaxRate
FROM TableB
GROUP BY MaxYear, MaxMonth
) AS x
ON b.Rate = x.MinRate AND YEAR(b.Date) = x.MaxYear AND MONTH(b.Date) = x.MaxMonth
) AS a
ON a.MinYear = b.MaxYear AND a.MinMonth = b.MaxMonth
ORDER BY Year, Month;
请注意,如果在给定月份的三个不同日期报告了相同的最低费率,则该月将有三行输出,每一天中的每一行。实际上,如果还有两天发生最大速率,那么该月将有六行输出。如果这不是必需的,则可以在一个月内的日期进行适当的汇总(最有可能表示MIN或MAX):
SELECT n.MinYear, n.MinMonth, MAX(a.Date) AS MinDate, n.MinRate
FROM TableA AS a
JOIN (SELECT YEAR(date) AS MinYear, MONTH(date) AS MinMonth, MIN(rate) AS MinRate
FROM TableA
GROUP BY MinYear, MinMonth
) AS n
ON a.Rate = n.MinRate AND YEAR(a.Date) = n.MinYear AND MONTH(a.Date) = n.MinMonth
GROUP BY n.MinYear, n.MinMonth, n.MinRate
然后将此表达式组合到主查询的“最终”(下一个)版本中:
SELECT a.MinYear AS Year, a.MinMonth AS Month, a.MinDate, a.MinRate, b.MinDate, b.MaxRate
FROM (SELECT n.MinYear, n.MinMonth, MAX(a.Date) AS MinDate, n.MinRate
FROM TableA AS a
JOIN (SELECT YEAR(date) AS MinYear, MONTH(date) AS MinMonth, MIN(rate) AS MinRate
FROM TableA
GROUP BY MinYear, MinMonth
) AS n
ON a.Rate = n.MinRate AND YEAR(a.Date) = n.MinYear AND MONTH(a.Date) = n.MinMonth
GROUP BY x.MaxYear, x.MaxMonth, x.MaxRate
) AS a
JOIN (SELECT x.MaxYear, x.MaxMonth, MAX(b.Date) AS MaxDate, x.MaxRate
FROM TableB AS b
JOIN (SELECT YEAR(date) AS MaxYear, MONTH(date) AS MaxMonth, MAX(rate) AS MaxRate
FROM TableB
GROUP BY MaxYear, MaxMonth
) AS x
ON b.Rate = x.MinRate AND YEAR(b.Date) = x.MaxYear AND MONTH(b.Date) = x.MaxMonth
GROUP BY n.MinYear, n.MinMonth, n.MinRate
) AS a
ON a.MinYear = b.MaxYear AND a.MinMonth = b.MaxMonth
ORDER BY Year, Month;
我不愿尝试一次性写出最终查询。但是通过逐步构建它,即使没有将其提交给DBMS,我也有一定的信心,它几乎是准确的。如果我正在测试它,我可能会直接进行最终查询,但是如果它有问题,那么我将测试组件查询,一次使用一个子查询,直到零件产生正确的结果。然后合并总查询。
扩展以处理日期范围和再次丢失数据
在评论中,MonthYearTable引起了一些混乱。正如我在评论中的答复所指出的那样,问题是,如果表A和B中有1月和3月的数据,但由于某些特殊原因,则没有2月的数据,那么“最终”查询将不会显示2月的任何内容。如果要明确查看二月份的(缺少)值,请输入MonthYearTable
可以包含以下行:
Year Month
2011 1
2011 2
2011 3
然后,您可以从那里选择要报告的月份,并在最终表中对极值查询进行LEFT OUTER JOIN。这样,即使TableA或TableB中没有2月(2011-02)的数据,也会在结果行中显示该数据。并且,假设您实际上从2009年1月到2012年12月每个月都有YearMonthTable中的数据,但是您希望报表涵盖从2009年7月到2011年6月的时期,则需要在MonthYearTable上指定过滤条件( d可能也会在TableA和TableB上执行此操作,因为优化程序不太可能为您推断子范围。
SELECT c.RefYear AS Year, c.RefMonth AS Month, a.MinDate, a.MinRate, b.MaxDate, b.MaxRate
FROM MonthYearTable AS c
LEFT JOIN
(SELECT n.MinYear, n.MinMonth, MAX(a.Date) AS MinDate, n.MinRate
FROM TableA AS a
JOIN (SELECT YEAR(m.date) AS MinYear, MONTH(m.date) AS MinMonth, MIN(m.rate) AS MinRate
FROM TableA AS m
WHERE m.date BETWEEN DATE '2009-07-01' AND DATE '2011-06-30'
GROUP BY MinYear, MinMonth
) AS n
ON a.Rate = n.MinRate AND YEAR(a.Date) = n.MinYear AND MONTH(a.Date) = n.MinMonth
GROUP BY x.MaxYear, x.MaxMonth, x.MaxRate
) AS a
JOIN (SELECT x.MaxYear, x.MaxMonth, MAX(b.Date) AS MaxDate, x.MaxRate
FROM TableB AS b
JOIN (SELECT YEAR(m.date) AS MaxYear, MONTH(m.date) AS MaxMonth, MAX(m.rate) AS MaxRate
FROM TableB AS m
WHERE m.date BETWEEN DATE '2009-07-01' AND DATE '2011-06-30'
GROUP BY MaxYear, MaxMonth
) AS x
ON b.Rate = x.MinRate AND YEAR(b.Date) = x.MaxYear AND MONTH(b.Date) = x.MaxMonth
GROUP BY n.MinYear, n.MinMonth, n.MinRate
) AS a
ON a.MinYear = b.MaxYear AND a.MinMonth = b.MaxMonth
WHERE ((c.RefYear = 2009 AND c.RefMonth >= 7) OR (c.RefYear > 2009))
AND ((c.RefYear = 2011 AND c.RefMonth <= 6) OR (c.RefYear < 2011))
ORDER BY Year, Month;
您可以对查询进行更多调整,尤其是在更多位置添加日期范围过滤器。您可以考虑使用以下表达式:
WHERE (c.RefYear * 100 + c.RefMonth) BETWEEN 200907 AND 201106
表示MonthYearTable中的日期范围。 (为此,Informix支持的DATETIME YEAR TO MONTH类型是理想的; MonthYearTable仅需要包含一个包含该类型值的单列。)
这样一来,故事就继续了……您可以无休止地处理查询,但是只要您逐步构建查询并系统地应用额外条件,就可以进行管理。临时执行此操作并尝试大爆炸查询(而不是系统地进行查询布置)只会导致混乱和灾难。
分析问题中的更新查询
选择列表中的相关子查询,尽管在主查询的FROM子句中的子查询的选择列表中;和LIMIT子句。哎哟!我倾向于避免在可能的情况下在选择列表中编写子查询。他们对我的大脑的伤害甚至超过了我的写作风格。 OTOH,经过周密的处理,他们有时会做必要的工作。
以我的风格重新格式化后,修改后的查询如下所示:
SELECT a.MinYear AS Year, a.MinMonth AS Month, a.MinRate, b.MaxRate, a.MinDate, b.MaxDate
FROM (SELECT YEAR(date) AS MinYear, MONTH(date) AS MinMonth, MIN(rate) AS MinRate,
(SELECT date
FROM $TableA
WHERE rate = MIN(t2.rate)
AND YEAR(date) = YEAR(t2.date) AND MONTH(date) = MONTH(t2.date)
LIMIT 1
) AS MinDate
FROM $TableA t2
GROUP BY MinYear, MinMonth
) AS a
JOIN (SELECT YEAR(date) AS MaxYear, MONTH(date) AS MaxMonth, MAX(rate) AS MaxRate,
(SELECT date
FROM $TableB
WHERE rate = MAX(t3.rate)
AND YEAR(date) = YEAR(t3.date) AND MONTH(date) = MONTH(t3.date)
LIMIT 1
) AS MaxDate
FROM $TableB t3
GROUP BY MaxYear, MaxMonth
) AS b
ON a.MinYear = b.MaxYear AND a.MinMonth = b.MaxMonth
ORDER BY Year, Month;
那可能行得通,但我不会对此夸大其词。我会说,我所熟悉的大多数DBMS可能会误以
MAX(t3.rate)
和MIN(t2.rate)
术语使用。未经实验,我将不信任该查询。我也倾向于不信任LIMIT 1
,当没有排序标准时,我就不会信任。如果可以将LIMIT应用于多个行,那么DBMS会急于返回哪一行,并且不确定的查询通常不是一个好主意。因此,尽管这可能行得通,但这并不是我用过的-即使假设我的DBMS接受了它。实际上,这比我容易。我对查询的思考方式永远不会提出那种设计,因此基本上没有冒犯我这样编写查询的风险。这是否好是一个单独的讨论。
关于mysql - 来自不同mysql表的最小值和最大值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9441893/