【问题标题】:How can I select a row from tableA and join the next appropriate row from the same table如何从 tableA 中选择一行并从同一个表中加入下一个适当的行
【发布时间】:2017-08-10 20:33:08
【问题描述】:

我有一张包含以下内容的表格...

以上已按:CustomerID、JobType、Book 和 Page 排序

最终目标是在一个或两个为空时填充 EndBook 和 EndPage 列(在此示例中,除了第 15 行之外的每一行)。目前我只是试图创建一个 SELECT 查询,该查询返回如下所示的同一张表,但在 EndBook 和 EndPage 列中填写了值。

我期望它的工作方式是......

  • EndBook 将等于结果中下一行的 Book(按 CustomerID、JobType、Book 和 Page 排序时)。
    • 例如:ID11 将是“ABCD”
    • 例如:ID12 将是“ABCD”
    • 例如:ID13 将是“ABT5”
    • 例如:ID14 将是 ''(因为这是 typeA 的最后一个结果)
    • 例如:ID15 将是“00A1”(单独保留,不包含在查询中(因为两端都已填写)
    • 例如:ID16 将是 ''(因为这是 typeB 的最后一个结果)
    • 例如:ID17 将是 ''(因为这是客户 586 的唯一 typeC)
    • 例如:ID18 将是“1234”
  • EndPage 将等于结果中下一行的 Page(按 CustomerID、JobType、Book 和 Page 排序时)。
    • 例如:ID11 将是“126”
    • 例如:ID12 将是 '150'
    • 例如:ID13 将是 '021'
    • 例如:ID14 将是 ''(因为这是 typeA 的最后一个结果)
    • 例如:ID15 将是“005”(单独保留,不包含在查询中(因为两端都已填写)
    • 例如:ID16 将是 ''(因为这是 typeB 的最后一个结果)
    • 例如:ID17 将是 ''(因为这是客户 586 的唯一 typeC)
    • 例如:ID18 将是 '013'

我目前有以下查询,但我似乎无法得到我想要的。在这个最新的尝试中,它只返回 4 个结果,而我期望它总共返回 9 个(除了 1 个)......

SELECT
    job.CustomerID,
    job.JobType,
    job.Book,
    job.Page,
    job.EndBook,
    job.EndPage,
    next_inst.min_book,
    next_inst.min_page
FROM JobList AS job
INNER JOIN
(
    SELECT
        jl2.CustomerID,
        jl2.JobType,
        MIN(jl3.Book) AS min_book,
        MIN(jl3.Page) AS min_page
    FROM JobList AS jl2
    INNER JOIN
        JobList AS jl3 ON jl3.Book>=jl2.Book AND jl3.Page>jl2.Page
    GROUP BY jl2.CustomerID, jl2.JobType
) AS next_inst ON next_inst.min_book=job.Book AND next_inst.min_page=job.Page
WHERE job.EndBook='' or job.EndPage=''
ORDER BY job.CustomerID, job.JobType, job.Book, job.Page

【问题讨论】:

标签: sql sql-server sql-server-2016


【解决方案1】:

使用lead()窗口函数:

SELECT
    job.CustomerID,
    job.JobType,
    job.Book,
    job.Page,
    job.EndBook,
    job.EndPage,
    nextBook = lead(job.book) over (partition by CustomerId, JobType order by Book, Page),
    nextPage = lead(job.page) over (partition by CustomerId, JobType order by Book, Page)
FROM JobList AS job
ORDER BY job.CustomerID, job.JobType, job.Book, job.Page

要将null 更改为空字符串,您可以使用coalesce()isnull()


使用common table expression,我们可以把它变成update

;with cte as (
  select
      job.Customerid,
      job.JobType,
      job.Book,
      job.Page,
      job.EndBook,
      job.EndPage,
      nextBook = lead(job.book) over (partition by CustomerId, JobType order by Book, Page),
      nextPage = lead(job.page) over (partition by CustomerId, JobType order by Book, Page)
  from JobList as job
)
update cte
  set EndBook = coalesce(nextBook,'')
    , EndPage = coalesce(nextPage,'')
where EndBook = ''
   or EndPage = '';

【讨论】:

  • 天哪,如果这对我有用...我很高兴我决定问这个问题,我永远不会知道 LEAD() 函数!我现在正在测试 SqlZim!谢谢!!
  • @ArvoBowen 如果您按照我对您问题的评论中的说明进行操作,我可以提供演示。
  • SqlZim,我刚刚针对我自己的数据库进行了测试,它完全符合我的需要!我第一次看到 LEAD() 函数和 CTE 都在使用...感谢您今天教我两件重要的事情!一个问题,为什么在 CTE 开头使用分号?
  • @ArvoBowen 乐于助人!我在 CTE 的开头使用分号,因为很多人不会用分号结束他们之前的语句,所以如果有人试图将我的代码复制/粘贴到他们的设置中......实际上 Aaron Bertrand 在他的回答中解释了这一点非常问题:Why should a CTE start with a semi-colon? - Answer by Aaron Bertrand
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
相关资源
最近更新 更多