sql - 拉取数据而不改变引用表中的项目顺序

标签 sql sql-server sql-server-2008-r2

我想查找临时表中列出的值:

所以让我们说:

Create Table #mylist
(
eserial nvarchar(35) Collate SQL_Latin1_General_CP850_CI_AS,
refdate datetime
)

Insert Into #mylist (eserial, refdate) Values ('A', '2015-09-15')
Insert Into #mylist (eserial, refdate) Values ('B', '2015-09-14')
Insert Into #mylist (eserial, refdate) Values ('C', '2015-09-13')
Insert Into #mylist (eserial, refdate) Values ('D', '2015-09-12')

我需要结果是小于引用日期的Top 1日期。
并且应该以与临时表中相同的顺序返回。

我尝试过的:

Select
    lst.eserial,
    lst.refdate,
    app.CREATEDDATETIME,
From #mylist lst
Outer Apply 
    (Select Top 1 rec.CREATEDDATETIME, rec.ESERIAL, rec.ITEMID
     From TableSource rec
     Where lst.eserial=rec.ESERIAL And rec.CREATEDDATETIME<lst.refdate
     Order By rec.CREATEDDATETIME Desc
    ) As app

这可以工作,但速度很慢。此外,如果行数增加,它不会一致地保留 eserial 的序列。我需要查询来保留我将其放入临时表中的顺序。

我的预期输出很简单:

enter image description here

其中 eserial 与临时表的序列相同,CREATEDDATETIME 是小于引用日期的最大日期。如果您了解 Excel,则更像是条件 Vlookup

最佳答案

不太清楚你的意思

maintain the sequence of the items in the temporary table

,但如果您想获得按 eserial 排序的结果,则必须将 ORDER BY eserial 添加到查询中。如果没有 ORDER BY,结果行可以按任何顺序返回。这适用于您选择的任何方法。

因此,以您最后一个查询为基础,它将如下所示:

Select
    lst.eserial
    ,lst.refdate
    ,app.CREATEDDATETIME
From
    #mylist lst
    Outer Apply
    (
        Select Top 1 rec.CREATEDDATETIME
        From TableSource rec
        Where lst.eserial=rec.ESERIAL And rec.CREATEDDATETIME<lst.refdate
        Order By rec.CREATEDDATETIME Desc
    ) As app
ORDER BY lst.eserial;

为了使其快速高效地工作,请在 (ESERIAL, CREATEDDATETIME) 上向 TableSource 添加索引。索引中列的顺序很重要。

了解OUTER APPLY 查询中是否使用了任何其他列以及如何使用它们也很重要。您在问题的第一个变体中提到了列AREAID,但在最后一个变体中没有提到。如果您确实有更多列,请清楚地表明您打算如何使用它们,因为正确的索引将取决于它。 (ESERIAL, CREATEDDATETIME) 上的索引足以满足我上面编写的查询,但如果您有更多列,则可能需要不同的索引。

如果您使用PRIMARY KEY定义临时表,它也会对优化器有所帮助:

Create Table #mylist
(
    eserial nvarchar(35) Collate SQL_Latin1_General_CP850_CI_AS PRIMARY KEY,
    refdate datetime
)

主键将创建唯一的聚集索引。

还有一个重要的说明。主 TableSource 表中 ESERIALCREATEDDATETIME 列的类型和排序规则是什么?确保临时表中列的类型和排序规则与主 TableSource 表匹配。如果类型不同(varcharnvarchardatetimedate)或排序规则不同,索引可能会不使用 => 会很慢。

编辑

您在问题中多次使用短语“与临时表相同的序列”,但并不清楚您的意思。您的示例数据无助于解决歧义。列名 eserial 也增加了困惑。我可以看到两种可能的含义:

  1. 返回临时表中的行,按 eserial 列中的值排序。
  2. 按照插入顺序从临时表中返回行。

我原来的答案意味着(1):它返回临时表中的行,这些行按 eserial 列中的值排序。

如果您想保留行插入表中的顺序,则需要以某种方式明确记住该顺序。最简单的方法是向临时表添加一个 IDENTITY 列,然后按此列进行排序。像这样:

Create Table #mylist
(
    ID int IDENTITY PRIMARY KEY,
    eserial nvarchar(35) Collate SQL_Latin1_General_CP850_CI_AS,
    refdate datetime
)

并在最终查询中使用ORDER BY lst.ID

关于sql - 拉取数据而不改变引用表中的项目顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32389446/

相关文章:

php - SQL 查询对于另一个 mysql 版本执行速度较慢?

c# - 更新记录

php - SQL Server 选择具有相同最后操作的行列表

mysql - SQL 和分组查询

SQL 服务器 : verify that two columns are in same sort order

tsql - 哪里存在 - 所有 - 分组依据?

sql - 如何在 20 行后选择前 5 个

php - 类似于 PL/SQL 中的 += 或 .= 的运算符?

sql - 将所有与不存在的并入并插入

sql-server - 数据库 'Name' 的事务日志已满。要了解日志中的空间无法重用的原因,请参阅 sys.databases 中的 log_reuse_wait_desc 列