我正在编写一个存储过程来填充多选控件,我想从数据库表中删除至少100个选项,但我想确保我带回用户已经拥有的所有选项地选择。
现有查询仅返回前100行:
SELECT TOP 100
t2.Id,
t2.value2
FROM
table1 t1
INNER JOIN
table2 t2
ON
t1.clientId = t2.clientId AND t1.Id = t2.Id
WHERE
t1.clientId = 1
我已在此查询中添加了UNION
,以确保我始终可以获取所选的选项:
SELECT TOP 100
t2.Id,
t2.value2
FROM
table1 t1
INNER JOIN
table2 t2 ON
t1.clientId = t2.clientId AND t1.Id = t2.Id
WHERE
t1.clientId = 1
UNION
SELECT t2.id,
t_si.externalCertificateNumber
FROM table2 t2
INNER JOIN
Table3 t3
ON t2.value = 333
在我的一个测试示例中,有4个先前选择的选项。其中3个将返回前100名(1不是,因此需要更新)。
我预计会回到101行,并且很惊讶地回到104行。我认为这与DISTINCT
中固有的UNION
工作方式有关。
然而,我也看到了 100 返回的不同结果。有些(超过3个)不同的值出现。还有一些在之前的TOP 100
中消失了!
所以我的问题是,UNION
是否有某种类型的内置排序会影响结果?或者还有其他事情发生在这里吗?
----------------------------- EDIT ----------------- -------------
如果我将上述查询更改为TOP 5:
之前选择的值是:
1, Blue
2, Green
20, Violet
100 Indigo
SELECT的结果本身如下:
1, Blue
2, Green
7, Red
15, Cyan
20, Violet
SELECT和UNION的结果
1, Blue
2, Green
33, Cyan
20, Violet
24, Yellow
100, Indigo
60, Aero
40, Amber
25, Black
这是一个不是来自DB的组成示例,但请注意SELECT和UNION中缺少SELECT中的红色
答案 0 :(得分:2)
UNION
运算符会删除重复记录。要保留所有记录,请使用UNION ALL
:
SELECT TOP 100
t2.Id,
t2.value2
FROM
table1 t1
INNER JOIN
table2 t2 ON
t1.clientId = t2.clientId AND
t1.Id = t2.Id
WHERE
t1.clientId = 1
UNION ALL
SELECT t2.id, t_si.externalCertificateNumber FROM table2 t2
INNER JOIN Table3 t3
ON t2.value = 333
TOP 100
查询中缺少的记录可以通过UNION
轻松解释,也可以通过结果集中不同的记录数来解释。
答案 1 :(得分:2)
我开始怀疑添加
UNION
已经改变了 执行计划,因为没有明确设置的顺序,这个 正在影响即将发生的事情。
你是对的。
没有TOP 100
的 ORDER BY
会返回一些 100行。未定义返回哪些行。
没有UNION
的查询的第一个版本返回了一组100行,带有UNION
的查询的第二个版本返回了另一组100行。
要获得可预测和预期的结果,您应该将ORDER BY
添加到使用TOP
的查询中。理想情况下,排序应该是明确的。
是的,UNION
确实有“内置”排序。如果你看一下执行计划,你通常会看到它。
我更喜欢使用公用表表达式(CTE)来编写复杂的查询,如下所示:
WITH
CTE
AS
(
SELECT TOP 100
t2.Id,
t2.value2
FROM
table1 t1
INNER JOIN table2 t2
ON t1.clientId = t2.clientId
AND t1.Id = t2.Id
WHERE
t1.clientId = 1
ORDER BY
t2.Id
)
SELECT
Id,
value2
FROM
CTE
UNION
SELECT
t2.id,
t_si.externalCertificateNumber
FROM
table2 t2
INNER JOIN Table3 t3 ON t2.value = 333
;