如何明智地将列增加一组

Posted

技术标签:

【中文标题】如何明智地将列增加一组【英文标题】:How to increment column by one group wise 【发布时间】:2020-06-03 06:58:22 【问题描述】:

我有一张表叫productLocation,它的数据结构如下,SQLFiddle

+--------------+-------------+-----------+
| FkLocationId | FkProductId | SortValue |
+--------------+-------------+-----------+
| 1            | 100         | 0         |
+--------------+-------------+-----------+
| 1            | 101         | 0         |
+--------------+-------------+-----------+
| 1            | 102         | 0         |
+--------------+-------------+-----------+
| 1            | 103         | 2         |
+--------------+-------------+-----------+
| 1            | 104         | 1         |
+--------------+-------------+-----------+
| 1            | 105         | 3         |
+--------------+-------------+-----------+
| 2            | 100         | 0         |
+--------------+-------------+-----------+
| 2            | 101         | 0         |
+--------------+-------------+-----------+
| 2            | 102         | 0         |
+--------------+-------------+-----------+
| 2            | 103         | 1         |
+--------------+-------------+-----------+
| 2            | 104         | 3         |
+--------------+-------------+-----------+
| 2            | 105         | 2         |
+--------------+-------------+-----------+
| 3            | 100         | 0         |
+--------------+-------------+-----------+
| 3            | 101         | 0         |
+--------------+-------------+-----------+
| 3            | 102         | 0         |
+--------------+-------------+-----------+
| 3            | 103         | 1         |
+--------------+-------------+-----------+
| 3            | 104         | 2         |
+--------------+-------------+-----------+

每个位置都有自己的产品排序顺序。但有些产品有 0 作为SortValue 现在我需要编写一个查询来将SortValue 更新为,

如果我考虑一个位置,FkLocationId = 1

+--------------+-------------+-----------+
| FkLocationId | FkProductId | SortValue |
+--------------+-------------+-----------+
| 1            | 100         | 0         |
+--------------+-------------+-----------+
| 1            | 101         | 0         |
+--------------+-------------+-----------+
| 1            | 102         | 0         |
+--------------+-------------+-----------+
| 1            | 103         | 2         |
+--------------+-------------+-----------+
| 1            | 104         | 1         |
+--------------+-------------+-----------+
| 1            | 105         | 3         |
+--------------+-------------+-----------+

在上面的数据表中,可以看到FkProductId = 100,101,1020作为SortValue。我需要按FkProductId 降序更新其sortValue。我需要更新它的样子

+--------------+-------------+-----------+
| FkLocationId | FkProductId | SortValue |
+--------------+-------------+-----------+
| 1            | 100         | 3         |
+--------------+-------------+-----------+
| 1            | 101         | 2         |
+--------------+-------------+-----------+
| 1            | 102         | 1         |
+--------------+-------------+-----------+

并且还将之前的SortValue一一更新。

那么完整的输出应该是,

+--------------+-------------+-----------+
| FkLocationId | FkProductId | SortValue |
+--------------+-------------+-----------+
| 1            | 100         | 3         |
+--------------+-------------+-----------+
| 1            | 101         | 2         |
+--------------+-------------+-----------+
| 1            | 102         | 1         |
+--------------+-------------+-----------+
| 1            | 103         | 5         |
+--------------+-------------+-----------+
| 1            | 104         | 4         |
+--------------+-------------+-----------+
| 1            | 105         | 6         |
+--------------+-------------+-----------+

这可能吗?我真的很困惑,请帮我解决这个问题。谢谢

更新:

假设我有另一个表作为产品。其数据结构如下,

+-----------+-----------+
| ProdcutId | SortValue |
+-----------+-----------+
| 100       | 0         |
+-----------+-----------+
| 101       | 0         |
+-----------+-----------+
| 107       | 0         |
+-----------+-----------+
| 108       | 1         |
+-----------+-----------+
| 109       | 2         |
+-----------+-----------+
| 110       | 6         |
+-----------+-----------+
| 111       | 5         |
+-----------+-----------+
| 112       | 4         |
+-----------+-----------+
| 113       | 3         |
+-----------+-----------+

我也需要为这张桌子做同样的事情,我该怎么做

预期输出:

+-----------+-----------+
| ProdcutId | SortValue |
+-----------+-----------+
| 100       | 3         |
+-----------+-----------+
| 101       | 2         |
+-----------+-----------+
| 107       | 1         |
+-----------+-----------+
| 108       | 4         |
+-----------+-----------+
| 109       | 5         |
+-----------+-----------+
| 110       | 9         |
+-----------+-----------+
| 111       | 8         |
+-----------+-----------+
| 112       | 7         |
+-----------+-----------+
| 113       | 6         |
+-----------+-----------+

【问题讨论】:

Sql fiddle 有一个漂亮的小按钮,叫做“Text to DDL”。请使用它和edit 你的问题与proper 示例数据。 请向我们展示您的尝试,以便我们提供帮助。 @ZoharPeled 我用 SQL fiddle 先生sqlfiddle.com/#!18/b1997/1更新了问题@ 【参考方案1】:

以下是一个示例查询,您可以使用 CTE 检查并使用相同的逻辑进行更新过程-

DEMO HERE

重要提示:更新是一个有风险的过程,您应该先尝试使用您的测试数据。

WITH CTE
AS
(
    SELECT *,
    (
        SELECT COUNT(*) 
        FROM #Temp B 
        WHERE B.FkLocationId = A.FkLocationId
        AND SortValue = 0
    ) Zero_Count,
    -- The above Zero count is a simple count of rows with 0
    -- for a specific FkLocationId. This is for adding to other 
    -- rows where there are already value in column SortValue. The logic
    -- is simple, the number of row with 0 in column SortValue, 
    -- should be add to existing value where there is value not equal 0.
    ROW_NUMBER() OVER (PARTITION BY FkLocationId ORDER BY SortValue ASC, FkProductId DESC) RN
    -- ROW_NUMBER is simply creating the Number you should replace 0 by.
    -- As you are looking for 1 to start for the MAX FkProductId with 0,
    -- I applied DESC order on that column
    FROM #Temp A
) 

UPDATE A
SET A.SortValue = 
CASE 
    WHEN A.SortValue = 0 THEN B.RN 
    -- RN is created in such way, so that you can directly 
    -- Replace your value in column SortValue by RN if SortValue = 0 
    ELSE A.SortValue + B.Zero_Count
    -- IF SortValue contains already value > 0, 
    -- You need to just increment the value with Number 
    -- of rows is there with value 0. I have calculated that value
    -- by a sub query in the CTE you can check.
END
FROM  #Temp A
INNER JOIN CTE B ON A.FkLocationId = B.FkLocationId
AND A.FkProductId = B.FkProductId


SELECT * FROM #Temp

只需在我使用过 #temp 的地方使用您的“table_name”

【讨论】:

@Adam 如果真的有帮助,请接受答案:) 如果你能在查询中解释每个部分就更好了。 @Adam,我在脚本中添加了一些 cmets。检查是否有帮助。如果需要更多说明,我可以解释。 先生,我在我的问题中添加了另一部分作为更新你能解释一下我怎样才能为那张桌子做同样的事情。所以很容易为我提出一个想法。请给我一个更新部分的答案 您也可以使用相同的查询。唯一的区别是这次您没有 FkLocationId 列。只需避免我使用列 FkLocationId 作为参考的查询部分。【参考方案2】:
with cte as
(select FkLocationId, FkProductId, SortValue,
ROW_NUMBER() over(partition by FkLocationId order by sortvalue,FkProductId desc) new_sort_value
from productLocation where FkLocationId =1  --and SortValue =0
)

update pl SET
pl.SortValue = c.new_sort_value
from productLocation pl inner join cte c
on pl.FkLocationId = c.FkLocationId and pl.FkProductId = c.FkProductId

Select * from productLocation where FkLocationId =1 order by FkProductId

我采用的方法的核心是基于row_number的窗口函数,它将fkproductid上的数据按sortvalue和fkproductid降序排序。

涉及到 2 个查询,虽然可以做单个查询,但为简单起见,我使用了公用表表达式 (cte)

从查询一派生的 CTE 在第二个更新查询中用作连接表。

我已经为自我探索留下了很多东西,请记住必须根据集合进行思考。

【讨论】:

以上是关于如何明智地将列增加一组的主要内容,如果未能解决你的问题,请参考以下文章

如何动态地将列添加到 DataFrame?

如何以最佳性能明智地将右表中的列加入左列表

如何使用 MySqlParameter 有条件地将列设置为其默认值?

如何在AngularJS网格中有条件地将列更改为文本框?

如何使用 DB2 sql 代码动态地将列转置为表的行,其中列可能会随着时间的推移而增加且无需更改代码?

从另一个 DataFrame 添加一列