在T-SQL中关联大表上的子查询的最有效方法是什么?

时间:2019-04-15 20:54:08

标签: sql-server tsql correlated-subquery

我有一个表,其中包含机器销售的品牌,型号,序列号和发票日期,我想将其与包含品牌,序列号,记录的用法,使用单位和记录日期的表配对-使用/记录表是HUUUUUUGE,并且可能没有每台机器的记录。

我尝试编写一个OUTER JOIN,但是“用法/记录”表中的数据太多,无法使其高效运行。我试图编写一个CROSS APPLY,但是我一定弄错了,因为这似乎也不怎么有效。

文件示例:

我的基本查询:

Inv. Date      Mk      Model      Serial
2019-03-29     AA      420D       0FDP09999
2019-03-21     AA      A19B-SSL   0DX240481

用法/记录表:

Mk      Serial      Usage      Units      Record Date
AA      0FDP09999   2345.0     H          2019-03-27
AA      0FDP09999   2349.2     H          2019-03-28
AA      0FDP09999   2351.8     H          2019-03-29
AA      0DX240481   0.0        H          2019-03-21
AA      0DX240481   24.0       H          2019-03-22

输出应为:

Inv. Date      Mk      Model      Serial      Usage      Units      Record Date
2019-03-29     AA      420D       0FDP09999   2351.8     H          2019-03-29
2019-03-21     AA      A19B-SSL   0DX240481   0.0        H          2019-03-21

...仅返回发票日期之前的最新条目的用法,单位和记录日期。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

您可以尝试左联接和row_number()

SELECT t1.[Inv. Date],
       t1.[Mk],
       t1.[Model],
       t1.[Serial],
       t2.[Usage],
       t2.[Units],
       t2.[Record Date]
       FROM (SELECT t1.[Inv. Date],
                    t1.[Mk],
                    t1.[Model],
                    t1.[Serial],
                    t2.[Usage],
                    t2.[Units],
                    t2.[Record Date],
                    row_number() OVER (PARTITION BY t1.[Inv. Date]
                                       ORDER BY t2.[Record Date] DESC) rn
                    FROM table1 t1
                         LEFT JOIN table2 t2
                                   ON t2.[Mk] = t1.[Mk]
                                      AND t2.[Serial] = t1.[Serial]
                                      AND t2.[Record Date] <= t1.[Inv. Date]) x
       WHERE x.rn = 1;

为提高性能,请尝试在第一个表的([Mk], [Serial], [Inv. Date])上索引,并在第二个表的索引上([Mk], [Serial], [Record Date])。或者,如果序列在不同的品牌上或多或少“独特”,则尝试切换[Mk][Serial]的位置。

答案 1 :(得分:0)

为解决此问题,我最终在最初的基本查询之外创建了其他查询。

在第一个外部查询中,我执行了此操作(“发票号”是我为了确保唯一的行号而调用的另一个字段,以防万一机器售出一次,购回然后在该时间段内再次售出):

CASE
    WHEN Q1.[Usage] IS NULL
    THEN 1
    ELSE ROW_NUMBER() OVER (PARTITION BY Q1.[Serial Number], Q1.[Mk], Q1.[Invoice Number] ORDER BY Q1.[Record Date] DESC)
END AS [RowNum]

这确保即使连接的表中没有使用情况度量,表中的每个条目都具有排序机制。

然后,下一个外部查询仅使用RowNum = 1捕获行。