如何按特定顺序选择(几乎)唯一值

时间:2015-05-01 07:58:59

标签: sql distinct

在旅行中,按照特定顺序有几个停靠点(停止=加载或交付一个或多个订单的地址)。 例如:

Trip A
Trip_order   Action   Place          Ordernumber
10           Load     Paris          394798
20           Load     Milan          657748
30           UnLoad   Athens         657748
40           Unload   Thessaloniki   394798
50           Load     Thessaloniki   10142
60           Load     Thessaloniki   6577
70           Unload   Athens         6577
80           Unload   Athens         10412
90           Load     Thessaloniki   975147
100          Unload   Paris          975147

我希望按行程顺序查看具体的停靠点:

Load Paris
Load Milan
Unload Athens
Unload Thessaloniki
Load Thessaloniki
Unload Athens
Load Thessaloniki
Unload Paris

我确实看过This,但如果我这样做,我只能卸载雅典,卸载塞萨洛尼基并加载塞萨洛尼基一次。

我该如何解决这个问题?

编辑:11:11(UTC +01:00) 更具体地说:这些是提供此信息的表格:

Trips
Trip_ID
100001  
100002
100003
....

Actions
Trip_ID  Action MatNr RoOr RoVlg    OrderID
100001   1      10      10     1     394798
100001   1      10      20     1     657748
100001   1      10      30     1     657748
100001   1      10      40     1     394798
100001   1      10      50     1      10142
100001   1      10      60     1       6577
100001   1      10      70     1       6577
100001   1      10      80     1      10412
100001   1      10      90     1     975147
100001   1      10     100     1     975147

(动作:1 =加载,4 =卸载) MatNr,RoOr和RoVlg的组合是Trip的顺序。

Orders
OrderID LoadingPlace UnloadingPlace
6577    Thessaloniki Athens
10142   Thessaloniki Athens
394798  Paris        Thessaloniki
657748  Milan        Athens
975147  Thessaloniki Paris

6 个答案:

答案 0 :(得分:5)

试试这个。没有变数,没什么特别的花哨:

select a1.action, a1.place
  from trip_a a1
    left join trip_a a2
      on a2.trip_order = 
        (select min(trip_order) 
          from trip_a a3 
          where trip_order > a1.trip_order)
  where a1.action != a2.action or a1.place != a2.place or a2.place is null

在这里演示:http://sqlfiddle.com/#!9/4b6dc/13

希望它适用于你正在使用的任何sql,它应该是,只要支持子查询。

如果没有更高的trip_id,Tt只会找到下一个最高null,并加入其中,或加入trip_order。然后,它只会选择placeaction或两者不同的行,或者联接表中没有位置的行(a2.place is null)。

在标准完全更改后进行修改

如果您希望获得完全由基表构建的相同结果,则可以执行以下操作:

  select 
         case when a.action = 1 then 'load' when a.action = 0 then 'unload' end as action,
         case when a.action = 1 then o.loadingplace when a.action = 0 then o.unloadingplace end as place
    from trips t
      inner join actions a
        on t.trip_id = a.trip_id
      inner join orders o
        on a.orderid = o.orderid
      left join actions a2
        on a2.roor = 
          (select min(roor) 
             from actions a3
             where a3.roor > a.roor)
      left join orders o2
        on a2.orderid = o2.orderid
      where a.action != a2.action
        or a2.action is null
        or
          case when a.action = 1 then o.loadingplace != o2.loadingplace
               when a.action = 0 then o.unloadingplace != o2.unloadingplace
          end
    order by a.roor asc

这是一个更新的小提琴:http://sqlfiddle.com/#!9/fdf9c/14

答案 1 :(得分:2)

您不需要,并且您不想使用distinct,因为我们可以在您的示例中看到多个目的地多次出现。你想要什么:根据行动和地点过滤掉与前一记录相匹配的记录。

这看起来像这样:

SELECT *
FROM Trips t1 LEFT JOIN Trips t2 ON t1.Trip_Order = t2.Trip_Order - 10
WHERE t1.Action <> t2.Action OR t1.Place <> t2.Place)

答案 2 :(得分:2)

在SQL Server中,您可以获得ROW_NUMBER()基于trip_orderaction,place的差异,并尝试这样的方法。

您可以将其用作在USQL中创建类似查询的参考。

示例数据

DECLARE @Trip TABLE (Trip_order INT,   Action VARCHAR(10),  Place  VARCHAR(50),Ordernumber INT)

INSERT INTO @Trip VALUES
(10           ,'Load',     'Paris',          394798),
(20           ,'Load',     'Milan',          657748),
(30           ,'UnLoad',   'Athens',         657748),
(40           ,'UnLoad',   'Thessaloniki',   394798),
(50           ,'Load',     'Thessaloniki',   10142),
(60           ,'Load',     'Thessaloniki',   6577),
(70           ,'UnLoad',   'Athens',         6577),
(80           ,'UnLoad',   'Athens',         10412),
(90           ,'Load',     'Thessaloniki',   975147),
(100          ,'UnLoad',   'Paris',          975147);

<强>查询

SELECT action,place FROM 
(
    SELECT *,ROW_NUMBER()OVER(ORDER BY trip_order) - ROW_NUMBER()OVER(ORDER BY action,place) n
    FROM @trip
)t
GROUP BY n,action,place
ORDER BY MIN(trip_order)

答案 3 :(得分:1)

试试这个:

可以在 MySQL :::

中使用
SELECT IF(@temp=@temp:=A.TripName, @rank, @rank:=@rank+1) AS rank, A.TripName
FROM (SELECT CONCAT(A.Action, A.Place) AS TripName
      FROM TripA A
     ) A, (SELECT @temp:=0, @rank:=0) AS B
GROUP BY rank

答案 4 :(得分:1)

SELECT s.*
FROM stops s LEFT JOIN stops prev ON 
     ( prev.Trip_order < s.Trip_order
       AND NOT EXISTS ( SELECT 'a'
                        FROM stops prev2
                        WHERE prev2.Trip_order < s.Trip_order
                        AND prev2.Trip_order > prev.Trip_order
                       )
      )
WHERE s.Action <> COALESCE(prev.Action, '')
OR s.Place <> COALESCE(prev.Place, '')
ORDER BY s.Trip_order

答案 5 :(得分:-1)

select a1.action,a1.place
from tripa a1,tripa a2
where a2.trip_order = (select min(trip_order) from tripa a3 where trip_order > a1.trip_order)
and (a1.action != a2.action or a1.place != a2.place) 
or a2.place is null

这可以为您提供所需的结果。