将单个更新查询中的多个列更新为sql server 2008中的自动堆栈列值

时间:2013-08-27 12:36:48

标签: sql sql-server sql-server-2008

我有一个表,它在Stack1,Stack2,Stack3,Stack4,Stack5和Stack6列中存储代码。如果用户删除任何这些堆栈中的一个代码,我必须自动包装剩余的代码,以便可以将间隙移动到最后一个。

enter image description here

对于Eg: - 在上面的截图中,用户已经删除了Stack2中的代码,现在我希望stack3中的代码进入Stack2,Stack4中的代码进入Stack3。以下是预期的产出:

enter image description here

请提出解决方案。

3 个答案:

答案 0 :(得分:1)

虽然规范化当前架构会很好,但这里有一种更新表的可能性:

;with piv as (
    -- Unpivot the data for ordering
    select csCode, lane, [row], 1 as ordinal, stack1 as stack from MyTable
    union all select csCode, lane, [row], 2 as ordinal, stack2 as stack from MyTable
    union all select csCode, lane, [row], 3 as ordinal, stack3 as stack from MyTable
    union all select csCode, lane, [row], 4 as ordinal, stack4 as stack from MyTable
    union all select csCode, lane, [row], 5 as ordinal, stack5 as stack from MyTable
    union all select csCode, lane, [row], 6 as ordinal, stack6 as stack from MyTable
)
, sort as (
    -- Order the stacks
    select *
        , row_number() over (partition by csCode, lane, [row] order by case when stack = '' then 1 else 0 end, ordinal) as stackNumber
    from piv
)
update a
    set stack1 = (select stack from sort where csCode = a.csCode and lane = a.lane and [row] = a.[row] and stackNumber = 1)
    , stack2 = (select stack from sort where csCode = a.csCode and lane = a.lane and [row] = a.[row] and stackNumber = 2)
    , stack3 = (select stack from sort where csCode = a.csCode and lane = a.lane and [row] = a.[row] and stackNumber = 3)
    , stack4 = (select stack from sort where csCode = a.csCode and lane = a.lane and [row] = a.[row] and stackNumber = 4)
    , stack5 = (select stack from sort where csCode = a.csCode and lane = a.lane and [row] = a.[row] and stackNumber = 5)
    , stack6 = (select stack from sort where csCode = a.csCode and lane = a.lane and [row] = a.[row] and stackNumber = 6)
from MyTable a

我正在使用几个CTEs来取消堆叠并对堆栈进行排序,然后使用相关子查询更新每个堆栈。您可以在整个表上运行它,或者提供适当的where子句以获得更好的性能。

这里有几个假设:

  • 您的“空白”数据是空字符串。如果您可能有空格和空值,请对其进行清理或使用ltrim(rtrim(coalesce(stack1, ''))) != ''
  • 之类的内容进行限定
  • csCode, lane, row生成一个候选键(唯一且没有一个为null)。如果csCode本身是主键,那么在任何此查询中都不需要lanerow

答案 1 :(得分:-1)

Case语句和Coalesce的某些组合可以帮助您实现目标。如果没有所有边缘案例变体,提供精确的代码是很困难的,但 psuedo示例是您的可能的样子:

UPDATE MyTable 
       Stack1 =  Coalesce (Stack1, Stack2, Stack3, Stack4, Stack5, Stack6),
       Stack2 =  Coalesce (Stack2, Stack3, Stack4, Stack5, Stack6)
       Stack3 =  Coalesce (Stack3, Stack4, Stack5, Stack6),
       Stack4 =  Coalesce (Stack4, Stack5, Stack6),
       Stack5 =  Coalesce (Stack5, Stack6),
       Stack6 =  Stack6
WHERE ID = @SomeIDValue

话虽如此,您的问题仍然存在数据库设计问题。根据你的共享内容,我宁愿在子表中堆叠。

CodeParent
  * codeParentID
  * csCode
  * line
  * row

CodeStackChild
  * codeStackChildId  (int identity)
  * codeParentID
  *  stackValue

使用上面的表设置,您可以删除堆栈中间的值,只需移动而无需移动值。要按顺序获取值,只需查询CodeStackChild表并在select语句中使用ROW_NUMBER() OVER (Partition by codeParentID)

答案 2 :(得分:-1)

你必须在更新后编写一个触发器,如果​​堆栈列为空则将递归检查,如果是这种情况,则开始用stack [n]更新stack [n-1],很好问题你问。 / p>

此致

Ashutosh Arya