Как получить первое значение из первой строки и последнее значение из последней строки в SQL Server - PullRequest
0 голосов
/ 04 октября 2018

У меня есть таблица в SQL Server, как показано ниже

+---+-------------+-------------+-------------+
|Id | FromCity    | ToCity      |  RequestId  | 
+---+-------------+-------------+-------------+
| 1 | Mysore      | Atlanta     | 12          |
+---+-------------+-------------+-------------+
| 2 | Atlanta     | Singapore   | 12          |
+---+-------------+-------------+-------------+
| 3 | Singapore   | Pakistan    | 12          |
+---+-------------+-------------+-------------+
| 4 | Pakistan    | Myscot      | 12          |
+---+-------------+-------------+-------------+
| 5 | Rome        | Singapore   | 13          |
+---+-------------+-------------+-------------+

Здесь я пытаюсь получить значение в виде городов От и До (данные в оба конца) ( т. Е. Майсур -> Myscot дляRequestId = 12 ).Как получить это значение?

Когда я передаю RequestId = 12, я должен получить значение как Майсур -> Майскот

Я пробовал, как показано ниже:

SELECT  MIN(FromCity) [From],
        MAX(ToCity) [To]
FROM    MyTable
WHERE   RequestId = 12

Но я получаю Майсур -> Сингапур (на основе строк MIN и MAX).

Ответы [ 7 ]

0 голосов
/ 04 октября 2018

может быть, это то, что вам нужно

DECLARE 
    @t TABLE (
        ID INT
    ,   FromCity VARCHAR(250)
    ,   ToCity   VARCHAR(250)
    ,   RequestId   INT 
    )

INSERT INTO @t VALUES 
 (1,'Mysore','Atlanta',12)
,(2,'Atlanta','Singapore',12)
,(3,'Singapore','Pakistan',12)
,(4,'Pakistan','Myscot',12)
,(5,'Rome','Singapore',13)


SELECT DISTINCT 
    ISNULL(FromCity, ISNULL(NextCity, PreCity) ) FromCity
,   ISNULL(ToCity, ISNULL(NextCity2, PreCity2) ) FromCity
FROM (
SELECT 
    CASE WHEN RN = 1 THEN FromCity END FromCity
,   CASE WHEN RN = CNT THEN ToCity END  ToCity
,   LEAD(CASE WHEN RN = 1 THEN FromCity END)  OVER(PARTITION BY RequestId ORDER BY ID) NextCity
,   LEAD(CASE WHEN RN = CNT THEN ToCity END)  OVER(PARTITION BY RequestId ORDER BY ID) NextCity2
,   LAG(CASE WHEN RN = 1 THEN FromCity END)  OVER(PARTITION BY RequestId ORDER BY ID) PreCity
,   LAG(CASE WHEN RN = CNT THEN ToCity END)  OVER(PARTITION BY RequestId ORDER BY ID) PreCity2
FROM (
SELECT 
*,  ROW_NUMBER() OVER(PARTITION BY RequestId ORDER BY ID) RN
,   COUNT(ToCity) OVER(PARTITION BY RequestId) CNT
FROM @t
) D
WHERE 
    RN = 1 OR RN = CNT 
) C 
0 голосов
/ 04 октября 2018

попробуйте этот код

SELECT MIN (Id) [From], MAX (Id) [To] FROM MyTable WHERE RequestId = 12

0 голосов
/ 04 октября 2018

Рекурсивная версия, не зависящая от порядка Id s.Идея состоит в том, чтобы построить самую большую цепочку путешествий, соединенных между собой городами.

WITH cte1 AS (
-- start with all trips as 1 hop chain
  SELECT [FromCity], [ToCity], 1 AS HOP 
  FROM Mytable 
  WHERE REQUESTID = 12
UNION ALL
  -- recursively add one hop if we find a trip ending in start city of the chain
  SELECT T.[FromCity], cte1.[ToCity], cte1.HOP + 1 
  FROM cte1
  JOIN Mytable t 
    ON t.[ToCity] = cte1.[FromCity]
  WHERE t.REQUESTID = 12
)
, cte2 AS (
  -- order by number of hops 
  SELECT [FromCity], [ToCity], ROW_NUMBER() OVER (ORDER BY HOP DESC) AS N
  FROM cte1
)
-- choose the chain with the more hops
SELECT [FromCity], [ToCity] 
FROM cte2 
WHERE N = 1
0 голосов
/ 04 октября 2018

Проверьте это:

SELECT  M.FromCity [From],
        M2.ToCity [To]
FROM    #MyTable M
Inner join (select Min(ID) min ,Max(ID) max  from #MyTable M2  WHERE  M2.RequestId = 12 )
A on A.Min =ID
Inner join #MyTable M2 on M2.ID=A.Max 

Выход:

enter image description here

0 голосов
/ 04 октября 2018
SELECT  RequestId, 
        f.FromCity [From],
        t.ToCity [To]
FROM    MyTable t
    CROSS APPLY (
        SELECT TOP (1) FromCity
        FROM MyTable
        WHERE RequestId = t.RequestId
        ORDER BY Id ASC
    ) f
    CROSS APPLY (
        SELECT TOP (1) ToCity
        FROM MyTable
        WHERE RequestId = t.RequestId
        ORDER BY Id DESC
    ) t
WHERE   RequestId = 12
0 голосов
/ 04 октября 2018

Если идентификатор Id в основной таблице используется для описания порядка командировок, то будет работать что-то подобное:

SELECT startLocation.FromCity [From], endLocation.ToCity AS [To]
FROM (
SELECT MIN(Id) AS StartLocationId, MAX(Id) AS EndLocationId
FROM    MyTable
WHERE   RequestId = 12 
) AS a
INNER JOIN MyTable AS startLocation ON a.StartLocationId = startLocation.Id
INNER JOIN MyTable AS endLocation ON a.EndLocationId = endLocation.Id

Это пример решения для ситуации, когда идентификаторы являются просто идентификаторами и не соответствуют порядку командировок.:

declare @tbl as table
    ([Id] int, [FromCity] varchar(9), [ToCity] varchar(9), [Date Created] datetime, [RequestId] int)
;

INSERT INTO @tbl
    ([Id], [FromCity], [ToCity], [Date Created], [RequestId])
VALUES
    (19, 'Mysore', 'Atlanta', '2018-10-05 15:10:00', 12),
    (22, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 12),
    (1, 'Singapore', 'Pakistan', '2018-10-07 15:10:00', 12),
    (4, 'Pakistan', 'Myscot', '2018-10-07 15:10:00', 12),
    (5, 'UK', 'Atlanta', '2018-10-06 15:10:00', 13),
    (0, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 13),
    (-1, 'Singapore', 'Italy', '2018-10-23 15:10:00', 13)
;

select * from @tbl

declare @Id int = 12
declare @FromStart nvarchar(255), @ToStart nvarchar(255) 
declare @StartResult nvarchar(255), @ToResult nvarchar(255) 
declare @StartResultFound bit = 0, @ToResultFound bit = 0

-- select random starting point
select @FromStart = [FromCity], @ToStart = [ToCity] from @tbl where [RequestId] = @Id
ORDER BY NEWID()

select @FromStart, @ToStart

while (@StartResultFound = 0)
begin
    if exists (select top 1 1 from @tbl where [RequestId] = @Id and [ToCity] = @FromStart)
    begin
        select top 1 @FromStart = [FromCity] from  @tbl where [RequestId] = @Id and [ToCity] = @FromStart
    end
    else
    begin
        set @StartResultFound = 1
        set @StartResult = @FromStart
    end
end

while (@ToResultFound = 0)
begin
    if exists (select top 1 1 from @tbl where [RequestId] = @Id and [FromCity] = @ToStart)
    begin
        select top 1 @ToStart = [ToCity] from  @tbl where [RequestId] = @Id and [FromCity] = @ToStart
    end
    else
    begin
        set @ToResultFound = 1
        set @ToResult = @ToStart
    end
end

select @StartResult, @ToResult
0 голосов
/ 04 октября 2018

Единственная логика, которую я вижу, это использовать Id из вашей таблицы и сделать что-то подобное.Используя CTE, вы найдете идентификаторы MIN и MAX для каждого запроса, то есть из города в город.И после этого вы присоединяете свою таблицу к CTE, чтобы найти фактические значения.

declare @tbl as table
    ([Id] int, [FromCity] varchar(9), [ToCity] varchar(9), [Date Created] datetime, [RequestId] int)
;

INSERT INTO @tbl
    ([Id], [FromCity], [ToCity], [Date Created], [RequestId])
VALUES
    (1, 'Mysore', 'Atlanta', '2018-10-05 15:10:00', 12),
    (2, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 12),
    (3, 'Singapore', 'Pakistan', '2018-10-07 15:10:00', 12),
    (4, 'Pakistan', 'Myscot', '2018-10-07 15:10:00', 12),
    (5, 'UK', 'Atlanta', '2018-10-06 15:10:00', 13),
    (6, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 13),
    (7, 'Singapore', 'Italy', '2018-10-23 15:10:00', 13);


;with cte as (
    select
        MIN(Id) as [start]
        ,MAX(Id) as [end]
        ,RequestId
    from @tbl
    group by requestID
)

select
    t1.FromCity
    ,t1.[Date Created]
    ,t2.ToCity
    ,t2.[Date Created]
from cte 
inner join @tbl t1
    on t1.Id = cte.[start]
    and t1.RequestId = cte.RequestId
inner join @tbl t2
    on t2.Id = cte.[end]
    and t2.RequestId = cte.RequestId

Обновление: на основе комментария @Panagiotis Kanavos вы можете упростить запрос следующим образом

;with cte as (
    select
        MIN(Id) as [start]
        ,MAX(Id) as [end]
    from @tbl
    where RequestId = 12  ---> here you can use a variable containing the requestID
)

select
    t1.FromCity
    --,t1.[Date Created]
    ,t2.ToCity
    --,t2.[Date Created]
from cte 
inner join @tbl t1
    on t1.Id = cte.[start]
inner join @tbl t2
    on t2.Id = cte.[end]
...