如何按特定顺序 select(几乎)唯一值
Howto select (almost) unique values in a specific order
在一次旅行中有几个停靠站,(一个停靠站 = 装载或交付一个或多个订单的地址),按特定顺序排列。
例如:
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
试试这个:
将在 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
您不需要也不想为此使用 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)
在SQL 服务器中,你可以得到基于trip_order
和action,place
的ROW_NUMBER()
的差异,然后尝试类似的操作。
您可以将其用作在 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)
试试这个。没有变量,没有什么特别花哨的:
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,只要支持子查询,它就应该适用。
Tt 简单地找到下一个最高的 trip_id
,并加入它,或者如果没有更高的 trip_order
则加入 null
。然后它只选择 place
、action
或两者不同的行,或者如果在连接的 table (a2.place is null
) 中没有位置的行。
标准完全更改后编辑
如果你想获得相同的结果,完全从你的基础 tables 构建,你可以这样做:
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
这是更新后的 fiddle:http://sqlfiddle.com/#!9/fdf9c/14
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
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
这为您提供了所需的结果。
在一次旅行中有几个停靠站,(一个停靠站 = 装载或交付一个或多个订单的地址),按特定顺序排列。 例如:
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
试试这个:
将在 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
您不需要也不想为此使用 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)
在SQL 服务器中,你可以得到基于trip_order
和action,place
的ROW_NUMBER()
的差异,然后尝试类似的操作。
您可以将其用作在 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)
试试这个。没有变量,没有什么特别花哨的:
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,只要支持子查询,它就应该适用。
Tt 简单地找到下一个最高的 trip_id
,并加入它,或者如果没有更高的 trip_order
则加入 null
。然后它只选择 place
、action
或两者不同的行,或者如果在连接的 table (a2.place is null
) 中没有位置的行。
标准完全更改后编辑
如果你想获得相同的结果,完全从你的基础 tables 构建,你可以这样做:
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
这是更新后的 fiddle:http://sqlfiddle.com/#!9/fdf9c/14
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
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
这为您提供了所需的结果。