查询在SQLite上有效,但在SQL Server上失败

时间:2019-09-19 19:42:24

标签: sql sql-server

以下查询在SQLite中对我有用。

SELECT Id, (SELECT Id
            FROM Vehicles v
            WHERE v.Id = t.VehicleId) AS VehId
FROM Transactions t
WHERE t.VehicleId IS NOT NULL AND VehId IS NULL;

但是在SQL Server中,它给我一个错误。

  

无效的列名“ VehId”。

然后编辑器在最后一个VehId(但不是第一个)的下方放一个红色的波浪线。

如您所料,Vehicles.Id是主键。我试图在Transactions中找到所有未引用Vehicles中任何行的外键。最好的方法是什么?

6 个答案:

答案 0 :(得分:4)

您可以使用LEFT OUTER JOIN查找不匹配的记录。

SELECT Id, v.Id AS VehId
FROM Transactions t
LEFT OUTER JOIN Vehicles v ON v.Id = t.VehicleId
WHERE t.VehicleId IS NOT NULL AND v.Id IS NULL

这保留了VehId列,但是由于您知道它将始终为NULL,因此可以通过子查询找到一组相似的数据。这将为您提供所有相同的行,但缺少VehId列-如果出于某种原因需要它,您始终可以对其进行硬编码。

SELECT Id
FROM Transactions t
WHERE t.VehicleId IS NOT NULL
AND t.VehicleId NOT IN (SELECT Id FROM Vehicles WHERE Id IS NOT NULL)

这将返回所有带有未知(但不为NULL)VehicleId的交易

答案 1 :(得分:2)

我认为您的查询可以简化为LEFT JOIN反模式:

SELECT t.Id
FROM Transactions t
LEFT JOIN Vehicles v ON v.Id = t.VehicleId
WHERE t.VehicleId IS NOT NULL AND v.Id IS NULL

另一种选择是对关联子查询使用NOT EXISTS条件:

SELECT Id
FROM Transactions t
WHERE 
    t.VehicleId IS NOT NULL
    AND NOT EXISTS (SELECT 1 FROM Vehicles v WHERE v.Id = t.VehicleId)

答案 2 :(得分:2)

您不能在where子句中引用列别名,这就是查询失败的原因。

看着它,我认为这可能是您要寻找的东西,它实质上复制了一个左联接,其中右表中的列不匹配。

SELECT Id, (SELECT Id
            FROM Vehicles v
            WHERE v.Id = t.VehicleId and v.id is null) AS VehId
FROM Transactions t
WHERE t.VehicleId IS NOT NULL;

答案 3 :(得分:2)

查询的问题在于,在SQL Server中,列列表是在WHERE子句之后评估的。这就是为什么您不能从WHERE子句引用列别名的原因。

有几种方法可以重写查询。这是其中的三个。

SELECT *
FROM (
    SELECT Id, (SELECT Id
                FROM Vehicles v
                WHERE v.Id = t.VehicleId) AS VehId
    FROM Transactions t) x
WHERE VehicleId IS NOT NULL AND VehId IS NULL;

SELECT Id, VehId
FROM Transactions t
OUTER APPLY (SELECT Id
            FROM Vehicles v
            WHERE v.Id = t.VehicleId) v(VehId)
WHERE t.VehicleId IS NOT NULL AND VehId IS NULL;

SELECT Id, NULL AS VehId
FROM Transactions t
WHERE t.VehicleId IS NOT NULL 
AND NOT EXISTS (SELECT Id
            FROM Vehicles v
            WHERE v.Id = t.VehicleId); 

答案 4 :(得分:1)

即使您的代码有效,为什么还要在结果中的第二列VehId内填充null呢?
当然,您可以进行LEFT联接或使用其他方法,但是如果您想使其像代码一样简单,请从SELECT列表中删除该列并将其移至WHERE子句:

SELECT t.Id 
FROM Transactions t
WHERE 
  t.VehicleId IS NOT NULL 
  AND 
  (SELECT v.Id FROM Vehicles v WHERE v.Id = t.VehicleId) IS NULL;

答案 5 :(得分:1)

使用NOT EXISTS

SELECT Id
FROM Transactions t
WHERE t.VehicleId IS NOT NULL AND 
      NOT EXISTS (SELECT Id
                  FROM Vehicles v
                  WHERE v.Id = t.VehicleId
                 );

这不仅是标准的SQL,而且在声明vehicles.id为主键的任何数据库上都应具有良好的性能。