Группа SQL Server по запросу с использованием нескольких значений

Я новичок в Microsoft SQL Server и был разочарован запросом GROUP BY, который не будет делать то, что я хочу. Таблица следующая:

make    model   distancefrom    distanceto  driverid
toyota  yaris   358.2   368.2   401
toyota  yaris   368.2   378.7   103
toyota  yaris   378.7   382.2   103
toyota  yaris   382.2   392.2   103
toyota  yaris   392.2   403.6   103
toyota  yaris   403.6   414.3   103
toyota  yaris   414.3   419.4   103
toyota  yaris   419.4   430.2   103
toyota  yaris   430.2   439.2   401
toyota  yaris   439.2   446     401
toyota  yaris   446     457.2   401
toyota  yaris   457.2   460.1   401
toyota  yaris   460.1   468.6   401
toyota  yaris   468.6   480.3   401
toyota  yaris   480.3   486.2   103
toyota  yaris   486.2   490     103
toyota  yaris   490     501.1   103
toyota  yaris   501.1   512.5   103
toyota  yaris   512.5   523.1   103
toyota  yaris   523.1   532.6   401
toyota  yaris   532.6   542.7   401
toyota  yaris   542.7   551.1   401

Мне нужно найти начальное и конечное значение для каждого из драйверов. Обычный запрос GROUP BY с использованием MIN и MAX группирует все одинаковые идентификаторы драйверов вместе, но мне нужно хранить их отдельно. т.е. вывод должен выглядеть так:

make    model   distancefrom    distanceto  driverid
toyota  yaris   358.2   368.2   401
toyota  yaris   368.2   430.2   103
toyota  yaris   430.2   480.3   401
toyota  yaris   480.3   523.1   103
toyota  yaris   523.1   551.1   512

Любая помощь будет оценена по достоинству.


person Community    schedule 10.07.2009    source источник
comment
Не могли бы вы переформатировать это, пожалуйста? Попробуйте выбрать данные и использовать значок 0101, чтобы пометить их как код.   -  person Gary McGill    schedule 10.07.2009
comment
Вы хотите собрать цепи? Глядя на DriverId = 401, у вас есть две строки на выходе. с 358,2 до 368,2, а затем с 430,2 до 480,3. И причина того, что у вас есть две строки, связана с разрывом между 368,2 и 480,3 во входных данных. Это правильно?   -  person Shannon Severance    schedule 10.07.2009
comment
И какая версия MS SQL Server? В версиях 2005 и 2008 есть инструменты, облегчающие эту задачу, которых нет в версии 2000.   -  person Shannon Severance    schedule 10.07.2009
comment
Кроме того, на входе, который вы показываете, нет driverId = 512, а на выходе есть.   -  person Shannon Severance    schedule 10.07.2009


Ответы (4)


Вы явно хотите разделить поездки - результаты, которые, как вы говорите, вы хотите, например. драйвер 401 задействует первую строку, затем мин/макс пробегает второй набор строк для этого драйвера. Таким образом, похоже, что вам не хватает столбца «JourneyID» или подобного. Первая строка будет иметь одно значение JourneyID, второй набор строк будет иметь одинаковое значение JourneyID, но отличное от значения для первой строки.

Если у вас есть этот столбец, вы можете добавить его в предложение Group By.

person Vinay Sajip    schedule 10.07.2009

Мне кажется, вам нужно что-то вроде этого:

SELECT make, model, driverid, min(distancefrom), max(distancefrom), min(distanceto), max(distanceto)
FROM table
GROUP BY make, model, driverid

Это тот запрос, который вы выполняете?

person ttarchala    schedule 10.07.2009

SELECT  make, model, driverid
FROM    (
        SELECT  make, model, driverid,
                ROW_NUMBER() OVER (PARTITION BY make, model, driverid ORDER BY distancefrom) AS rns,
                ROW_NUMBER() OVER (PARTITION BY make, model, driverid ORDER BY distancefrom DESC) AS rne
        FROM    mytable
        ) q
WHERE   1 IN (rns, rne)

Если у вас есть индекс (make, model, driverid, distance), этот может быть более эффективным:

SELECT  m.make, m.model, m.driverid,
        (
        SELECT  TOP 1 distancefrom
        FROM     mytable mi
        WHERE    mi.make = m.make
                 AND mi.model = m.model
                 AND mi.driverid = m.driverid
        ORDER BY
                 distancefrom
        ),
        (
        SELECT  TOP 1 distancefrom
        FROM     mytable mi
        WHERE    mi.make = m.make
                 AND mi.model = m.model
                 AND mi.driverid = m.driverid
        ORDER BY
                 distancefrom DESC
        )
FROM    (
        SELECT  DISTINCT make, model, driverid
        FROM    mytable
        ) m
person Quassnoi    schedule 10.07.2009

Решение MS SQL 2005/2008. Не работает на MS SQL 2000.

create table #journeySegment (make varchar(100) not null
        , model varchar(100) not null
        , distanceFrom decimal(10,2) not null
        , distanceTo decimal(10, 2) not null
        , driverId int not null -- References blah
        , CONSTRAINT data_U unique (make, model, driverId, distanceFrom)
        , CONSTRAINT data_FromTo_CHK check (distanceFrom <= distanceTo))


insert into #journeySegment values ('toyota', 'yaris', 358.2, 368.2, 401)
insert into #journeySegment values ('toyota', 'yaris', 368.2, 378.7, 103)
insert into #journeySegment values ('toyota', 'yaris', 378.7, 382.2, 103)
insert into #journeySegment values ('toyota', 'yaris', 382.2, 392.2, 103)
insert into #journeySegment values ('toyota', 'yaris', 392.2, 403.6, 103)
insert into #journeySegment values ('toyota', 'yaris', 403.6, 414.3, 103)
insert into #journeySegment values ('toyota', 'yaris', 414.3, 419.4, 103)
insert into #journeySegment values ('toyota', 'yaris', 419.4, 430.2, 103)
insert into #journeySegment values ('toyota', 'yaris', 430.2, 439.2, 401)
insert into #journeySegment values ('toyota', 'yaris', 439.2, 446, 401)
insert into #journeySegment values ('toyota', 'yaris', 446, 457.2, 401)
insert into #journeySegment values ('toyota', 'yaris', 457.2, 460.1, 401)
insert into #journeySegment values ('toyota', 'yaris', 460.1, 468.6, 401)
insert into #journeySegment values ('toyota', 'yaris', 468.6, 480.3, 401)
insert into #journeySegment values ('toyota', 'yaris', 480.3, 486.2, 103)
insert into #journeySegment values ('toyota', 'yaris', 486.2, 490, 103)
insert into #journeySegment values ('toyota', 'yaris', 490, 501.1, 103)
insert into #journeySegment values ('toyota', 'yaris', 501.1, 512.5, 103)
insert into #journeySegment values ('toyota', 'yaris', 512.5, 523.1, 103)
insert into #journeySegment values ('toyota', 'yaris', 523.1, 532.6, 513)
insert into #journeySegment values ('toyota', 'yaris', 532.6, 542.7, 513)
insert into #journeySegment values ('toyota', 'yaris', 542.7, 551.1, 513)

-- ASSUMPTIONS:
-- journeySegments do not overlap.
-- distanceFrom and distanceTo are exact numeric types.

; with potentialJourney (make, model, journeyFrom, journeyTo, driverId, level) as
    (-- Find the starting segment for each journey.
    select make,
        model, 
        distanceFrom, 
        distanceTo,
        driverId,
        0
    from #journeySegment A
    where not exists
        (select *
        from #journeySegment B
        where B.make = A.Make
        and B.model = A.model
        and B.driverId = A.driverId 
        and B.DistanceTo = A.DistanceFrom)
    union all
    -- add on next segment.
    select PJ.make
        , PJ.model
        , PJ.journeyFrom
        , nextJS.distanceTo
        , PJ.driverId
        , PJ.level + 1
    from potentialJourney PJ
    inner join #journeySegment nextJS
        on nextJS.make = PJ.Make
        and nextJS.model = PJ.Model
        and nextJs.driverId = PJ.driverId
        and nextJs.distanceFrom = PJ.journeyTo)
select M.make
    , M.Model
    , M.journeyFrom
    , M.journeyTo
    , M.driverId
from potentialJourney M
-- Eliminate the partial solutions
where not exists
    (select *
    from potentialJourney S
    where S.make = M.make
    and S.model = M.model
    and S.journeyFrom = M.journeyFrom
    and S.driverId = M.driverId
    and S.level > M.level)
order by journeyFrom
person Shannon Severance    schedule 10.07.2009