选择字段中发生更改的行并将它们连接到另一个表

Posted

技术标签:

【中文标题】选择字段中发生更改的行并将它们连接到另一个表【英文标题】:Select rows that where a change has occurred in a field and join them to another table 【发布时间】:2016-11-16 00:48:29 【问题描述】:

我有以下两张表:

Table 1
datetime (datetime)
code1 (int)
code2 (int)

Table 2
code2 (int)
description (text)

假设数据的一个例子是:

表 1

   DateTime                 Code1 Code2
** 14/11/2016 6:55:00 PM    6     21
   14/11/2016 6:56:00 PM    6     21
** 14/11/2016 6:57:00 PM    6     23
** 14/11/2016 6:58:00 PM    6     28
   14/11/2016 6:59:00 PM    6     28
   14/11/2016 7:00:00 PM    6     28
** 14/11/2016 7:01:00 PM    6     22
** 14/11/2016 7:02:00 PM    6     23
   14/11/2016 7:03:00 PM    6     23
   14/11/2016 7:04:00 PM    6     23
** 14/11/2016 7:05:00 PM    6     27
** 14/11/2016 7:06:00 PM    5     8
** 14/11/2016 7:07:00 PM    5     9
   14/11/2016 7:08:00 PM    5     9
** 14/11/2016 7:09:00 PM    5     11
** 14/11/2016 7:10:00 PM    5     12
   14/11/2016 7:11:00 PM    5     12
** 14/11/2016 7:12:00 PM    5     14
** 14/11/2016 7:13:00 PM    5     15
   14/11/2016 7:14:00 PM    5     15
** 14/11/2016 7:15:00 PM    5     17

我想运行一个 sql-express-2012 查询,该查询将仅返回加星标的行,然后根据 code2 将返回的数据连接到描述表 - 生成以下输出表:

最终输出表

   DateTime                 Code1 Code2 Description
** 14/11/2016 6:55:00 PM    6     21    some text 
** 14/11/2016 6:57:00 PM    6     23    some text 
** 14/11/2016 6:58:00 PM    6     28    some text 
** 14/11/2016 7:01:00 PM    6     22    some text 
** 14/11/2016 7:02:00 PM    6     23    some text 
** 14/11/2016 7:05:00 PM    6     27    some text 
** 14/11/2016 7:06:00 PM    5     8     some text 
** 14/11/2016 7:07:00 PM    5     9     some text 
** 14/11/2016 7:09:00 PM    5     11    some text 
** 14/11/2016 7:10:00 PM    5     12    some text 
** 14/11/2016 7:12:00 PM    5     14    some text 
** 14/11/2016 7:13:00 PM    5     15    some text 
** 14/11/2016 7:15:00 PM    5     17    some text

问候,马克

【问题讨论】:

【参考方案1】:

此答案假定时间列中的粒度固定为一分钟间隔:(它也不按要求使用窗口函数。)

Select a.*, description
  From #tbl1 As a
  Left Join #tbl1 As b
    On a.datetime = DateAdd(Minute, 1, b.datetime)
    And a.code1 = b.code1 
    And a.code2 = b.code2
  Left Join #tbl2 On a.code2 = #tbl2.code2
  Where b.datetime Is Null;

【讨论】:

谢谢,门多西。我只做了一点测试,但这似乎对我有用。然而,我对` On a.datetime = DateAdd(Minute, 1, b.datetime) And a.code1 = b.code1 And a.code2 = b.code2 `你能详细说明一下吗?另外,例如,我将如何修改代码以仅选择 Code1 = 3 的行? @beliskna 这只是测试code1code2 在当前行的未来 1 分钟内是否相同。如果是这样,则不要返回该行。至于另一个问题,您可以将最后一行更改为WHERE b.datetime Is Null And a.code1 = 3;【参考方案2】:

为了只选择 Code2 更改的行,您可以对 code2 进行分区:

select DateTime, Code1, Code2 from
(select *, rownumber() over (partition by code2 order by datetime) c from table1 ) t
where c = 1

这是最难的部分,我们可以通过加入 table2 来扩充它:

select t.DateTime, t.Code1, t.Code2, t2.Description from
(select *, rownumber() over (partition by code2 order by datetime) c from table1 ) t
left join table2 t2 on t.code2 = t2.code2
where t.c = 1

【讨论】:

谢谢,但我认为 sql-server-express 不支持您建议的功能【参考方案3】:

你也可以使用LEAD函数:

WITH CteLead AS(
    SELECT *,
        ldCode2 = LEAD(Code2) OVER(PARTITION BY code1 ORDER BY datetime)
    FROM Tbl1
)
SELECT
    datetime, code1, code2, t2.description
FROM CteLead cl
INNER JOIN Table2 t2
    ON t2.code2 = cl.code2
WHERE
    code2 <> ldCode2
    OR ldCode2 IS NULL
ORDER BY datetime;

【讨论】:

我在使用 sql-server-express 的lead、lag 和over 语句时没有取得多大成功,它们似乎不受支持? SQL Server 2012 supports the LEAD function. 但是我正在使用 sql-server-express 2012 并且向我报告该功能不受支持 - 或者可能是报告服务不支持该功能?【参考方案4】:

您似乎想要获取每组code1, code2 的每一行(基于日期时间)。

使用row_number解析函数分配数字,然后每组只取第一个:

select
  first_occurence.datetime,
  first_occurence.code1,
  first_occurence.code2,
  table2.description
from (
  select *
  from (
    select
      *,
      row_number() over (partition by code1, code2 order by datetime) as rn
    from table1
    ) table1
  where rn = 1
  ) first_occurence
  join table2 on first_occurence.code2 = table2.code2

再次查看您想要的输出后,上面的内容似乎还不够。我不确定逻辑,但我假设一天中的特定小时也会使该组(在您的示例中为 code1 = 6, code2 = 23)所以添加这个:

convert(varchar(10), datetime, 103) -- date without time
datepart(hour, datetime) -- only hour

PARTITION BY 子句:

select
  first_occurence.datetime,
  first_occurence.code1,
  first_occurence.code2,
  table2.description
from (
  select *
  from (
    select
      *,
      row_number() over (partition by code1, code2, convert(varchar(10),datetime,103), datepart(hour, datetime) order by datetime) as rn
    from table1
    ) table1
  where rn = 1
  ) first_occurence
  join table2 on first_occurence.code2 = table2.code2

【讨论】:

谢谢,但我认为 sql-server-express 不支持您建议的功能 检查这个:sql-server-performance.com/forum/threads/… 我已经运行了它报告数据库版本是 2012 的命令 - 我想知道它是否是不支持该功能的报告服务元素?

以上是关于选择字段中发生更改的行并将它们连接到另一个表的主要内容,如果未能解决你的问题,请参考以下文章

将不同文件中的多个excel表导入python并将它们连接到一个数据框中

解析 IP 并将其连接到 BigQuery 上具有一系列整数表示的另一个表

如何将表 id 字段连接到另一个表 id 字段? [关闭]

从一个连接到另一个表 SQL 的表中删除记录

MySQL 只加入最近的行?

比较两个字段并在另一个表中返回不匹配的存储过程