将CTE从Postgres转换为MSSQL

时间:2017-12-07 10:34:40

标签: sql-server tsql common-table-expression recursive-query

我应该从Postgresql zu MSSQL转换CTE。 问题是,Postgresql-Query使用Arrays。我不知道如何将它们转换为MSSQL。

以下是创建数据的完整查询:

CREATE TABLE pairs (
    from_city VARCHAR(255) NOT NULL,
    to_city VARCHAR(255) NOT NULL,
    distance INTEGER NOT NULL,
    PRIMARY KEY(from_city, to_city),
    CHECK (from_city < to_city)
);


INSERT INTO pairs
VALUES
('Bari','Bologna',672),
('Bari','Genova',944),
('Bari','Milano',881),
('Bari','Napoli',257),
('Bari','Palermo',708),
('Bologna','Genova',190),
('Bologna','Milano',200),
('Bologna','Napoli',470),
('Bologna','Palermo',730),
('Bologna','Roma',300), 
('Genova','Milano',120),
('Genova','Napoli',590),
('Genova','Palermo',790),
('Genova','Roma',400),
('Milano','Napoli',660),
('Milano','Palermo',890),
('Milano','Roma',480),
('Napoli','Palermo',310),
('Napoli','Roma',190),
('Palermo','Roma',430);


SELECT * FROM pairs;


-- Paths from Palermo to Milano...
;WITH RECURSIVE both_ways (
    from_city,
    to_city,
    distance
) /* Working Table containing all ways */
AS (
    SELECT
        from_city,
        to_city,
        distance
    FROM pairs
UNION ALL
    SELECT
        to_city AS "from_city",
        from_city AS "to_city",
        distance
    FROM pairs
),
paths (
    from_city,
    to_city,
    distance,
    path
)
AS (
    SELECT
        from_city,
        to_city,
        distance,
        ARRAY[from_city] AS "path"
    FROM both_ways b1
    WHERE b1.from_city = 'Palermo' --<<< Start Node >>>
  UNION ALL
    SELECT
        b2.from_city,
        b2.to_city,
        p.distance + b2.distance,
        p.path + b2.from_city
    FROM both_ways b2
    JOIN paths p
         ON (p.to_city = b2.from_city
             AND b2.from_city <> ALL (p.path[2:array_upper(p.path,1)]) /* Prevent re-tracing */
             AND array_upper(p.path,1) < 6)
)
SELECT
    path || to_city AS "path",
    distance
FROM paths
WHERE to_city = 'Milano'  --<<< End node >>>
AND ARRAY['Napoli','Roma','Bari'] <@ path -- <<< via... >>> - <@ means 'is contained by' 
ORDER BY distance, path 
LIMIT 5;

我希望有人可以帮助我,如何转换

ARRAY[from_city] AS "path"
路径定义中的

路径中的此条件-CTE:

AND b2.from_city <> ALL (p.path[2:array_upper(p.path,1)]) /* Prevent re-tracing */
         AND array_upper(p.path,1) < 6)

使用CTE的选择条件:

AND ARRAY['Napoli','Roma','Bari'] <@ path -- <<< via... >>> - <@ means 'is contained by' 

1 个答案:

答案 0 :(得分:2)

尝试以下

-- Paths from Palermo to Milano...
;WITH both_ways (
    from_city,
    to_city,
    distance
) /* Working Table containing all ways */
AS (
    SELECT
        from_city,
        to_city,
        distance
    FROM pairs
UNION ALL
    SELECT
        to_city AS "from_city",
        from_city AS "to_city",
        distance
    FROM pairs
),
paths (
    from_city,
    to_city,
    distance,
    path,
    Step
)
AS (
    SELECT
        from_city,
        to_city,
        distance,
        CAST(CONCAT('[',from_city,']') AS varchar(MAX)) AS "path",
        1 Step
    FROM both_ways b1
    WHERE b1.from_city = 'Palermo' --<<< Start Node >>>
  UNION ALL
    SELECT
        b2.from_city,
        b2.to_city,
        p.distance + b2.distance,
        p.path + CONCAT('[',b2.from_city,']'),
        p.Step+1
    FROM both_ways b2
    JOIN paths p
         ON (p.to_city = b2.from_city
             AND CHARINDEX(CONCAT('[',b2.from_city,']'),p.path)=0 /* Prevent re-tracing */
             AND p.Step < 6)
)
SELECT TOP 5
    REPLACE(REPLACE(REPLACE(path,'][',','),'[',''),']',',') + to_city AS "path",
    distance
FROM paths
WHERE to_city = 'Milano'  --<<< End node >>>

  AND CHARINDEX('[Napoli]',path)>0
  AND CHARINDEX('[Roma]',path)>0
  AND CHARINDEX('[Bari]',path)>0  -- <<< via... >>> - <@ means 'is contained by' 

ORDER BY distance, path

如果函数CONCAT不起作用,那么每个函数都会使用+

进行连接
CONCAT('[',from_city,']') => '['+from_city+']'