【问题标题】:Why SQL Server sql query returns empty list?为什么 SQL Server sql 查询返回空列表?
【发布时间】:2015-09-04 20:14:45
【问题描述】:

请注意,我知道它一定很简单而且可能很明显 - 我只是看不到它...如上所述,你知道为什么这个 sql 查询在 SQL Server 上执行时会返回空列表(通过 SQL Server Management Studio),提供适当的表中有数据并且查询的所有参数都设置正确?

这个问题与我的另一个问题(Does anyone know why JPQL query on a view with SQL Server does not work? 'GetResultList' always returns empty list)相关,但在这个阶段它实际上变成了一个单独的主题,所以我把它放在这里。这是查询:

SELECT t1.Id,
         t2.IdTransiti,
         t1.CodiceCaricoPericoloso,
         t1.Confidenza,
         t1.Istante,
         t1.IstanteRicezione,
         t2.SQLServer_latitude,
         t2.SQLServer_longitude,
         t1.Partizione,
         t1.Targa,
         t1.TargaSecondaria,
         t1.UtmcInstanceId,
         t1.VelocitaStimata,
         t1.IdColore,
         t1.IdCorsia,
         t1.IdMarca,
         t1.IdModello,
         t1.IdNazionalita,
         t1.IdSerie,
         t1.IdTipologiaVeicolo
    FROM dbo.TransitiView t1
    LEFT OUTER JOIN Serie t0
       ON (t0.Id = t1.IdSerie)
    LEFT OUTER JOIN dbo.Colori t3
       ON (t3.Id = t1.IdColore)
    LEFT OUTER JOIN Modelli t4
       ON (t4.Id = t1.IdModello)
    LEFT OUTER JOIN Marche t5
       ON (t5.Id = t1.IdMarca),
    TransitiPunti t2,
    Corsie t6
   WHERE ( ( ( ( ( (t6.Attiva = 1)
                  AND (t1.Istante BETWEEN '2015-09-03 00:16:50.693'
                                      AND '2015-09-03 23:16:50.693'))
                AND ( (t1.Partizione = 0) OR (t1.Partizione = 6)))
              AND (t1.IdCorsia = 1))
            AND (t2.IdTransiti = t1.Id))
          AND (t6.Id = t1.IdCorsia))
ORDER BY t1.Istante DESC

编辑:

感谢 russ 的回答,我现在知道发生了什么 - SQL Server 不喜欢内部连接中的空记录 - 奇怪! 请问,你们中的任何人都知道如何以及是否可以进行 SQL Server“LIKE”内部联接,其中联接表的相应列中可能缺少条目? 或者...至少如何让它适用于这个特定的查询?

我想这样做:...ON (t2.IdTransiti = t1.Id or t2.IdTransiti is null) 但这对于 SQL Server 来说还不够好。它没有帮助:(。

BONUS QUESTION:知道为什么当通过内部连接连接的表可能为空时,MySQL 可以,但 SQL Server 不行?为什么这首先是不行的?


编辑:

问题解答: 感谢 russ - 我基本上明白了 - 这只是我的困惑,仅此而已。请在接受的答案下阅读 cmets。一切都源于我忘记的事实,不知道 JPA 中的 @SecondaryTable 注释会转化为内部连接,然后是双重混淆 - 我无视 这显然是在两个表中都期望内部连接!!!

感谢大家的努力,我想在下一次陈述事情之前我必须多考虑一下:)。

【问题讨论】:

  • 不要混合显式连接语法和旧的隐式连接!!!太容易出错了——只使用新的、显式的连接语法!!!
  • 将 t2 等条件从 WHERE 移动到 ON,以获得真正的 LEFT JOIN。 (就像现在一样,它作为常规内部连接执行......)
  • @jarhl 谢谢 Jahrl!但有趣的是,这个查询实际上是由我的项目中的 Microsoft sqljdbc4.jar 驱动程序自动生成的,我希望它不会出错?你知道这里可能是什么原因吗?另外 - 你知道这个查询是否真的有什么问题吗,因为它确实执行没有错误,除了它只返回一个空列表。
  • @jahrl Aaaahhhh ...就是这样!但是你知道为什么会这样吗? Java 端的相同代码(此处不相关的细节)将 ojdbc 驱动程序与 MySQL 一起使用,它必须生成正确的 sql 语法,因为我从来没有得到一个空列表,为什么 sqljdbc4.jar 驱动程序和 SQL Server 会失败?这实际上是自动生成的代码。
  • 驱动程序不会“自动生成”任何语句。驱动程序只执行 Java 程序传递给它的语句。另外,如果使用“ojdbc 驱动程序”,您的意思是 ojdbc6.jar,那么这适用于 Oracle,而不适用于 MySQL。

标签: sql sql-server


【解决方案1】:

如果您认为表 [TransitiPunti] 中没有记录,那么是的,这将阻止在该查询上使用 INNER JOIN 的任何查询生成行。注意:您现有的查询确实在该表上使用了 INNER JOIN(遗憾的是它使用了老式语法,但它是一个内部联接)。

我建议您“逐步”测试,以便解决问题。 “从小处着手”,尝试一下,如果成功,一次添加一项,然后重试。

一旦您停止获取结果,您就会知道您添加的最后一项是什么,而导致问题的将是该项。

这里有 3 个查询可供尝试。

/* 仅一张表 (t1) */

SELECT
      t1.Id
    , t1.CodiceCaricoPericoloso
    , t1.Confidenza
    , t1.Istante
    , t1.IstanteRicezione
    , t1.Partizione
    , t1.Targa
    , t1.TargaSecondaria
    , t1.UtmcInstanceId
    , t1.VelocitaStimata
    , t1.IdColore
    , t1.IdCorsia
    , t1.IdMarca
    , t1.IdModello
    , t1.IdNazionalita
    , t1.IdSerie
    , t1.IdTipologiaVeicolo
FROM dbo.TransitiView t1
WHERE t1.Istante BETWEEN '2015-09-03 00:16:50.693' AND '2015-09-03 23:16:50.693'
      AND (t1.Partizione = 0 OR t1.Partizione = 6)
      AND t1.IdCorsia = 1
ORDER BY t1.Istante DESC
;

/* 两个表(t1 & t6)*/

SELECT
      t1.Id
    , t1.CodiceCaricoPericoloso
    , t1.Confidenza
    , t1.Istante
    , t1.IstanteRicezione
    , t1.Partizione
    , t1.Targa
    , t1.TargaSecondaria
    , t1.UtmcInstanceId
    , t1.VelocitaStimata
    , t1.IdColore
    , t1.IdCorsia
    , t1.IdMarca
    , t1.IdModello
    , t1.IdNazionalita
    , t1.IdSerie
    , t1.IdTipologiaVeicolo
FROM dbo.TransitiView t1
      INNER JOIN Corsie t6 ON t6.Id = t1.IdCorsia
WHERE t6.Attiva = 1
      AND t1.Istante BETWEEN '2015-09-03 00:16:50.693' AND '2015-09-03 23:16:50.693'
      AND (t1.Partizione = 0 OR t1.Partizione = 6)
      AND t1.IdCorsia = 1
ORDER BY t1.Istante DESC
;

/*三个表t1,t2,t6 */

SELECT
      t1.Id
    , t2.IdTransiti
    , t1.CodiceCaricoPericoloso
    , t1.Confidenza
    , t1.Istante
    , t1.IstanteRicezione
    , t2.SQLServer_latitude
    , t2.SQLServer_longitude
    , t1.Partizione
    , t1.Targa
    , t1.TargaSecondaria
    , t1.UtmcInstanceId
    , t1.VelocitaStimata
    , t1.IdColore
    , t1.IdCorsia
    , t1.IdMarca
    , t1.IdModello
    , t1.IdNazionalita
    , t1.IdSerie
    , t1.IdTipologiaVeicolo
FROM dbo.TransitiView t1
      INNER JOIN TransitiPunti t2 ON t2.IdTransiti = t1.Id
      INNER JOIN Corsie t6 ON t6.Id = t1.IdCorsia
WHERE t6.Attiva = 1
      AND t1.Istante BETWEEN '2015-09-03 00:16:50.693' AND '2015-09-03 23:16:50.693'
      AND (t1.Partizione = 0 OR t1.Partizione = 6)
      AND t1.IdCorsia = 1
ORDER BY t1.Istante DESC

永远不要将旧的连接语法与(更好的)显式 ANSI 连接混合使用。

我也不喜欢多余的括号,我相信它们会混淆而不是帮助。

SELECT
      t1.Id
    , t2.IdTransiti
    , t1.CodiceCaricoPericoloso
    , t1.Confidenza
    , t1.Istante
    , t1.IstanteRicezione
    , t2.SQLServer_latitude
    , t2.SQLServer_longitude
    , t1.Partizione
    , t1.Targa
    , t1.TargaSecondaria
    , t1.UtmcInstanceId
    , t1.VelocitaStimata
    , t1.IdColore
    , t1.IdCorsia
    , t1.IdMarca
    , t1.IdModello
    , t1.IdNazionalita
    , t1.IdSerie
    , t1.IdTipologiaVeicolo
FROM dbo.TransitiView t1
      /*
      LEFT OUTER JOIN Serie t0 ON t0.Id = t1.IdSerie
      LEFT OUTER JOIN dbo.Colori t3 ON t3.Id = t1.IdColore
      LEFT OUTER JOIN Modelli t4 ON t4.Id = t1.IdModello
      LEFT OUTER JOIN Marche t5 ON t5.Id = t1.IdMarca
      */
      INNER JOIN TransitiPunti t2 ON t2.IdTransiti = t1.Id
      INNER JOIN Corsie t6 ON t6.Id = t1.IdCorsia
WHERE t6.Attiva = 1
      AND t1.Istante BETWEEN '2015-09-03 00:16:50.693' AND '2015-09-03 23:16:50.693'
      AND (t1.Partizione = 0 OR t1.Partizione = 6)
      AND t1.IdCorsia = 1
ORDER BY t1.Istante DESC

在取出括号并更正连接语法时,我认为查询看起来像上面那样。请注意,显然不需要任何左连接表。

顺便说一句:

AND (t1.Partizione = 0 OR t1.Partizione = 6)

可以改为:

AND t1.Partizione IN (0,6)

【讨论】:

  • 谢谢,做到了——信不信由你,但您的查询仍然返回一个空列表....
  • 是的,表中有数据。它实际上是一个视图而不是一个表格,但这应该没关系,对吗?例如查询 select * from dbo.TransitiView where dbo.TransitiView.Partizione = 0 AND ... 正常工作并返回数据。
  • 哦我相信你,但只有你有能力解决这个问题。首先尝试简化查询(只有一个表)。那必须提供数据。如果它没有删除 where 子句条件,直到它删除。然后你就会知道为什么它没有返回数据。
  • 是缩减查询从表中返回数据。我的查询是由 jdbc 驱动程序从 JPQL 自动生成的。但问题是为什么扩展查询不... :-) 我实际上需要一个扩展查询。这是一个问题。这可能很重要:TransitiPunti 是空的 Corsie 表具有应有的相关数据,这适用于 MySQL 吗?
  • 您有一个生成结果的缩减查询。伟大的。现在再添加一项。那行得通吗? (是的,好的,再添加一项)(不,太好了,现在我们知道是什么阻止了结果)。只有你能做到这一点,只有你能看到你执行了什么查询,只有你能看到结果。重要的是过程。从有效的小查询开始,然后继续添加项目,直到它停止工作。那么你就有答案了。
【解决方案2】:

括号似乎不寻常,您可以尝试将当前的 WHERE 子句替换为:

WHERE t6.Attiva = 1 
AND (t1.Istante BETWEEN '2015-09-03 00:16:50.693' AND '2015-09-03 23:16:50.693')
AND (t1.Partizione = 0 OR t1.Partizione = 6)
AND t1.IdCorsia = 1
AND t2.IdTransiti = t1.Id
AND t6.Id = t1.IdCorsia
ORDER BY t1.Istante DESC

如果transitipunti表为空,试试这个:

SELECT t1.Id,
     t1.CodiceCaricoPericoloso,
     t1.Confidenza,
     t1.Istante,
     t1.IstanteRicezione,
     t1.Partizione,
     t1.Targa,
     t1.TargaSecondaria,
     t1.UtmcInstanceId,
     t1.VelocitaStimata,
     t1.IdColore,
     t1.IdCorsia,
     t1.IdMarca,
     t1.IdModello,
     t1.IdNazionalita,
     t1.IdSerie,
     t1.IdTipologiaVeicolo
FROM dbo.TransitiView t1
LEFT OUTER JOIN Serie t0
   ON (t0.Id = t1.IdSerie)
LEFT OUTER JOIN dbo.Colori t3
   ON (t3.Id = t1.IdColore)
LEFT OUTER JOIN Modelli t4
   ON (t4.Id = t1.IdModello)
LEFT OUTER JOIN Marche t5
   ON (t5.Id = t1.IdMarca),
Corsie t6
WHERE t6.Attiva = 1 
AND (t1.Istante BETWEEN '2015-09-03 00:16:50.693' AND '2015-09-03 23:16:50.693')
AND (t1.Partizione = 0 OR t1.Partizione = 6)
AND t1.IdCorsia = 1
AND t6.Id = t1.IdCorsia
ORDER BY t1.Istante DESC

SQL Server 中的 Null 友好左联接:

create table abc
(
a int,
b int,
c int
)

create table def
(
d int,
e int,
f int
)

insert into abc values (1,2,3)

select * from abc left join def on abc.a = def.d or def.d = null

【讨论】:

  • 感谢 russ,但没有区别。
  • 谢谢!也许我实际上应该编辑我的问题 - 它确实可以在没有内部连接的情况下工作,我实际上之前就知道它,但感谢你,我实际上已经意识到为什么。这是因为 SQL Server 看起来很奇怪,不能容忍空条目!您知道是否有任何方法可以使 SQL Server“LIKE”在表为空的情况下进行内部连接? MySQL Server 可以处理这些情况而 SQL Server 不能,这似乎很奇怪。你以前有过这种情况吗?感谢您的帮助!
  • 我总是将内部连接视为必然需要一些数据来提供任何结果集。我会开始思考(我并不是说我已经尝试过)在 ON 参数中放置 'or isnull' ...?
  • 我想这样做:...ON (t2.IdTransiti = t1.Id or t2.IdTransiti is null) 但这对于 SQL Server 来说还不够好。它没有帮助:(。
  • 我不确定您的“SQL Server 中的 null 友好左连接”是为了演示什么,因为无论有无最终 or def.d = null,它都会产生完全相同的结果。
猜你喜欢
  • 2017-12-28
  • 1970-01-01
  • 2021-06-15
  • 1970-01-01
  • 1970-01-01
  • 2017-05-21
  • 2021-12-24
  • 1970-01-01
  • 2014-01-26
相关资源
最近更新 更多