我们有7个人在波兰旅行(;))。问题是他们访问华沙时最多可以找到他们访问过的三个城市。如果一个人两次访问华沙,它也被视为下一次旅行的起点。 例如,家伙1不仅有一次旅行 - 华沙,克拉科夫,华沙,格但斯克,还有华沙,格但斯克。
表A
+------+-----------+-----+
| date | city | guy |
+------+-----------+-----+
| 2 | Warsaw | 1 |
| 4 | Cracow | 1 |
| 5 | Cracow | 2 |
| 6 | Bialystok | 3 |
| 7 | Warsaw | 1 |
| 8 | Gdansk | 1 |
| 10 | Warsaw | 5 |
| 12 | Cracow | 5 |
| 14 | Bialystok | 6 |
| 15 | Warsaw | 7 |
| 20 | Warsaw | 7 |
+------+-----------+-----+
所以最终的表格看起来像这样:
+-----------+-----------+-----------+-----------+
| Starting | 2nd dest. | 3th dest. | 4th dest. |
+-----------+-----------+-----------+-----------+
| Warsaw | Cracow | Warsaw | Gdansk |
| Warsaw | Gdansk | | |
| Warsaw | Cracow | | |
| Warsaw | Warsaw | | |
| Warsaw | | | |
+-----------+-----------+-----------+-----------+
问题是创建一个将自动从表A创建最终表的查询。
找到每个起点没有问题,但我不知道如何找到每个第二个目的地。我似乎也必须有某种循环 - 这个人必须与起点相同,而第二个目的地的日期必须大于此确切起点的日期。
任何帮助解决这个问题将不胜感激。 ;)
SQLFiddle以及更多示例条目数据 - http://sqlfiddle.com/#!2/de0f1 上面的数据只是一个样本,解决方案需要处理更大的集合。
答案 0 :(得分:1)
使用Row_Number()
和Pivot
的解决方案:
select guy,[1] as First, IsNULL([2], '') as Second, IsNUll([3], '') as Third, IsNull([4], '') as Forth
from (
select row_number() over (partition by guy order by guy, date) as number, city, guy
from voyage
) x
pivot
(
max(city)
for number in ([1], [2], [3], [4])
) as p
我的例子假设日期是int类型,但是这可以很容易地重新设计以使用正确的日期....
编辑:
这将提供所需的输出(不确定这将是一般方法......):
select *
from
(
select guy,[1] as First, IsNULL([2], '') as Second, IsNUll([3], '') as Third, IsNull([4], '') as Forth
from (
select row_number() over (partition by guy order by guy, date) as number, city, guy
from voyage ) x
pivot
(
max(city)
for number in ([1], [2], [3], [4])
) as p
where [1] = 'Warsaw'
union All
select guy,[3] as First, case when [4] = 'Warsaw' then '' else IsNULL([4], '') end as Second, '' as Third, '' as Forth
from (
select row_number() over (partition by guy order by guy, date) as number, city, guy
from voyage ) x
pivot
(
max(city)
for number in ([1], [2], [3], [4])
) as p
where [3] = 'Warsaw'
Union all
select guy,[2] as First, '' as Second, '' as Third, '' as Forth
from (
select row_number() over (partition by guy order by guy, date) as number, city, guy
from voyage ) x
pivot
(
max(city)
for number in ([1], [2], [3], [4])
) as p
where [2] = 'Warsaw'
) bigdata
order by guy
答案 1 :(得分:1)
如果您使用的是SQL Server 2012或更高版本,则可以在solve the problem的帮助下轻松LEAD() analytic function:
WITH ThreeDestinations AS (
SELECT
*,
Destination2 = LEAD(city, 1) OVER (PARTITION BY guy ORDER BY date),
Destination3 = LEAD(city, 2) OVER (PARTITION BY guy ORDER BY date),
Destination4 = LEAD(city, 3) OVER (PARTITION BY guy ORDER BY date)
FROM
dbo.voyage
)
SELECT
StartingPoint = city,
Destination2,
Destination3,
Destination4
FROM
ThreeDestinations
WHERE
city = 'Warsaw'
ORDER BY
date
;
对LEAD的三次调用会为您提供原始集合中每个城市之后的前三个(或更少)目的地。下一步,也是最后一步,只是过滤掉起点不是华沙的行。
答案 2 :(得分:0)
这应该有效。我用Cte's来查询一个来自华沙的人的第一次旅行以及来自华沙的第二次旅行。最后使用Pivot以请求的格式联合并显示结果集。希望这很有用。
;WITH cte_Itinerary([Date], City, Guy)
AS (SELECT '2', 'Warsaw', '1'
UNION ALL
SELECT '4', 'Cracow', '1'
UNION ALL
SELECT '5', 'Cracow', '2'
UNION ALL
SELECT '6', 'Bialystok', '3'
UNION ALL
SELECT '7', 'Warsaw', '1'
UNION ALL
SELECT '8', 'Gdansk', '1'
UNION ALL
SELECT '10', 'Warsaw', '5'
UNION ALL
SELECT '12', 'Cracow', '5'
UNION ALL
SELECT '14', 'Bialystok ', '6'
UNION ALL
SELECT '15', 'Warsaw', '7'
UNION ALL
SELECT '20', 'Warsaw', '7'
)
, cte_AddRowNumber
AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY Guy ORDER BY Guy, [Date]) AS number,
City,
Guy
FROM cte_Itinerary
)
, cte_FilterByWarsaw
AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY Guy ORDER BY Guy, [Date]) AS number,
City,
Guy
FROM cte_Itinerary
WHERE City = 'Warsaw'
)
, cte_Result_AllDestinations
AS (
SELECT DISTINCT
'One' AS ResultType,
o.Number,
o.City,
o.Guy
FROM cte_AddRowNumber AS o
JOIN cte_FilterByWarsaw AS t
ON o.Guy = t.Guy
AND t.number <= o.number
)
, cte_Result_SecondDestinations
AS (
SELECT 'Two' AS ResultType,
ROW_NUMBER() OVER (PARTITION BY r1.Guy ORDER BY r1.Guy) AS number,
r1.City,
r1.Guy
FROM cte_Result_AllDestinations AS r1
JOIN cte_Result_AllDestinations AS r2
ON r1.Guy = r2.Guy
AND r1.number >= r2.number
WHERE r2.City = 'Warsaw'
AND r2.number <> 1
)
SELECT Guy,
[1] AS Starting,
ISNULL([2], '') AS [2nd Dest.],
ISNULL([3], '') AS [3th Dest.],
ISNULL([4], '') AS [4th Dest.]
FROM(SELECT ResultType,Number,City,Guy
FROM cte_Result_AllDestinations
UNION ALL
SELECT ResultType,Number,City,Guy
FROM cte_Result_SecondDestinations)AS X
PIVOT(MAX(City)FOR NUMBER IN([1], [2], [3], [4]))AS P;