在UPDATE查询中使用SELECT

14

如何在Microsoft Access 2007中使用SELECT查询的结果更新表格字段?

以下是SELECT查询的代码:

SELECT Min(TAX.Tax_Code) AS MinOfTax_Code
FROM TAX, FUNCTIONS

WHERE (((FUNCTIONS.Func_Pure)<=[Tax_ToPrice]) AND ((FUNCTIONS.Func_Year)=[Tax_Year]))

GROUP BY FUNCTIONS.Func_ID;

以下是更新查询语句:

UPDATE FUNCTIONS

 SET FUNCTIONS.Func_TaxRef = [Result of Select query]

如果你想做一些特别的事情,90% 的情况下都是一个 hack。请考虑它是否有意义。我希望你的数据库已经规范化了。看看这个问题:<a href="http://stackoverflow.com/questions/825458/update-query-from-a-lookup-query">this question</a>。 - the_drow
请查看问题“MySQL/SQL: Update with correlated subquery from the updated table itself”的答案,或许会有所帮助。 - Roee Adler
通常情况下,您可以在Access查询设计器中单击一个按钮将SELECT查询转换为UPDATE查询 - 当您不处于SQL视图时,工具栏中有一个“查询类型”按钮。尝试一下,它会处理任何语法要求。 - Tomalak
你的评论听起来像是个笑话。 - mammadalius
4
你看到后面有一个笑脸吗?我不习惯写跨越多行的玩笑评论。 - Tomalak
6个回答

21

看起来Access无法在更新查询中执行聚合操作。但是它可以在SELECT查询中执行聚合操作。因此,创建一个定义为以下内容的查询:

SELECT func_id, min(tax_code) as MinOfTax_Code
FROM Functions
INNER JOIN Tax 
ON (Functions.Func_Year = Tax.Tax_Year) 
AND (Functions.Func_Pure <= Tax.Tax_ToPrice) 
GROUP BY Func_Id

将其保存为“YourQuery”。现在我们必须解决另一个访问限制。更新查询不能操作查询,但它们可以操作多个表。因此,让我们使用“制作表”查询将查询转换为表:

SELECT YourQuery.* 
INTO MinOfTax_Code
FROM YourQuery

这将把视图的内容存储在名为MinOfTax_Code的表中。现在,您可以执行UPDATE查询:

UPDATE MinOfTax_Code 
INNER JOIN Functions ON MinOfTax_Code.func_id = Functions.Func_ID 
SET Functions.Func_TaxRef = [MinOfTax_Code].[MinOfTax_Code]

在Access中执行SQL有点勉强,我建议你考虑使用Sql Server Express Edition来完成你的项目!


7

我之前写过一篇关于Access/JET SQL相关的相关子查询限制的文章,并记录了SQL UPDATE连接多个表的语法。根据那些信息和一些快速测试,我认为在Access/JET中没有任何方法可以使用单个SQL UPDATE语句实现你想要的操作。如果可以的话,该语句将类似于:

UPDATE FUNCTIONS A
INNER JOIN (
  SELECT AA.Func_ID, Min(BB.Tax_Code) AS MinOfTax_Code
  FROM TAX BB, FUNCTIONS AA
  WHERE AA.Func_Pure<=BB.Tax_ToPrice AND AA.Func_Year= BB.Tax_Year
  GROUP BY AA.Func_ID
) B 
ON B.Func_ID = A.Func_ID
SET A.Func_TaxRef = B.MinOfTax_Code

或者,Access/JET有时会允许您将子查询保存为单独的查询,然后以更传统的方式在UPDATE语句中进行连接。因此,例如,如果我们将上面的SELECT子查询保存为名为FUNCTIONS_TAX的单独查询,则UPDATE语句将如下所示:

UPDATE FUNCTIONS
INNER JOIN FUNCTIONS_TAX
ON FUNCTIONS.Func_ID = FUNCTIONS_TAX.Func_ID
SET FUNCTIONS.Func_TaxRef = FUNCTIONS_TAX.MinOfTax_Code

然而,这仍然不起作用。
我认为使其生效的唯一方法是将最小Tax_Code值的选择和聚合移出带外。您可以使用VBA函数或更容易地使用Access DLookup函数来实现此目的。将上面的GROUP BY子查询保存到名为FUNCTIONS_TAX的单独查询中,并将UPDATE语句重写为:
UPDATE FUNCTIONS
SET Func_TaxRef = DLookup(
  "MinOfTax_Code", 
  "FUNCTIONS_TAX", 
  "Func_ID = '" & Func_ID & "'"
)

请注意,DLookup函数防止此查询在Access之外使用,例如通过JET OLEDB。此外,此方法的性能取决于您要针对多少行,因为子查询正在为每个FUNCTIONS行执行(因为它不再相关,这是整个过程的关键点)。祝好运!

1
+1 不错,DLookup(),即使对于大表也会很慢。顺便说一下,似乎Access UPDATE不允许在查询上进行连接,但它允许在表上进行连接(请参阅我的帖子)。Access = 奇怪。 - Andomar
1
@ewbi:你可能会对这篇知识库文章感兴趣,基于总计查询的更新查询失败(http://support.microsoft.com/kb/116142)。 - onedaywhen
Access还具有域聚合函数,如DAvgDMinDMaxDCount等,这些函数在这种情况下非常有用。 - Olivier Jacot-Descombes

1

我曾经遇到过类似的问题。我想在一个列中查找字符串,并将该值放入同一表格中的另一列中。下面的选择语句可以找到括号内的文本。

当我在Access中创建查询时,我选择了所有字段。在该查询的SQL视图中,我用括号内的字段替换了mytable.myfield,以便从中获取值。

SELECT Left(Right(OtherField,Len(OtherField)-InStr((OtherField),"(")), 
            Len(Right(OtherField,Len(OtherField)-InStr((OtherField),"(")))-1) 

我运行了一个制表查询。该制表查询具有所有字段,其中包含上述替换,并以INTO NameofNewTable FROM mytable结尾。


0

我想再添加一个使用VBA函数的答案,但它确实可以在一个SQL语句中完成任务。不过,它可能会比较慢。

UPDATE FUNCTIONS
SET FUNCTIONS.Func_TaxRef = DLookUp("MinOfTax_Code", "SELECT
FUNCTIONS.Func_ID,Min(TAX.Tax_Code) AS MinOfTax_Code
FROM TAX, FUNCTIONS
WHERE (((FUNCTIONS.Func_Pure)<=[Tax_ToPrice]) AND ((FUNCTIONS.Func_Year)=[Tax_Year]))
GROUP BY FUNCTIONS.Func_ID;", "FUNCTIONS.Func_ID=" & Func_ID)

0

这个管用吗?未经测试但应该能解决问题。

UPDATE FUNCTIONS
SET Func_TaxRef = 
(
  SELECT Min(TAX.Tax_Code) AS MinOfTax_Code
  FROM TAX, FUNCTIONS F1
  WHERE F1.Func_Pure <= [Tax_ToPrice]
    AND F1.Func_Year=[Tax_Year]
    AND F1.Func_ID = FUNCTIONS.Func_ID
  GROUP BY F1.Func_ID;
)

基本上,对于FUNCTIONS中的每一行,子查询确定最小当前税收代码并将FUNCTIONS.Func_TaxRef设置为该值。这是假设FUNCTIONS.Func_ID是主键或唯一键。


Access提示:操作必须使用可更新的查询。 - mammadalius
@mammadalius 添加了TAKE 2。看看是否有所不同。 - beach
谷歌搜索显示,“操作必须使用可更新的查询”可能与“数据库和/或包含数据库的文件夹上的写入权限”有关。您确定数据库不是只读的吗?检查访问文件以验证它不是只读的。由于语法错误,我将删除TAKE 2。 - beach
以下代码是否有效?基本上需要缩小范围以查看它在哪里出错。更新函数 SET Func_TaxRef = ( SELECT 1 ) - beach
不,这是我自己尝试过但没有结果的方法。以下是数据库方案 http://i44.tinypic.com/35l6hoj.jpg - mammadalius
4
ACE/Jet引擎不支持此语法。它有自己的专有UPDATE..JOIN语法。错误“操作必须使用可更新的查询”有点泛指,意思是“我不能这样做”。 - onedaywhen

0

我知道这个话题很老了,但我觉得我可以为它添加一些内容。

使用SQL在MS Access 2010中无法使用选择查询更新。我使用了Tomalak的建议来使它工作。我有一张截图,但显然我在这个网站上太新手了,无法发布它。

我能够使用查询设计工具完成此操作,但即使我正在查看确认成功的更新查询,Access也不能向我显示使其发生的SQL。因此,我无法仅使用SQL代码使其工作。

我创建并保存了一个单独的选择查询。在查询设计工具中,我添加了要更新的表和我保存的选择查询(我将唯一键放入选择查询中,以便它们之间有联系)。正如Tomalak所建议的那样,我将查询类型更改为“更新”。然后,我只需选择要更新的字段(并指定表),在“更新到”字段中输入我导入的选择查询中的字段名称即可。

这种格式成功地更新了原始表。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接