SQL Server 2008 UPDATE 语句 WHERE 子句优先级

发布于 2024-11-28 14:44:32 字数 1645 浏览 4 评论 0原文

我编写了以下查询:

UPDATE king_in
SET IN_PNSN_ALL_TP_CNTRCT_CD = IN_PNSN_ALL_TP_CNTRCT_CD + '3'
WHERE COALESCE(IN_PNSN_ALL_TP_CNTRCT_TX, '') <> ''
        AND CHARINDEX('3', IN_PNSN_ALL_TP_CNTRCT_CD) = 0

它检查某个字段中是否有值,如果有,则将 3 放入相应的字段中(如果该字段中还没有 3)。当我运行它时,出现字符串或二进制数据将被截断的错误。该字段是 VARCHAR(3),表中的某些行已经包含 3 个字符,但我实际上通过 WHERE 过滤器进行更新的行的 MAX LEN 为 2,所以我完全感到困惑为什么 SQL Server 向我抛出截断错误。所以我将 UPDATE 语句更改为:

UPDATE king_in
SET IN_PNSN_ALL_TP_CNTRCT_CD = k.IN_PNSN_ALL_TP_CNTRCT_CD + '3'
FROM king_in k
        INNER JOIN
                     (
                        SELECT ki.row_key,
                                in_sqnc_nb
                        FROM king_in ki
                                INNER JOIN King_Ma km
                                    ON ki.Row_Key = km.Row_Key
                                INNER JOIN King_Recs kr
                                    ON km.doc_loc_nb = kr.ACK_ID
                        WHERE CHARINDEX('3', IN_PNSN_ALL_TP_CNTRCT_CD) = 0
                                AND COALESCE(IN_PNSN_ALL_TP_CNTRCT_TX, '') <> ''
                      ) a
            ON k.Row_Key = a.Row_Key 
                AND k.in_sqnc_nb = a.insr_sqnc_nb

并且它工作正常,没有错误。

因此,基于此,当执行不带 FROM 子句的 UPDATE 语句时,SQL Server 在根据 WHERE 子句过滤记录之前,会在内部执行并运行 SET 语句。这就是为什么我收到截断错误,因为即使我想要更新的记录少于 3 个字符,但表中的某些行在该字段中包含 3 个字符,并且无法将“3”添加到其中一行的末尾,它引发了错误。

所以在所有这些之后,我有一些问题。

1)为什么?是否有特定的 DBMS 原因导致 SQL Server 在应用 SET 语句之前不会过滤结果集?

2) 这是否只是我一直以来从未学过的有关 SQL 的已知知识?

3) SQL Server 中是否有设置可以更改此行为?

提前致谢。

I wrote the following query:

UPDATE king_in
SET IN_PNSN_ALL_TP_CNTRCT_CD = IN_PNSN_ALL_TP_CNTRCT_CD + '3'
WHERE COALESCE(IN_PNSN_ALL_TP_CNTRCT_TX, '') <> ''
        AND CHARINDEX('3', IN_PNSN_ALL_TP_CNTRCT_CD) = 0

It checks to see if a field has a value in it and if it does it puts a 3 in a corresponding field if there isn't a 3 already in it. When I ran it, I got a string or binary data will be truncated error. The field is a VARCHAR(3) and there are rows in the table that already have 3 characters in them but the rows that I was actually doing the updating on via the WHERE filter had a MAX LEN of 2 so I was completely baffled as to why SQL Server was throwing me the truncation error. So I changed my UPDATE statement to:

UPDATE king_in
SET IN_PNSN_ALL_TP_CNTRCT_CD = k.IN_PNSN_ALL_TP_CNTRCT_CD + '3'
FROM king_in k
        INNER JOIN
                     (
                        SELECT ki.row_key,
                                in_sqnc_nb
                        FROM king_in ki
                                INNER JOIN King_Ma km
                                    ON ki.Row_Key = km.Row_Key
                                INNER JOIN King_Recs kr
                                    ON km.doc_loc_nb = kr.ACK_ID
                        WHERE CHARINDEX('3', IN_PNSN_ALL_TP_CNTRCT_CD) = 0
                                AND COALESCE(IN_PNSN_ALL_TP_CNTRCT_TX, '') <> ''
                      ) a
            ON k.Row_Key = a.Row_Key 
                AND k.in_sqnc_nb = a.insr_sqnc_nb

and it works fine without error.

So it appears based on this that when doing an UPDATE statement without a FROM clause that SQL Server internally goes through and runs the SET statement before it filters the records based on the WHERE clause. Thats why I was getting the truncation error, because even though the records I wanted to update were less than 3 characters, there were rows in the table that had 3 characters in that field and when it couldn't add a '3' to the end of one of those rows, it threw the error.

So after all of that, I've got a handful of questions.

1) Why? Is there a specific DBMS reason that SQL Server wouldn't filter the result set before applying the SET statement?

2) Is this just a known thing about SQL that I never learned along the way?

3) Is there a setting in SQL Server to change this behavior?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

若有似无的小暗淡 2024-12-05 14:44:32

1 - 可能是因为您的条件无法使用 SARG - 也就是说,它们无法使用索引。如果查询优化器确定执行表扫描速度更快,它将继续对所有行运行。当您像此处那样筛选应用于该字段的函数时,这种情况尤其可能发生。

2 - 是的。优化器会做它认为最好的事情。您可以通过使用括号强制执行 WHERE 子句的评估顺序来解决此问题,但在您的示例中,我认为这没有帮助,因为无论如何它都会强制进行表扫描。

3 - 不,您需要更改数据或逻辑以允许使用索引。如果您真的需要过滤字段中是否存在某个字符,它可能应该是它自己的列和/或者您应该更好地规范该特定数据位。

针对您的特定实例的解决方法是添加 WHERE LEN(IN_PNSN_ALL_TP_CNTRCT_CD) WHERE LEN(IN_PNSN_ALL_TP_CNTRCT_CD) 3 也是如此。

1 - Likely because your criteria are not SARGable - that is, they can't use an index. If the query optimizer determines it's faster to do a table scan, it'll go ahead and run on all the rows. This is especially likely when you filter on a function applied to the field like you do here.

2 - Yes. The optimizer will do what it thinks it best. You can get around this somewhat by using parentheses to force an evaluation order of your WHERE clause but in your example I don't think it would help since it forces a table scan regardless.

3 - No, you need to alter your data or your logic to allow indexes to be used. If you really really need to filter on existence of a certain character in a field, it probably should be it's own column and/or you should normalize that particular bit of data better.

A workaround for your particular instance would be to add a WHERE LEN(IN_PNSN_ALL_TP_CNTRCT_CD) < 3 as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文