【问题标题】: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

问候,马克

【问题讨论】:

    标签: sql-server sql-server-2012 sql-server-express


    【解决方案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-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 不支持您建议的功能
    • 我已经运行了它报告数据库版本是 2012 的命令 - 我想知道它是否是不支持该功能的报告服务元素?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-19
    • 1970-01-01
    • 1970-01-01
    • 2014-01-21
    • 1970-01-01
    • 2014-07-04
    • 1970-01-01
    相关资源
    最近更新 更多