重用行中的最后一个值并在下一个SQL服务器上创建第一个值

时间:2017-06-02 06:43:45

标签: sql-server sql-server-2012

所以,我有这个SQL表:

Traveller      checkin       dateTime
5566           Madrid        2017-01-01 01:00:00.00
5566           Barcelona     2017-01-02 03:00:00.00
5566           Berlin        2017-01-03 02:00:00.00
5566           Paris         2017-01-06 05:00:00.00
5566           London        2017-01-07 06:00:00.00
5566           Madrid        2017-01-08 02:00:00.00
4422           Moscow        2017-01-03 08:00:00.00
4422           Madrid        2017-01-04 07:00:00.00
4422           Barcelona     2017-01-05 03:00:00.00
8833           Barcelona     2017-02-01 08:00:00.00
8833           Berlin        2017-02-02 04:00:00.00
8833           London        2017-02-03 01:00:00.00
8833           Berlin        2017-02-03 22:00:00.00
9966           Paris         2017-02-03 04:00:00.00
9966           London        2017-02-04 06:00:00.00
9966           Berlin        2017-02-05 01:00:00.00
...            ...           ...

是否有可能以某种方式将这些命令分配到一个从一个表到另一个表,使用除了第一个签到之外的所有来自目的地。像这样:

Traveller      From       To
5566           Madrid     Barcelona
5566           Barcelona  Berlin
5566           Berlin     Paris
5566           Paris      London
5566           London     Madrid
4422           Moscow     Madrid
4422           Madrid     Barcelona
8833           Barcelona  Berlin
8833           Berlin     London
8833           London     Berlin
...            ...        ...

我知道SQL的基础知识,但我还在学习,所以如果有人能够想到一种方法可以做到(或不做),请帮助我理解它是如何工作的。

非常感谢!

3 个答案:

答案 0 :(得分:2)

您可以使用ROW_NUMBER()为CTE中每位旅行者的签到分配序号,然后将CTE加入自身以创建结果:

declare @t table (Traveller int not null, checkin varchar(19) not null,
                  TimeStamp datetime2 not null)
insert into @t (Traveller,checkin,TimeStamp) values
(5566,'Madrid',   '2017-06-02T07:56:01'),
(5566,'Barcelona','2017-06-02T07:56:02'),
(5566,'Berlin',   '2017-06-02T07:56:03'),
(5566,'Paris',    '2017-06-02T07:56:04'),
(5566,'London',   '2017-06-02T07:56:05'),
(5566,'Madrid',   '2017-06-02T07:56:06'),
(4422,'Moscow',   '2017-06-02T07:56:07'),
(4422,'Madrid',   '2017-06-02T07:56:08'),
(4422,'Barcelona','2017-06-02T07:56:09'),
(8833,'Barcelona','2017-06-02T07:56:10'),
(8833,'Berlin',   '2017-06-02T07:56:11'),
(8833,'London',   '2017-06-02T07:56:12'),
(8833,'Berlin',   '2017-06-02T07:56:13'),
(9966,'Paris',    '2017-06-02T07:56:14'),
(9966,'London',   '2017-06-02T07:56:15'),
(9966,'Berlin',   '2017-06-02T07:56:16')

;With Numbered as (
    select
        *,
        ROW_NUMBER() OVER (PARTITION BY Traveller ORDER by TimeStamp) as rn
    from @t
)
select
    n1.Traveller,n1.checkin,n2.checkin
from
    Numbered n1
        inner join
    Numbered n2
        on
            n1.Traveller = n2.Traveller and
            n1.rn = n2.rn - 1
order by
    n1.Traveller,n1.rn

结果:

Traveller   checkin             checkin
----------- ------------------- -------------------
4422        Moscow              Madrid
4422        Madrid              Barcelona
5566        Madrid              Barcelona
5566        Barcelona           Berlin
5566        Berlin              Paris
5566        Paris               London
5566        London              Madrid
8833        Barcelona           Berlin
8833        Berlin              London
8833        London              Berlin
9966        Paris               London
9966        London              Berlin

答案 1 :(得分:0)

您可以使用row_number窗口功能。它是Sql Server 2008处理此问题的方法。这是:

;with raw_data (id, city, arrival) as (
    select 5566, 'Madrid', '2017-01-01 01:00:00.00' union all
    select 5566, 'Barcelona', '2017-01-02 03:00:00.00' union all
    select 5566, 'Berlin', '2017-01-03 02:00:00.00' union all
    select 5566, 'Paris', '2017-01-06 05:00:00.00' union all
    select 5566, 'London', '2017-01-07 06:00:00.00' union all
    select 5566, 'Madrid', '2017-01-08 02:00:00.00' union all
    select 4422, 'Moscow', '2017-01-03 08:00:00.00' union all
    select 4422, 'Madrid', '2017-01-04 07:00:00.00' union all
    select 4422, 'Barcelona', '2017-01-05 03:00:00.00' union all
    select 8833, 'Barcelona', '2017-02-01 08:00:00.00' union all
    select 8833, 'Berlin', '2017-02-02 04:00:00.00' union all
    select 8833, 'London', '2017-02-03 01:00:00.00' union all
    select 8833, 'Berlin', '2017-02-03 22:00:00.00' union all
    select 9966, 'Paris', '2017-02-03 04:00:00.00' union all
    select 9966, 'London', '2017-02-04 06:00:00.00' union all
    select 9966, 'Berlin', '2017-02-05 01:00:00.00'
)
, arrivals as (
    select
        id, city, arrival,
        row_number() over (partition by id order by arrival) as rn
    from raw_data
)
, flies as (
    select
        fr.id,
        fr.city as [from],
        fr.arrival as [departure],
        [to].city as [to],
        [to].arrival as [arrival]
    from arrivals fr
    join arrivals [to] on
        fr.id = [to].id
        and [to].rn = fr.rn + 1
)
select
    *
from flies

SQL Server 2012及更高版本

但是如果你有Sql Server 2012及更高版本,你可以使用lag函数来解决它,它可以访问当前的某些前一行。

E.g。 lag(colX, N, <default>)表示您获得列colX的第N个值或值(如果没有)。这只是我们需要的!严格地说是前一个:

;with raw_data (id, city, arrival) as (
    -- omitted for the sake of shortness :)
)
, flies as (
    select
        id,
        -- here it is!!! prev city and arrival
        lag(city, 1, null) over (partition by id order by arrival) as [from],
        lag(arrival, 1, null) over (partition by id order by arrival) as [departure],
        city as [to],
        arrival as [arrival]
    from raw_data
)
select
    *
from flies
where
    -- and here we take only rows from where we're 'departured'
    [from] is not null

答案 2 :(得分:0)

您可以使用LEAD function返回下一行的值,例如

export default class React.Component {
  constructor(props) {
    super(props);
  }

  renderNames() {
    let empty = ``
    let names = this.props.names;
    let namesLength = names.length;
    for (var i = 0; i < namesLength; i++) {
      empty = empty + `-` + ` ${names[i]}`
    }

    return empty;
  }

  render() {
    return(
      <div>
        {this.renderNames()}
      </div>
    )
  }
}

这将返回最后一段的NULL目的地。要删除它,您可以使用CTE过滤数据:

select 
    Traveller,
    checkin,
    LEAD(checkin,1) OVER(PARTITION by traveller order by timestamp) as destination
from @t t

测试所有这些:

with checkins as (
    select 
        Traveller,
        checkin,LEAD(checkin,1) OVER(PARTITION by traveller order by timestamp) as destination
    from @t t)
select * from checkins 
where destination is not null

将返回:

declare @t table (Traveller int not null, checkin varchar(19) not null, TimeStamp datetime2 not null);

insert into @t (Traveller,checkin,TimeStamp) values
(5566,'Madrid',   '2017-06-02T07:56:01'),
(5566,'Barcelona','2017-06-02T07:56:02'),
(5566,'Berlin',   '2017-06-02T07:56:03'),
(5566,'Paris',    '2017-06-02T07:56:04'),
(5566,'London',   '2017-06-02T07:56:05'),
(5566,'Madrid',   '2017-06-02T07:56:06'),
(4422,'Moscow',   '2017-06-02T07:56:07'),
(4422,'Madrid',   '2017-06-02T07:56:08'),
(4422,'Barcelona','2017-06-02T07:56:09'),
(8833,'Barcelona','2017-06-02T07:56:10'),
(8833,'Berlin',   '2017-06-02T07:56:11'),
(8833,'London',   '2017-06-02T07:56:12'),
(8833,'Berlin',   '2017-06-02T07:56:13'),
(9966,'Paris',    '2017-06-02T07:56:14'),
(9966,'London',   '2017-06-02T07:56:15'),
(9966,'Berlin',   '2017-06-02T07:56:16');



with checkins as (
    select 
        Traveller,
        checkin,LEAD(checkin,1) OVER(PARTITION by traveller order by timestamp) as destination
    from @t t)
select * from checkins 
where destination is not null