5

这是我的桌子:

ROUTES = the route ID
STATIONS = the station ID
STOPS? = if the train stops at this station then is equal to 1 otherwise 0

-------------------------
ROUTES STATIONS  STOPS?
-------------------------
R1    S1    1
R1    S2    0
R1    S3    1
R1    S4    0
R1    S5    1
R2    S1    1
R2    S2    1
R2    S3    1
R2    S4    0
R2    S5    1
R3    S1    1
R3    S2    0
R3    S4    1
R3    S5    0
R3    S6    1
R3    S7    1
R4    S1    1
R4    S2    1
R4    S3    0
R4    S4    1
R5    S2    1
R5    S3    0
R5    S4    1

我要做的是找出哪些路线经过相同的车站但没有相同的停靠点。

例如:我们看到

Route R1 passes through stations S1->S2->S3->S4->S5 
Route R2 passes through stations S1->S2->S3->S4->S5 

但它们有不同的停靠点,所以结果应该是:

R1 
R2

我想首先将所有 ROUTES 分组并将属于该组的 STATIONS 与所有其他站点进行比较,并检查它们是否至少有一个不同的站点。

4

6 回答 6

1

以下查询将返回其中一列火车不停靠的路线和车站,http://sqlfiddle.com/# !3/f4c5f/8 。

  SELECT DISTINCT
    tblRoutes.ROUTES
   ,tblRoutesCross.ROUTES CrossingRoute
   ,tblRoutes.STATIONS
  FROM
    tblRoutes
  INNER JOIN
    tblRoutes tblRoutesCross
  ON
    tblRoutesCross.STATIONS = tblRoutes.STATIONS
  AND
    tblRoutes.ROUTES < tblRoutesCross.ROUTES
  AND
    (
       tblRoutesCross.STOPS = 0 
      OR
       tblRoutes.STOPS = 0 
    )

以下查询将仅返回交叉路线:

 SELECT DISTINCT
    tblRoutes.ROUTES
   ,tblRoutesCross.ROUTES CrossingRoute
   --,tblRoutes.STATIONS
  FROM
    tblRoutes
  INNER JOIN
    tblRoutes tblRoutesCross
  ON
    tblRoutesCross.STATIONS = tblRoutes.STATIONS
  AND
    tblRoutes.ROUTES < tblRoutesCross.ROUTES
  AND
    (
       tblRoutesCross.STOPS = 0 
      OR
       tblRoutes.STOPS = 0 
    )

在 where 子句中查找非火车停靠的路线或 to and in where 子句:

  SELECT DISTINCT
    tblRoutes.ROUTES
   ,tblRoutesCross.ROUTES CrossingRoute
   --,tblRoutes.STATIONS
  FROM
    tblRoutes
  INNER JOIN
    tblRoutes tblRoutesCross
  ON
    tblRoutesCross.STATIONS = tblRoutes.STATIONS
  AND
    tblRoutes.ROUTES < tblRoutesCross.ROUTES
  AND
    (
       tblRoutesCross.STOPS = 0 
      AND
       tblRoutes.STOPS = 0 
    )
于 2012-11-16T15:56:32.583 回答
0

我对我的代码感到抱歉,但我正在工作,我稍后会格式化,但这是您在步骤中需要的
希望它有所帮助

DECLARE @table TABLE (r NVARCHAR(3), s NVARCHAR(3), st BIT)
DECLARE @temp TABLE (r NVARCHAR(3), s NVARCHAR(100), st NVARCHAR(100))

INSERT INTO @table
        ( [r], [s], [st] )
VALUES  ('R1','S1',1 ),
        ('R1','S2',0),
        ('R1','S3',1),
        ('R1','S4',0),
        ('R1','S5',1),
        ('R2','S1',1),
        ('R2','S2',1),
        ('R2','S3',1),
        ('R2','S4',0),
        ('R2','S5',1),
        ('R3','S1',1),
        ('R3','S2',0),
        ('R3','S4',1),
        ('R3','S5',0),
        ('R3','S6',1),
        ('R3','S7',1),
        ('R4','S1',1),
        ('R4','S2',1),
        ('R4','S3',0),
        ('R4','S4',1),
        ('R5','S2',1),
        ('R5','S3',0),
        ('R5','S4',1)

SELECT * FROM @table

INSERT INTO @temp
        ( [r], [s], [st] )

SELECT DISTINCT r ,(
Select s + ',' AS 'data()' 
            From @table R2
            WHERE R2.[r] = [R].r
            ORDER BY [r]
            For XML PATH ('') ) [Routs]
            , (
Select CAST([st]AS NVARCHAR(2)) + ',' AS 'data()' 
            From @table R2
            WHERE R2.[r] = [R].r
            ORDER BY [r]
            For XML PATH ('') ) [Stops]
    FROM @table R

SELECT * FROM @temp

SELECT * FROM @temp WHERE [s] IN (SELECT [s] FROM @temp GROUP BY s HAVING COUNT(*) > 1 )

SELECT T.* FROM @temp T
INNER JOIN (
SELECT [s], [st] FROM @temp WHERE [r] IN (
 SELECT [r] FROM @temp WHERE [s] IN 
    ( SELECT [s] FROM @temp GROUP BY s HAVING COUNT(*) > 1 ) )
    GROUP BY [s], [st] HAVING COUNT (*) = 1 ) X ON T.[s] = X.[s] AND T.[st] = X.[st]
于 2012-11-16T16:17:12.113 回答
0

我假设一个 TrainRoutes 表,其中 R1、R2 等各有一行。如果需要,您可以将其替换为从 Stops 中选择不同的 RouteID。

Select
    r1.RouteID Route1,
    r2.RouteID Route2
From
    -- cross to compare each route with each route
    dbo.TrainRoutes r1
        Cross Join
    dbo.TrainRoutes r2
        Inner Join
    dbo.Stops s1
        On r1.RouteID = s1.RouteID
        Inner Join
    dbo.Stops s2
        On r2.RouteID = s2.RouteID
Where
    r1.RouteID < r2.RouteID -- no point in comparing R1 with R2 and R2 with R1
Group By
    r1.RouteID,
    r2.RouteID
Having
     -- check each route has the same number of stations
    count(Distinct s1.stationID) = count(Distinct s2.stationID) And
    -- check each route has the same stops
    Sum(Case When s1.StationID = s2.StationID Then 1 Else 0 End) = count(Distinct s1.StationID) And
    -- check each route has different halts
    sum(Case When s1.StationID = s2.StationID And s1.Halts = s2.Halts Then 1 Else 0 End) != count(Distinct s1.StationID)

您也可以在没有 TrainRoute 表的情况下执行此操作,但您现在要交叉连接两个更大的表:

Select
    s1.RouteID Route1,
    s2.RouteID Route2
From
    dbo.Stops s1
        Cross Join
    dbo.Stops s2
Where
    s1.RouteID < s2.RouteID
Group By
    s1.RouteID,
    s2.RouteID
Having
    count(Distinct s1.stationID) = count(Distinct s2.stationID) And
    Sum(Case When s1.StationID = s2.StationID Then 1 Else 0 End) = count(Distinct s1.StationID) And
    sum(Case When s1.StationID = s2.StationID And s1.Halts = s2.Halts Then 1 Else 0 End) != count(Distinct s1.StationID)

http://sqlfiddle.com/#!6/76978/8

于 2012-11-16T16:18:58.697 回答
0

这里真正的挑战是找到经过相同车站的路线。这个想法是通过在表上进行自连接来比较两条路线,compa 和 compb。当然,比较是针对所有配对。

现在,如果我们汇总有关路线的一些信息,我们可以确定它们是否具有相同的站点:

  • 按站加入,因此只计算匹配项
  • 计算 compA 和 compB 上的站数
  • 数一下两者的数字

第一个是join的条件,第二个是使用window函数在join前进行计数,第三个是join的结果。

当所有这些计数相同时,两条路线通过同一个车站。

很容易。现在我们只需要添加某个站点在一条路线上停靠但在另一条路线上没有停靠的位置。

以下查询包含此逻辑:

select compa_Route, compb_Route
from (select compa.route as compa_route, compb.route as compb_Route,
             MAX(compa.numstations) as compa_NumStations,
             MAX(compb.NumStations) as compb_NumStations,
             SUM(case when compa.stop <> compb.stop then 1 else 0 end) as DifferentStops,
             COUNT(*) as both_NumStations
      from (select t.*, COUNT(*) over (partition by route) as numstations
            from t
           ) routea join
           (select t.*, COUNT(*) over (partition by route) as numstations
            from t
           ) routeb
           on routea.station = routeb.station and
              routea.route < routeb.route
      group by compa.route, compb.route
     ) ab
where compa_NumStations = compb_NumStations and
      compa_NumStations = both_NumStations and
      DifferentStops > 0

请注意,这是假设站点没有在路线上重复。如果站可以重复,那么问题变得有点困难。

于 2012-11-16T16:22:12.293 回答
0

在 SQLServer2005+ 中,使用递归 CTE(公用表表达式)查找所有车站并将列车停靠点相加以进行比较

;WITH cte (id, r, s, st, max_level) AS
 (
  SELECT ROW_NUMBER() OVER(PARTITION BY t.r ORDER BY (SELECT 1)) as id,
         t.r, t.s, t.st,
         COUNT(*) OVER(PARTITION BY t.r) AS max_level
  FROM dbo.test11 t
  ), cte2 (id, r, s, st, max_level) AS
 (
  SELECT id, r, s, st, max_level
  FROM cte
  WHERE id = 1
  UNION ALL
  SELECT c.id, c.r, CAST(ISNULL(ct.s, '') + ', ' + ISNULL(c.s, '') AS nvarchar(100)) AS s,
         ct.st + c.st, c.max_level
  FROM cte c JOIN cte2 ct ON c.id = ct.id + 1 AND c.r = ct.r
)
SELECT c.r, c.s, c.st
FROM cte2 c JOIN cte2 ct ON c.s = ct.s AND c.r <> ct.r AND c.st <> ct.st
WHERE c.id = c.max_level AND ct.id = ct.max_level

SQLFiddle上的演示

于 2012-11-17T18:28:57.993 回答
-1

只需搜索没有余数的关系除法或精确的关系除法。

于 2012-11-18T03:09:53.480 回答