代码之家  ›  专栏  ›  技术社区  ›  Mar1009

如何根据需要从SQL Server中检索数据?

  •  1
  • Mar1009  · 技术社区  · 6 年前

    我有一张这样的桌子:

      CustName    Country    RecordedTime
     ---------------------------------------------
      Alex        Australia  2018-Jun-01 08:00 AM
      Alex        China      2018-Jun-01 10:00 AM
      Alex        Japan      2018-Jun-01 11:00 AM
      John        Australia  2018-Jun-01 08:00 AM
      John        China      2018-Jun-02 08:00 AM
      Bob         Australia  2018-Jun-02 09:00 AM
      Bob         Brazil     2018-Jun-03 09:50 AM
    

    如果该记录在系统中是全新的,则它应在给定日期的“审核”和“历史记录”字段(结果集中的两个附加字段)中显示“添加”和“新建”。

    如果当天编辑了两次记录,则该记录应在审核字段中分别显示两个“添加”和“更改”条目,在给定日期的历史状态字段中分别显示“在”和“当前”条目。

    例如,我的结果应该是这样出现的;

    当我通过输入日期为2018-Jun-01时,输出应如下:

       CustName    Country    RecordedTime           Audit    History
      ----------------------------------------------------------------
       Alex        Australia  2018-Jun-01 08:00 AM   ADD      NEW
       Alex        China      2018-Jun-01 10:00 AM   CHANGE   BEFORE
       Alex        Japan      2018-Jun-01 11:00 AM   CHANGE   CURRENT
       John        Australia  2018-Jun-01 08:00 AM   ADD      NEW
    

    当我通过输入日期为2018-Jun-02时,输出应如下:

       CustName    Country    RecordedTime           Audit    History
      -----------------------------------------------------------------
       John        China      2018-Jun-02 08:00 AM   CHANGE   CURRENT
       Bob         Australia  2018-Jun-02 09:00 AM   ADD      NEW
    

    当我通过输入日期为2018-Jun-02时,输出应如下:

       CustName    Country    RecordedTime           Audit    History
      ----------------------------------------------------------------
       Bob         Brazil     2018-Jun-03 09:50 AM   CHANGE   CURRENT
    

    我尝试了很多方法,但我仍然错过了一些实现这一点的场景。有人能解释一下吗?

    3 回复  |  直到 6 年前
        1
  •  1
  •   DhruvJoshi    6 年前

    一种方法是通过下面这样的CTE,我们有row_number()函数来双向跟踪序列。

    参见 live demo

    ; with cte as 
    (
    select *, rn= row_number() over(partition by CustName order by RecordedTime),
    rn2=row_number() over(partition by CustName order by RecordedTime desc)
    from records
        )
    , cte2 as
    (
    select *, audit='New', History='Change' from cte where rn=1
        union 
    select *, audit='Change', History='Current' from cte where rn2=1 and rn<>1
        union
    select *, audit='Change', History='before' from cte where rn>1 and rn2<>1
    )
    
    select 
        CustName,
        Country,
        RecordedTime,
        audit,
        History
    from cte2
    order by  CustName,RecordedTime
    
        2
  •  2
  •   D-Shih    6 年前

    我只会用 case 表达。

    select t.*,
           (case when seqnum = 1 then 'ADD' else 'CHANGE' end) as audit,
           (case when seqnum = 1 then 'NEW'
                 when seqnum_day = 1 then 'CURRENT'
                 else 'BEFORE'
            end) as history
    from (select t.*,
                 row_number() over (partition by custname order by recordedtime) as seqnum,
                 row_number() over (partition by custname, cast(recordedtime as date) order by recordedtime desc) as seqnum_day
          from t
         ) t;
    

    sqlfiddle: http://sqlfiddle.com/#!18/43c08/27

        3
  •  1
  •   D-Shih    6 年前

    你可以试试。

    CASE WHEN RANK 具有 Windows函数

    ;WITH CTE (CustName,Country,RecordedTime,rn) AS(
      SELECT *,RANK() OVER(PARTITION BY CustName ORDER BY RecordedTime) rn
      FROM T
    )
    SELECT t.*,
           (CASE WHEN rn = 1 then 'ADD' ELSE 'CHANGE' END) 'Audit',
           (CASE 
              WHEN rn = 1  then 'NEW'
              WHEN t2.mRn = rn then 'CURRENT' 
           ELSE 'BEFORE' END) 'History'
    FROM CTE t LEFT JOIN  (
      SELECT MAX(rn) mRn,CustName  FROM CTE GROUP BY CustName
    ) t2 on t2.mRn = t.rn and t2.CustName = t.CustName
    WHERE CONVERT(char(10), RecordedTime,126) = '2018-06-02'
    

    sqlfiddle: http://sqlfiddle.com/#!18/43c08/26