【问题标题】:SQL Server Data ConversionSQL Server 数据转换
【发布时间】:2011-01-07 21:40:29
【问题描述】:

我有以下格式的数据:

Date, FirstName, LastName, Unit
Jan1 , Bob      , Guy     , Home
Jan2 , Bob      , Guy     , Home
Jan3 , Bob      , Guy     , Home
Jan5 , Bob      , Guy     , Home
Jan6 , Bob      , Guy     , Home
Jan7 , Bob      , Guy     , Home
Jan8 , Bob      , Guy     , Offsite
Jan3 , Jane     , Doe     , Home
Jan4 , Jane     , Doe     , Home
Jan5 , Jane     , Doe     , Home
Jan9 , Bob      , Guy     , Home
Jan10, Bob      , Guy     , Home
Jan11, Bob      , Guy     , Home
Jan12, Jane     , Doe     , Home
Jan13, Jane     , Doe     , Home
Jan14, Jane     , Doe     , Home

我想要它的格式

DateStart, DateEnd, FirstName, LastName, Unit
Jan1     , Jan3   , Bob      , Guy     , Home
Jan5     , Jan7   , Bob      , Guy     , Home
Jan8     , Jan8   , Bob      , Guy     , Offsite
Jan3     , Jan5   , Jane     , Doe     , Home
Jan9     , Jan11  , Bob      , Guy     , Home
Jan12    , Jan14  , Jane     , Doe     , Home

编辑:更新数据。

如何轻松转换数据?

这是一次转换。

感谢 cmets/answers!

【问题讨论】:

  • 不完全清楚你想做什么;例如为什么 Jane Doe 的“DateEnd”= Jan3,而 Bob Guy 的为空?给定的名字/姓氏是否可以有两个以上的条目?如果是:您是否希望 DateStart = MIN(Date) 和 DateEnd = MAX(Date) 用于该名称??
  • 同意 marc_s... 我希望 Jane Doe 的 DateEnd 为空,就像您解释的 Bob 一样?否则你的意思是最后一行只有没有 DateEnd 吗?
  • @marc_s & @Matthew PK Bob 的 DateEnd 为空,因为他是最后一个进入该单元的人。给定的名字/姓氏可以有许多条目。 Jan4 之后可能有更多的“Home”条目,这将使第二个表上的 Jan4 条目的 DateEnd 为 Jan4(如果它是另一个人),或者如果 Bob 有多个条目,然后是另一个人,则成为另一个日期在他之后的家庭单元上有一个条目。每个单元最近的 DateStart 将有一个 null DateEnd
  • 如果两个人在Unit的最后日期有相同的日期怎么办?
  • 我放弃了我之前关于 null DateEnds 的声明。 :( 他们让事情变得更复杂了。

标签: sql sql-server tsql gaps-and-islands


【解决方案1】:

下面的 SQL 将产生所需的输出,但我不确定您是否最好将其编写为 C#

更新 这已更新为适当的差距和孤岛解决方案。这是基于 Alexander Kozak 的 MSDN 文章 Islands and Gaps in Sequential Numbers。这可以通过使用 CTE 来改进,并且 Exists 可以替换为 LEFT JOIN。

应该注意的是,这依赖于没有任何时间组件的日期。如果有时间组件,则必须预先将其删除。

输出

Date                    enddate                 FirstName LastName Unit
----------------------- ----------------------- --------- -------- -------
2011-01-01 00:00:00.000 2011-01-03 00:00:00.000 Bob       Guy      Home
2011-01-03 00:00:00.000 2011-01-05 00:00:00.000 Jane      Doe      Home
2011-01-05 00:00:00.000 2011-01-07 00:00:00.000 Bob       Guy      Home
2011-01-08 00:00:00.000 2011-01-08 00:00:00.000 Bob       Guy      Offsite
2011-01-09 00:00:00.000 2011-01-11 00:00:00.000 Bob       Guy      Home
2011-01-12 00:00:00.000 2011-01-14 00:00:00.000 Jane      Doe      Home

SQL 语句

SET NOCOUNT On

DECLARE @Test 
Table (
    Date datetime, 
    FirstName varchar(100),
     LastName varchar(100), 
     Unit  varchar(7))



INSERT INTO @Test VALUES ('01/01/2011'  , 'Bob', 'Guy',  'Home')
INSERT INTO @Test VALUES ('01/02/2011'  , 'Bob', 'Guy',  'Home')
INSERT INTO @Test VALUES ('01/03/2011'  , 'Bob', 'Guy',  'Home')
INSERT INTO @Test VALUES ('01/05/2011'  , 'Bob', 'Guy',  'Home')
INSERT INTO @Test VALUES ('01/06/2011'  , 'Bob', 'Guy',  'Home')
INSERT INTO @Test VALUES ('01/07/2011'  , 'Bob', 'Guy',  'Home')
INSERT INTO @Test VALUES ('01/08/2011'  , 'Bob', 'Guy',  'Offsite')
INSERT INTO @Test VALUES ('01/03/2011'  , 'Jane', 'Doe',  'Home')
INSERT INTO @Test VALUES ('01/04/2011'  , 'Jane', 'Doe',  'Home')
INSERT INTO @Test VALUES ('01/05/2011'  , 'Jane', 'Doe',  'Home')
INSERT INTO @Test VALUES ('01/09/2011'  , 'Bob', 'Guy',  'Home')
INSERT INTO @Test VALUES ('01/10/2011'  , 'Bob', 'Guy',  'Home')
INSERT INTO @Test VALUES ('01/11/2011'  , 'Bob', 'Guy',  'Home')
INSERT INTO @Test VALUES ('01/12/2011'  , 'Jane', 'Doe',  'Home')
INSERT INTO @Test VALUES ('01/13/2011'  , 'Jane', 'Doe',  'Home')
INSERT INTO @Test VALUES ('01/14/2011'  , 'Jane', 'Doe',  'Home')


SELECT 
    t1.Date,
    MIN(t2.Date) enddate, 
    t1.FirstName,
    t1.LastName,
    t1.Unit
 FROM

    (SELECT * 
    FROM
        @Test t1
    WHERE
       NOT EXISTS(SELECT * FROM @Test t2
                  WHERE
                      t1.firstName = t2.FirstName   
                      AND t1.LastName = t2.LastName
                      AND t1.Unit = t2.Unit
                        and t1.Date - t2.Date = 1)) 
        t1


      INNER JOIN (SELECT * FROM @Test t1

    WHERE
       NOT EXISTS(SELECT * FROM @Test t2
                  WHERE
                      t1.firstName = t2.FirstName   
                      AND t1.LastName = t2.LastName
                      AND t1.Unit = t2.Unit
                        and t2.Date - t1.Date = 1)) t2
      ON
        t1.firstName = t2.FirstName 
                      AND t1.LastName = t2.LastName
                      AND t1.Unit = t2.Unit
                      AND t1.Date <= t2.Date  
       GROUP BY
       t1.Date,
       t1.FirstName,
       t1.LastName,
       t1.Unit

【讨论】:

  • 太好了,我要把“Min(t2.date) todate”改成“ISNULL(Min(t2.date), t.Date) toDate”,我想我是在业务!非常感谢!
  • 嗯,当针对我的数据运行时,我得到了 2 天的时间表。我可能需要做更多的挖掘工作。
  • @Bill 随时为您的问题添加更多示例
  • @Conrad Frix 谢谢!我试图让我正在做的事情更清楚。
  • @Biff(很抱歉在我使用智能手机之前打电话给你 Bill,f 看起来像 l 的)是的,这可以做到。它的差距和岛屿问题。我会更新我的答案
【解决方案2】:

使用 Conrad 的测试数据和 Itzik Ben Gan 的方法!

;WITH base AS ( 
SELECT    FirstName, 
          LastName, 
          Unit,
          Date,
          DATEDIFF(DAY,0,Date) - 
                         DENSE_RANK() OVER (PARTITION BY FirstName, LastName, Unit 
                                            ORDER BY DATEDIFF(DAY,0,Date)) AS G
 FROM     @Test
 )
SELECT FirstName, LastName, Unit, MIN(Date) DateStart,MAX(Date) DateEnd
FROM base
GROUP BY G, FirstName, LastName, Unit

【讨论】:

  • +! @马丁。非常好。我正在寻找一种排名方法,但找不到。
猜你喜欢
  • 2012-06-26
  • 1970-01-01
  • 2015-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-14
  • 1970-01-01
相关资源
最近更新 更多