我有两个表:TableA和TableB。两者都有“日期”和“费率”字段。我希望得到TableA及其日期的最低费率;表B的最高费率及其日期。此外,我喜欢列出每个月和每年。
我使用下面的查询从一个表中获取最低和最高费率。但我无法弄清楚如何从TableB获得TableA最高费率的最低费率。
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";
答案 0 :(得分:2)
您需要创建两个结果集,一个来自tableA,一个来自TableB,然后加入它们。与任何复杂的SQL查询一样,我将结果部分构建。首先,我们需要TableA的每月最低费率:
SELECT YEAR(date) AS MinYear, MONTH(date) AS MinMonth, MIN(rate) AS MinRate
FROM TableA
GROUP BY MinYear, MinMonth;
表B中最大费率的类似查询是:
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
然后将此表达式合并到“#final”中。 (下一个)主要查询的版本:
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引起了轻微的混淆。正如我在评论中的回答中所指出的那样,问题在于,如果您在1月和3月的表A和表B中有数据,但由于某些特殊原因,2月没有数据,那么最后的数据是'查询不会显示2月的任何内容。如果要显式查看2月的(缺少)值,则为MonthYearTable 可以包含如下行:
Year Month
2011 1
2011 2
2011 3
您可以从那里选择要报告的月份,并使用最终表格中的极值查询进行LEFT OUTER JOIN。这样,即使2月(2011-02)的TableA或TableB中没有数据,也会显示结果行。并且,假设您实际上在2009年1月到2012年12月的每个月都有YearMonthTable中的数据,但是您希望报告涵盖2009年7月到2011年6月期间,您需要在MonthYearTable上指定过滤条件(和您可能也会在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只需要包含一个包含该类型值的列。)
所以故事还在继续......你可以无休止地使用查询,但只要你将它构建成碎片并系统地应用额外的标准,你就能够进行管理。执行 ad hoc 并尝试进行大爆炸查询(而不是系统地进行查询)只会导致混乱和灾难。
select-list中的相关子查询,尽管在主查询的FROM子句中的子查询的select-list中;和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接受了它。实际上,对我来说比这更容易;我对查询的思考方式永远不会出现在那个设计中,所以基本上没有我像这样制定查询的风险。这个好的与否是一个单独的讨论。
答案 1 :(得分:0)
为什么不能在select语句中使用TableB
答案 2 :(得分:0)
我不确定我是否完全了解您的需求,但我认为您需要每年每月的表A中的最低费率以及每年每月的表B的最高费率。
因此,假设每个tableA和tableB有2列“rate”和“date”,以下查询应该有效:
每年每月从tableA检索最小值:
SELECT DATE_FORMAT(`date`, '%Y%m') AS `yearmonth`, MIN(rate) AS `minrate`
FROM `tableA`
GROUP BY `yearmonth`;
每年每月从tableB检索最大值:
SELECT DATE_FORMAT(`date`, '%Y%m') AS `yearmonth`, MAX(rate) AS `maxrate`
FROM `tableB`
GROUP BY `yearmonth`;
希望它有所帮助!