如何在不使用SQL中的相关子查询的情况下获取最早的日期?

时间:2012-11-04 21:19:30

标签: sql oracle greatest-n-per-group correlated-subquery

以下代码列出了所有发票,我只想要供应商提供的最早发票:

SELECT DISTINCT vendor_name, i.invoice_number AS OLDEST_INVOICE, 
    MIN(i.invoice_date), i.invoice_total
FROM vendors v
JOIN invoices i
ON i.vendor_id = v.vendor_id
GROUP BY vendor_name, invoice_number, invoice_total
ORDER BY MIN(i.invoice_date);

4 个答案:

答案 0 :(得分:1)

TDQD的时间 - 测试驱动的查询设计

每个供应商的发票的最短日期由:

SELECT vendor_id, MIN(invoice_date) AS invoice_date
  FROM invoices
 GROUP BY vendor_id

相应的最低发票编号(假设在{1}}是真正的DATE且没有时间成分的情况下,可能在供应商开具发票的第一天发送了多张发票;如果DATE包含时间成分,第二个MIN()可能是不必要的),是:

invoice_date

您可以将此表达式与其他表连接以满足您的查询要求:

SELECT vendor_id, MIN(invoice_number) AS invoice_number
  FROM invoices AS i
  JOIN (SELECT vendor_id, MIN(invoice_date) AS invoice_date
          FROM invoices
         GROUP BY vendor_id
       ) AS j ON j.vendor_id = i.vendor_id AND j.invoice_date = i.invoice_date
 GROUP BY vendor_id

毫无疑问,还有其他方法来设计它。请注意,这些子查询都不是相关的子查询。

TDQD纯粹是名义上的;没有DBMS在检查这些查询是否在语法上有效时更加困难,更不用说返回正确答案了。 OTOH,这是一种标准技术。

如果您希望在GROUP BY子句中列出大量列,则可以通过让SELECT v.*, i.* FROM vendors AS v JOIN (SELECT vendor_id, MIN(invoice_number) AS invoice_number FROM invoices AS i JOIN (SELECT vendor_id, MIN(invoice_date) AS invoice_date FROM invoices GROUP BY vendor_id ) AS j ON j.vendor_id = i.vendor_id AND j.invoice_date = i.invoice_date GROUP BY vendor_id ) AS inv_info ON v.vendor_id = inv_info.vendor_id JOIN invoices AS i ON i.invoice_number = inv_info.invoice_number 子查询返回相关的发票列来最终加入invoices。我不喜欢写出很多列名 - 但如果我担心性能,我会测量它是否有显着差异。

您可能会发现有一个OLAP函数/查询可以更快地完成工作。

答案 1 :(得分:1)

我们将使用ROW_NUMBER()按供应商的日期对发票进行“排名”,然后仅选择每个供应商最早的发票:

SELECT vendor_name, invoice_number AS oldest_invoice, invoice_date, invoice_total
  FROM vendors v
 INNER JOIN (SELECT invoices.*,
                    ROW_NUMBER() OVER (PARTITION BY vendor_id ORDER BY invoice_date ASC)
                      AS rn
               FROM invoices) i
       ON i.vendor_id = v.vendor_id
          AND
          i.rn = 1;

答案 2 :(得分:0)

请改为尝试:

SELECT DISTINCT 
    v.vendor_name, 
    i.invoice_number AS OLDEST_INVOICE, 
    i2.MinDate, 
    i.invoice_total
FROM vendors v
INNER JOIN invoices i  ON i.vendor_id = v.vendor_id
INNER JOIN
(
    SELECT 
      invoice_number , 
      MIN(i.invoice_date) MinDate
    FROM invoices
    GROUP BY invoice_number
) i2 ON  i.invoice_number = i2.invoice_number
     AND i.invoice_date   = i2.MinDate
ORDER BY i2.MinDate;

答案 3 :(得分:0)

HAVING不会在这里工作吗?

SELECT DISTINCT vendor_name, i.invoice_number AS OLDEST_INVOICE, 
    MIN(i.invoice_date), i.invoice_total
FROM vendors v
JOIN invoices i
ON i.vendor_id = v.vendor_id
GROUP BY vendor_name, invoice_number, invoice_total
HAVING i.invoice_date = MIN (i.invoice_date)
ORDER BY MIN(i.invoice_date);