[英]Single CTE with multiple SELECTs, CTE created twice in SQL Server
要求是在某些字段上连接(配对)两个表,然后按顺序显示配对结果。 配对正在 CTE 中完成。 一对被分配了一个 GUID,然后用于按顺序显示每对。 对于 Oracle (11.2),它按预期工作,但对于 SQL 服务器 (2017),似乎 CTE 创建了两次,因为每一行都有自己的 GUID。
我如何使用 CTE 解决它? 为什么 SQL 服务器的行为是这样的?
SQL 服务器http://sqlfiddle.com/#!18/21c167/1
Oracle http://sqlfiddle.com/#!4/c49dbb/2 (使用了 DBMS_RANDOM.RANDOM 而不是 SYS_GUID(),因为 SYS_GUID() 为 sqlfiddle.com 上的所有行返回了相同的值,同时在我的开发机器上运行良好)
CREATE TABLE VEHICLE (CODE NUMERIC(3,0), [TYPE] VARCHAR(50), DRIVER_CATEGORY VARCHAR(2));
CREATE TABLE DRIVER (CODE NUMERIC(9,0), NAME VARCHAR(200), CATEGORY VARCHAR(2));
INSERT INTO VEHICLE VALUES (1, 'LIMOUSINE', 'A');
INSERT INTO VEHICLE VALUES (2, 'TRUCK', 'B');
INSERT INTO VEHICLE VALUES (3, 'SUV', 'C');
INSERT INTO VEHICLE VALUES (4, 'SEDAN', 'C');
INSERT INTO VEHICLE VALUES (5, 'SPORTS CAR', 'D');
INSERT INTO DRIVER VALUES (1, 'James', 'A');
INSERT INTO DRIVER VALUES (2, 'Robert', 'B');
INSERT INTO DRIVER VALUES (3, 'John', 'C');
INSERT INTO DRIVER VALUES (4, 'Jennifer', 'C');
INSERT INTO DRIVER VALUES (5, 'Patricia', 'D');
INSERT INTO DRIVER VALUES (6, 'Susan', 'A');
INSERT INTO DRIVER VALUES (7, 'Lisa', 'B');
;WITH MATCHPAIRS AS
(
SELECT V.CODE VEHICLE_CODE, D.CODE DRIVER_CODE, V.TYPE TYPE, V.DRIVER_CATEGORY, D.NAME, D.CATEGORY, NewID() PAIRID
FROM VEHICLE V INNER JOIN DRIVER D ON V.DRIVER_CATEGORY = D.CATEGORY
)
SELECT p.VEHICLE_CODE, p.DRIVER_CODE, P.PAIRID, V.TYPE TYPE_NAME, 0 RECORD_ORDER
FROM VEHICLE V INNER JOIN MATCHPAIRS P ON V.CODE = P.VEHICLE_CODE
UNION ALL
SELECT p.VEHICLE_CODE, p.DRIVER_CODE, P.PAIRID, D.NAME TYPE_NAME, 1 RECORD_ORDER
FROM DRIVER D INNER JOIN MATCHPAIRS P ON D.CODE = P.DRIVER_CODE
ORDER BY PAIRID, RECORD_ORDER
CTE 不会被缓存,它们会针对每个引用重新计算。
无论如何, NEWID
有时会做一些奇怪的事情,当不在最外面的SELECT
上使用时,所以最好使用临时表。 CROSS APPLY
或CROSS JOIN
有时也不适用于NEWID
。
或者,改用不同的唯一化符。 例如
;WITH MATCHPAIRS AS (
SELECT
V.CODE VEHICLE_CODE,
D.CODE DRIVER_CODE,
V.TYPE TYPE,
V.DRIVER_CATEGORY,
D.NAME,
D.CATEGORY,
ROW_NUMBER() OVER (ORDER BY v.CODE, D.CODE) PAIRID
FROM VEHICLE V
INNER JOIN DRIVER D ON V.DRIVER_CATEGORY = D.CATEGORY
)
SELECT
p.VEHICLE_CODE,
p.DRIVER_CODE,
P.PAIRID,
V1.TYPE_NAME,
v1.RECORD_ORDER
FROM MATCHPAIRS P
CROSS APPLY (VALUES
(p.TYPE, 0),
(p.NAME, 1)
) V1(TYPE_NAME, RECORD_ORDER)
ORDER BY
PAIRID,
RECORD_ORDER;
请注意使用CROSS APPLY (VALUES
to unpivot,这样可以节省两次读取 CTE。
最简单的解决方案是使用临时表而不是 CTE。 如果需要,您可以将代码包装在存储过程中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.