当您多次运行SELECT * FROM多个表连接时,是否有可能在执行之间以不同的列顺序返回数据?

时间:2009-07-01 08:22:28

标签: sql sql-server-2008 reflection ado.net

例如,我有以下表格:

CREATE TABLE A (Id int, BId int, Number int)
CREATE TABLE B (Id int, Number decimal(10,2))
GO
INSERT INTO A VALUES(1, 3, 10)
INSERT INTO B VALUES(3, 50)
INSERT INTO A VALUES(2, 5, 20)
INSERT INTO B VALUES(5, 671.35)
GO

我多次运行以下查询:

SELECT * FROM A INNER JOIN B ON A.BId = B.Id

我应该得到类似的东西:

ID  BId  Number  ID  Number
 1    3      10   3   50.00
 2    5      20   5  671.35

但A.Number和B.Number是否可能处于不同的位置(在这方面也是ID)所以我会得到类似的东西:

ID  Number  ID  BId  Number
 3   50.00   1    3      10
 5  671.35   2    5      20

我们目前正在经历一些可能由此类造成的奇怪问题。我们有一个ASP.NET应用程序,执行一个基于自定义反射的代码生成数据映射器,它连接到SQL Server 2008集群。

我们发现有时会出现这样的错误:

'System.Decimal'类型的对象无法转换为'System.Int32'类型

试图弄清楚这是SQL Server中的行为,还是基于反射的数据映射器引擎中的行为。

正如您所看到的,两个表中的字段名称相同。想想也许当我们尝试做DataReader.GetValue(DataReader.GetOrdinal(“Number”))时,它将返回B.Number,它是一个小数而不是A.Number,它是一个int。

为了使问题进一步复杂化,这只会间歇性地发生(但只有在Web场中的特定IIS Web服务器上发生一次后才会一直发生)。

假设Web服务器A正常运行直到下午2点突然,我们收到此错误,我们将继续在Web服务器A上收到该错误,直到我们重置该服务器上的IIS,然后它就可以了。< / p>

有什么事可以做连接池以及SQL查询计划如何缓存?

4 个答案:

答案 0 :(得分:1)

SQL是一种关系代数 - 如果您没有自己明确说明该命令,则该标准不会指定将返回哪些订单列。

我倾向于尽可能地避免使用"select *",因为它可能会堵塞网络中不必要的流量,并且更难以捕获列重命名和排序之类的内容,直到为时已晚。

只需选择您真正需要的列。

对于你的具体情况,我也只返回共享ID一次,因为你的连接必须是相同的(我倾向于选择“旧”的风格,因为DBMS应该足够聪明以优化它到内部无论如何加入):

select
    a.Id as Id,
    a.BId as BId,
    a.Number as Number,
    b.Number as BNumber
from
    a, b
where
    a.BId = b.Id

答案 1 :(得分:1)

只有交换表格订单时才可能出现第二种情况。

类似SELECT * FROM B INNER JOIN A ON A.BId = B.Id。

否则不可能。

答案 2 :(得分:1)

  

只有交换表格订单时才可能出现第二种情况。

连接顺序与列的位置无关,除非您使用不推荐的简单SELECT *。

即使在这种情况下,您也可以使用

SELECT B. ,A。,不改变联接顺序

最佳和推荐的解决方案是使用列名而不是*(在前两个答案中公布)

- 稍后补充

我忘记了一件我想指出的事情:对具有相同名称的列使用列别名,例如。

选择A.Number为NumberA,B.Number为NumberB

答案 3 :(得分:0)

我认为我没有看到它交换订单,但我个人不会在生产代码中使用“SELECT *”:

SELECT A.[Id], A.[Bid], A.[Number], B.[Id], b.[Number]
FROM A INNER JOIN B ON A.[BId] = B.[Id]

或者最坏的情况:

SELECT A.*, B.* FROM A INNER JOIN B ON A.[BId] = B.[Id]