简体   繁体   English

SQL Server - 使用 ROW_NUMBER() OVER PARTITION 函数来设置值

[英]SQL Server - Using ROW_NUMBER() OVER PARTITION function to SET a value

Hi everyone thanks for taking some time to look into my question,大家好,感谢您花时间研究我的问题,

Background背景

I'm using the ROW_NUMER() function along with a PARTITION BY..ORDER BY statement to set a varchar value with an incrementing int value at the end of it for each of a value in one of my tables.我正在使用 ROW_NUMER() 函数和 PARTITION BY..ORDER BY 语句来设置一个 varchar 值,在它的末尾为我的一个表中的每个值设置一个递增的 int 值。

SELECT  component_module_id as component_module_id,
        component_property_id,
        'cf' + CAST(ROW_NUMBER() OVER (PARTITION BY component_module_id ORDER BY component_module_id) as VARCHAR) AS cf
FROM component_property

Here the 'cf' value goes from cf1-cfX for each component_module_id这里的“cf”值来自每个 component_module_id 的 cf1-cfX

示例查询输出

My Question我的问题

Whenever I attempt to use these cf values elsewhere, like saved in a temp table, other Ordering and Grouping statements change these values.每当我尝试在其他地方使用这些 cf 值时,例如保存在临时表中,其他排序和分组语句都会更改这些值。 It's like the statements to generate the 'cf' values are saved and not the 'cf' values themselves.这就像生成“cf”值的语句被保存而不是“cf”值本身。

After inserting the query above into a temp table #t -将上面的查询插入临时表后#t -

SELECT * FROM #t ORDER BY cf

I receive 'cf' values that start at cf1 and jump to cf10 and then cf100, with a range of cf values from cf1 to cf900... I should only be receiving values ranging from c1 to cf29.我收到的“cf”值从 cf1 开始,然后跳转到 cf10,然后是 cf100,cf 值的范围从 cf1 到 cf900……我应该只接收从 c1 到 cf29 的值。

My question here is - Why are the values in this column treated differently than any other normal value?我的问题是 - 为什么此列中的值与任何其他正常值的处理方式不同? Why is the ROW_NUMBER() OVER (PARTITION BY....)) calculation being passed to further queries down the line?为什么将 ROW_NUMBER() OVER (PARTITION BY....)) 计算传递给后续查询? (if that's actually what's happening). (如果这确实是正在发生的事情)。 And finally, how I can treat these 'cf' values like normal VARCHAR values and not have them change on me whenever I try to group or order by them.最后,我如何将这些 'cf' 值视为正常的 VARCHAR 值,并且在我尝试按它们分组或排序时不会改变它们。

Thanks for any help!谢谢你的帮助!

Update更新

I took the suggestion from Larnu,我接受了拉努的建议,

"Seems like you'd be better off just storing the int value, and using a (PERSISTED) computed column to concatenate your prefix and ROW_NUMBER value." “似乎你最好只存储 int 值,并使用(PERSISTED)计算列连接你的前缀和 ROW_NUMBER 值。”

and my 'cf' values are now appearing correctly after being sorted.并且我的“cf”值在排序后现在正确显示。 Thanks everyone marking as solved.感谢大家标记为已解决。

Try this尝试这个

SELECT  component_module_id,
        component_property_id,
        'cf' + CAST(cf) AS VARCHAR(10)
FROM    (
            SELECT  component_module_id,
                    component_property_id,
                    ROW_NUMBER() OVER (PARTITION BY component_module_id ORDER BY component_module_id) AS cf
            FROM    component_property
        ) a
ORDER BY component_module_id

The behaviour you are experiencing is because VARCHAR orders numbers by doing an alphabetical sort您遇到的行为是因为VARCHAR通过按字母顺序排序数字

You need to do the ordering using an INT and then do your concatenation at the end (by wrapping the original query in a sub-query您需要使用INT进行排序,然后在最后进行连接(通过将原始查询包装在子查询中

However, a better solution was suggested in the comments which is to only store numbers as INT and add the prefix using a computed column (or at the query level)但是,评论中提出了一个更好的解决方案,即仅将数字存储为INT并使用计算列(或在查询级别)添加前缀

如果你这样做,它会起作用

SELECT * FROM #t ORDER BY component_module_id, cast(replace(cf, 'cf', '') as int)

The issue is that you are both partitioning by and ordering by component_module_id .问题是您同时按component_module_id分区排序。 Within each partition, the ordering keys have the same value.在每个分区内,排序键具有相同的值。

Why does this matter?为什么这很重要? Sorting in SQL is NOT stable. SQL 中的排序不稳定。 That means that ties can be resolved either way.这意味着可以通过任何一种方式解决关系。 Run the query a second time, and you might get a different ordering (among the ties).再次运行查询,您可能会得到不同的排序(在关系中)。

The simple solution is to change the ordering to be stable, and you have just the column to do that component_property_id .简单的解决方案是将排序更改为稳定,并且您只有一列来执行该component_property_id I would also recommend using CONCAT() so you don't need any type conversions:我还建议使用CONCAT()以便您不需要任何类型转换:

SELECT component_module_id as component_module_id,
       component_property_id,
       CONCAT('cf',
              ROW_NUMBER() OVER (PARTITION BY component_module_id ORDER BY component_property_id)
             0 AS cf
FROM component_property

I should also note that your code uses VARCHAR with no length.我还应该注意,您的代码使用没有长度的VARCHAR This is a really bad idea in SQL Server.这在 SQL Server 中是一个非常糟糕的主意。 The default length varies by context and may not be big enough for certain values (although you don't have that problem in this case).默认长度因上下文而异,对于某些值可能不够大(尽管在这种情况下您没有这个问题)。

Update更新

I took the suggestion from Larnu,我接受了拉努的建议,

"Seems like you'd be better off just storing the int value, and using a (PERSISTED) computed column to concatenate your prefix and ROW_NUMBER value." “似乎你最好只存储 int 值,并使用(PERSISTED)计算列连接你的前缀和 ROW_NUMBER 值。”

and my 'cf' values are now appearing correctly after being sorted.并且我的“cf”值在排序后现在正确显示。 Thanks everyone marking as solved.感谢大家标记为已解决。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM