sti*_*bit 3 sql sql-server uuid
抽象
像这样的查询
SELECT *
FROM elbat t
CROSS JOIN (SELECT newid() guid) x;
Run Code Online (Sandbox Code Playgroud)
在SQL Server中产生,其中每一行都有不同的GUID,而不是其在整个结果的共同GUID每一行的结果.如何为结果的所有行设置一个GUID(不使用变量或(临时)表)?
建立
请考虑SQL Server数据库中的下表.
CREATE TABLE elbat
(id integer);
INSERT INTO elbat
VALUES (1);
INSERT INTO elbat
VALUES (2);
INSERT INTO elbat
VALUES (3);
INSERT INTO elbat
VALUES (4);
INSERT INTO elbat
VALUES (5);
INSERT INTO elbat
VALUES (6);
Run Code Online (Sandbox Code Playgroud)
我们运行以下查询.
SELECT *
FROM elbat t
CROSS JOIN (SELECT newid() guid) x;
Run Code Online (Sandbox Code Playgroud)
这是一个db <>小提琴和一个SQL小提琴,可以看到它的实际效果.
问题
令我惊讶的是,在结果中每行都有不同的GUID.例如:
id | guid
-: | :-----------------------------------
1 | ad146af7-9ebd-4521-a440-47c7dea6a1d4
2 | ce24fbb8-af64-480c-8c46-1e03187642c5
3 | 14509451-9b1d-49e9-8da2-c691947ae805
4 | 37a86339-e352-486f-b541-92798540599f
5 | cbee1a8e-02ce-4915-8d2c-ef5db299d8c8
6 | d491275b-4ebb-461b-94e2-93b47e7d2348
Run Code Online (Sandbox Code Playgroud)
这让我感到困惑.我希望每一行在整个结果集中都具有相同的GUID.例如:
id | guid
-: | :-----------------------------------
1 | cbee1a8e-02ce-4915-8d2c-ef5db299d8c8
2 | cbee1a8e-02ce-4915-8d2c-ef5db299d8c8
3 | cbee1a8e-02ce-4915-8d2c-ef5db299d8c8
4 | cbee1a8e-02ce-4915-8d2c-ef5db299d8c8
5 | cbee1a8e-02ce-4915-8d2c-ef5db299d8c8
6 | cbee1a8e-02ce-4915-8d2c-ef5db299d8c8
Run Code Online (Sandbox Code Playgroud)
我当然明白,GUID会因呼叫而改变.但我不明白为什么它从一行变为另一行时加入单个GUID并且没有将newid()调用放在投影列列表中.
附加信息
我尝试使用小提琴平台上的所有可用版本以及本地Microsoft SQL Server 2014(12.0.2269.0(X64),Express).结果是无处不在(当然只有GUID更改).
在质疑我对连接的理解时,我还对其他DBMS进行了一些测试,并进行了相同的设置和查询.
Postgres的:
SELECT *
FROM elbat t
CROSS JOIN (SELECT uuid_generate_v4() guid) x;
Run Code Online (Sandbox Code Playgroud)
甲骨文:
SELECT *
FROM elbat t
CROSS JOIN (SELECT sys_guid() guid
FROM dual) x;
Run Code Online (Sandbox Code Playgroud)
MariaDB的:
SELECT *
FROM elbat t
CROSS JOIN (SELECT uuid() guid) x;
Run Code Online (Sandbox Code Playgroud)
MySQL的:
SELECT *
FROM elbat t
CROSS JOIN (SELECT uuid() guid) x;
Run Code Online (Sandbox Code Playgroud)
所有这些其他DBMS都会产生我实际期望的结果 - 结果的所有行中的一个常见GUID.
我也玩过改变查询.无济于事.
SELECT没有FROM使用TOP,并且也是主键.FROM elbat, (SELECT newid() ...)).CROSS APPLY.查看文档,我无法在任何地方找到此行为.
题
为什么SQL Server的行为与所有其他(已测试的)DBMS(在这方面)不同,是否有办法按预期获得结果(不使用变量或(临时)表)?
(注意:我知道我可以使用一个初始化的变量并将newid()其放在投影列中.但问题实际上是在我试图避免这样的变量时出现的.我实际上想要寻找一个无变量,仅查询的解决方案用于"随机排序表但有例外".)
我对 SQL Server 的行为感到非常惊讶。我没有意识到它会一遍又一遍地重新评估这些子查询。我怀疑原因是优化: 中的表达式cross join实际上移动到读取数据的节点,因此该函数被一遍又一遍地调用。
无论如何,我认为这是错误的。这种优化应该认识到这newid()是一个易变的函数并相应地进行调整。
经过一些实验,我发现order by在子查询中确实会导致它只被评估一次。所以,这就是你想要的:
select *
from elbat cross join
(select top (1) newid() as guid
order by guid
) x;
Run Code Online (Sandbox Code Playgroud)
另一个版本可以满足您的期望:
select *
from elbat cross join
(select max(newid()) as guid
) x;
Run Code Online (Sandbox Code Playgroud)
顺便说一句,后一个版本也适用于select:
select *, (select max(newid())) as guid
from elbat ;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我希望对每一行评估一次子查询。去搞清楚。
| 归档时间: |
|
| 查看次数: |
1251 次 |
| 最近记录: |