具有多个选择的单个CTE,在SQL Server中创建了两次CTE

yshpjwxd  于 2022-10-03  发布在  SQL Server
关注(0)|答案(2)|浏览(229)

要求是连接(配对)一些字段上的两个表,然后按顺序显示成对的结果。在CTE中正在进行配对。为一对分配一个GUID,然后使用该GUID按顺序显示每一对。对于Oracle(11.2),它如预期的那样工作,但对于SQL Server(2017),CTE似乎创建了两次,因为每一行都有自己的GUID。

我如何使用CTE来解决这个问题?为什么SQL Server会有这种行为?

SQL Serverhttp://sqlfiddle.com/#!18/21c167/1

已使用Oraclehttp://sqlfiddle.com/#!4/c49dbb/2*(DBMS_RANDOM.RANDOM代替SYSGUID(),因为SYSGUID()在我的开发机器上运行正常时,为SQLfiddle.com上的所有行返回相同的值)*

  1. CREATE TABLE VEHICLE (CODE NUMERIC(3,0), [TYPE] VARCHAR(50), DRIVER_CATEGORY VARCHAR(2));
  2. CREATE TABLE DRIVER (CODE NUMERIC(9,0), NAME VARCHAR(200), CATEGORY VARCHAR(2));
  3. INSERT INTO VEHICLE VALUES (1, 'LIMOUSINE', 'A');
  4. INSERT INTO VEHICLE VALUES (2, 'TRUCK', 'B');
  5. INSERT INTO VEHICLE VALUES (3, 'SUV', 'C');
  6. INSERT INTO VEHICLE VALUES (4, 'SEDAN', 'C');
  7. INSERT INTO VEHICLE VALUES (5, 'SPORTS CAR', 'D');
  8. INSERT INTO DRIVER VALUES (1, 'James', 'A');
  9. INSERT INTO DRIVER VALUES (2, 'Robert', 'B');
  10. INSERT INTO DRIVER VALUES (3, 'John', 'C');
  11. INSERT INTO DRIVER VALUES (4, 'Jennifer', 'C');
  12. INSERT INTO DRIVER VALUES (5, 'Patricia', 'D');
  13. INSERT INTO DRIVER VALUES (6, 'Susan', 'A');
  14. INSERT INTO DRIVER VALUES (7, 'Lisa', 'B');
  15. ;WITH MATCHPAIRS AS
  16. (
  17. SELECT V.CODE VEHICLE_CODE, D.CODE DRIVER_CODE, V.TYPE TYPE, V.DRIVER_CATEGORY, D.NAME, D.CATEGORY, NewID() PAIRID
  18. FROM VEHICLE V INNER JOIN DRIVER D ON V.DRIVER_CATEGORY = D.CATEGORY
  19. )
  20. SELECT p.VEHICLE_CODE, p.DRIVER_CODE, P.PAIRID, V.TYPE TYPE_NAME, 0 RECORD_ORDER
  21. FROM VEHICLE V INNER JOIN MATCHPAIRS P ON V.CODE = P.VEHICLE_CODE
  22. UNION ALL
  23. SELECT p.VEHICLE_CODE, p.DRIVER_CODE, P.PAIRID, D.NAME TYPE_NAME, 1 RECORD_ORDER
  24. FROM DRIVER D INNER JOIN MATCHPAIRS P ON D.CODE = P.DRIVER_CODE
  25. ORDER BY PAIRID, RECORD_ORDER
zf2sa74q

zf2sa74q1#

CTE不会被缓存,它们会为每个引用重新计算。

无论如何,NEWID有时会做一些奇怪的事情,当不在最外面的SELECT上使用时,所以最好使用临时表。CROSS APPLYCROSS JOIN有时也不适用于NEWID

或者,改用不同的唯一项。例如

  1. ;WITH MATCHPAIRS AS (
  2. SELECT
  3. V.CODE VEHICLE_CODE,
  4. D.CODE DRIVER_CODE,
  5. V.TYPE TYPE,
  6. V.DRIVER_CATEGORY,
  7. D.NAME,
  8. D.CATEGORY,
  9. ROW_NUMBER() OVER (ORDER BY v.CODE, D.CODE) PAIRID
  10. FROM VEHICLE V
  11. INNER JOIN DRIVER D ON V.DRIVER_CATEGORY = D.CATEGORY
  12. )
  13. SELECT
  14. p.VEHICLE_CODE,
  15. p.DRIVER_CODE,
  16. P.PAIRID,
  17. V1.TYPE_NAME,
  18. v1.RECORD_ORDER
  19. FROM MATCHPAIRS P
  20. CROSS APPLY (VALUES
  21. (p.TYPE, 0),
  22. (p.NAME, 1)
  23. ) V1(TYPE_NAME, RECORD_ORDER)
  24. ORDER BY
  25. PAIRID,
  26. RECORD_ORDER;

请注意,使用CROSS APPLY (VALUES取消透视,省去了两次读取CTE。

SQL小提琴

展开查看全部
vsdwdz23

vsdwdz232#

最简单的解决方案是使用临时表而不是CTE。如果需要,可以将代码 Package 在存储过程中。

相关问题