SQL - Как объединить строки - PullRequest
4 голосов
/ 21 марта 2019

У меня есть следующая таблица, которая смотрит на звонки и посещаемость. Я получил это, используя union all в таблицах «звонки» и «посещаемость», а затем использовал номер строки в идентификаторе и упорядочил по датам.

Table1:

     Type    | ID | Call/AttendanceDate | RowNum 
 ------------|----|---------------------|-------- 
  Attendance | 12 | 2018-09-16 10:11:00 |     82 
  Call       | 12 | 2018-09-18 14:11:47 |     83 
  Call       | 12 | 2018-10-02 17:26:13 |     84 
  Call       | 12 | 2018-10-05 14:58:31 |     85 
  Attendance | 12 | 2018-10-13 01:41:00 |     86 
  Call       | 12 | 2018-10-13 02:39:12 |     87 
  Call       | 12 | 2018-10-13 04:31:22 |     88 
  Attendance | 12 | 2018-10-13 14:29:00 |     89 
  Call       | 12 | 2018-10-13 14:59:19 |     90 
  Attendance | 12 | 2018-10-15 15:50:00 |     91 

Код, который я использовал для этого:

WITH CTE1 AS
(
SELECT 'Call' as [Type], ID, CallDate AS Date1 
FROM CallsTable     

UNION ALL

SELECT 'Attendance' as [Type], ID, AttendanceDate AS Date2
FROM AttendanceTable] 
)

,CTE2 AS
(
SELECT [Type], Date1, ID, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Date1 ASC) AS RowNum
FROM CTE1
)

--------------------------------OUTPUT--------------------------------

SELECT a.[Type], a.ID, a.Date1, a.RowNum
FROM CTE2 a
JOIN CTE2 b
    ON a.ID= b.ID
    AND a.RowNum = b.RowNum + 1
WHERE a.ID = '12'
ORDER BY ID, RowNum

Я хочу изменить это так, чтобы он выглядел так, как показано ниже, чтобы всякий раз, когда посещаемость следовала за вызовом, она была в одной строке.

Table2:

  Type | ID |     CallDate     | RowNum |    Type    |  AttendanceDate  | RowNum 
 ------|----|------------------|--------|------------|------------------|-------- 
  NULL | 12 | NULL             | NULL   | Attendance | 16/09/2018 10:11 | 82     
  Call | 12 | 18/09/2018 14:11 | 83     | NULL       | NULL             | NULL   
  Call | 12 | 02/10/2018 17:26 | 84     | NULL       | NULL             | NULL   
  Call | 12 | 05/10/2018 14:58 | 85     | Attendance | 13/10/2018 01:41 | 86     
  Call | 12 | 13/10/2018 02:39 | 87     | NULL       | NULL             | NULL   
  Call | 12 | 13/10/2018 04:31 | 88     | Attendance | 13/10/2018 14:29 | 89     
  Call | 12 | 13/10/2018 14:59 | 90     | Attendance | 15/10/2018 15:50 | 91  

Возможно ли это? Какой код я могу использовать?

Ответы [ 3 ]

3 голосов
/ 21 марта 2019

Использовать FULL JOIN

SELECT 
*
FROM 
(SELECT * FROM CTE2 WHERE Type = 'CALL') A
FULL JOIN
(SELECT * FROM CTE2 WHERE Type = 'ATTENDANCE') B
ON A.ID = B.ID AND A.RowNum = B.RowNum - 1
0 голосов
/ 21 марта 2019

Не так элегантно, но у меня работает, табличная функция

alter FUNCTION GetCallActivity()
RETURNS @activityTable TABLE 
(
  call_type     varchar(16),
  call_id       int, 
  call_date     datetime, 
  call_rownum   int,
  atnd_type     varchar(16),
  atnd_id       int, 
  atnd_date     datetime, 
  atnd_rownum   int
)
AS
BEGIN
    -- initialize the return table
    insert into @activityTable
    (call_type, call_id, call_date, call_rownum )
    select a.type, a.id, a.activity_date, a.rownum
    from   stack_calls  a
    where  a.type = 'Call'
    order  by a.activity_date;

    -- match to the attendence recs to the call recs
    update @activityTable
    set    atnd_type     = b.type,
           atnd_id       = b.id,
           atnd_date     = b.activity_date,
           atnd_rownum   = b.rownum
    from   stack_calls     b
    join   @activityTable  a
      on   b.rownum = a.call_rownum + 1
    where  b.type = 'Attendance';      

    -- deal with the edge cases
    insert into @activityTable
    ( atnd_type, atnd_id, atnd_date, atnd_rownum )
    select x.type, 
           x.id, 
           x.activity_date,
           x.rownum
    from 
    (
        select a.type, 
               a.id, 
               a.activity_date,
               a.rownum,
               lag(a.type, 1) over (order by a.activity_date) as prev_type 
        from   stack_calls  a
        where  a.type = 'Attendance'
    ) x
    where x.prev_type is null

    RETURN 
END
GO
0 голосов
/ 21 марта 2019

Вы можете использовать APPLY:

SELECT C.[Type], C.ID, C.CallDate, C.RowNum,
       (CASE WHEN C2.RowNum - C.RowNum = 1 THEN C2.[TYPE] end) [TYPE],
       (CASE WHEN C2.RowNum - C.RowNum = 1 THEN C2.CallDate end) AttendanceDate,    
       (CASE WHEN C2.RowNum - C.RowNum = 1 THEN C2.RowNum end) RowNum    
FROM CTE2 C OUTER APPLY
     (SELECT TOP (1) C2.*
      FROM CTE2 C2
      WHERE C2.ID = C.ID AND C2.[Type] = 'Attendance' AND C2.RowNum > C.RowNum
      ORDER BY C2.RowNum
     ) C2
WHERE C.ID = 12 AND C.[Type] = 'Call';
...