0

我有一个订单系统。用户可以作为不同用户的一种类型附加到不同的订单。他们可以下载与订单相关的文档。文档仅提供给订单上的某些类型的用户。我在编写查询以检查用户查看文档的权限并选择有关文档的信息时遇到问题。

我有以下表格和(适用的)字段:

Docs: DocNo, FileNo
DocAccess: DocNo, UserTypeWithAccess
FileUsers: FileNo, UserType, UserNo 

我有以下查询:

SELECT Docs.* 
FROM Docs
WHERE DocNo = 1000
  AND EXISTS (
         SELECT * FROM DocAccess
         LEFT JOIN FileUsers
           ON FileUsers.UserType = DocAccess.UserTypeWithAccess 
           AND FileUsers.FileNo = Docs.FileNo /* Errors here */
         WHERE DocAccess.UserNo = 2000 )

问题是在 Exists Select 中,它不能将 Docs(位于 Docs.FileNo)识别为有效表。如果我将第二个 on 参数移到 where 子句,它会起作用,但我宁愿限制初始连接,而不是事后将它们过滤掉。

我可以通过几种方式解决这个问题,但这似乎是最好的。我在这里缺少什么吗?还是根本不允许?

4

3 回答 3

2

我认为这是您的数据库引擎的限制。在大多数数据库中,docs将在整个子查询的范围内——包括whereandin子句。

但是,您不必担心将特定子句放在哪里。SQL 是一种描述性语言,而不是一种过程语言。SQL 的目的是描述输出。SQL 引擎、解析器和编译器应该选择最佳的执行路径。并非总是如此。但是,将条件移到where子句中,不要担心。

于 2013-01-15T02:05:40.410 回答
0

我不清楚为什么您需要在子查询中加入 FileUsers?查询的目的和想法是什么(用简单的英语)?

无论如何,如果您确实需要加入 FileUsers,那么我建议使用内部连接并将第二个过滤器移动到 WHERE 条件。我认为您不能在子查询的 JOIN 条件中使用它——至少我以前从未见过它以这种方式使用过。我相信您只能通过 WHERE 子句进行关联。

于 2013-01-15T01:59:11.193 回答
0

您必须使用别名才能使其正常工作:

SELECT
  doc.* 
FROM 
  Docs doc
WHERE 
      doc.DocNo = 1000
  AND EXISTS (
SELECT 
  * 
FROM 
  DocAccess acc
LEFT OUTER JOIN 
  FileUsers usr
ON 
      usr.UserType = acc.UserTypeWithAccess 
  AND usr.FileNo   = doc.FileNo
WHERE 
  acc.UserNo = 2000
)

这也使得每个字段属于哪个表更加清晰(考虑在具有不同别名的同一查询中使用同一个表两次或多次)。

如果您只想将输出限制为一行,您可以使用TOP 1

SELECT TOP 1
  doc.* 
FROM 
  Docs doc
INNER JOIN
  FileUsers usr
ON  
  usr.FileNo = doc.FileNo
INNER JOIN
  DocAccess acc
ON
  acc.UserTypeWithAccess = usr.UserType
WHERE 
      doc.DocNo  = 1000
  AND acc.UserNo = 2000

当然,第二个查询与第一个查询有点不同(两个 JOINS 都是 INNER)。根据您的数据模型,您甚至可能会忽略该TOP 1查询。

于 2013-01-15T12:13:36.697 回答