SQL通过翻转将2列向下移动

Posted

技术标签:

【中文标题】SQL通过翻转将2列向下移动【英文标题】:SQL Shifting 2 columns a row down with rollover 【发布时间】:2020-10-14 23:23:45 【问题描述】:

我目前正在尝试在 SQL Server 中操作一个表。

下表是一个例子:

Id  |  PrimaryId  |  PrimaryMail  |  SecondaryId  |  SecondaryMail
1.     1.        email1@something.  5.          email2@something
2.     2.        email3@something.  6.          email4@something
3.     3.        email5@something.  7.          email6@something
4.     4.        email7@something.  8.          email8@something

我希望它变成如下:

Id  |  PrimaryId  |  PrimaryMail  |  SecondaryId  |  SecondaryMail
1.     1.        email1@something.  6.          email4@something
2.     2.        email3@something.  7.          email6@something
3.     3.        email5@something.  8.          email8@something
4.     4.        email7@something.  5.          email2@something

我在这里发现了一个类似的问题,但这个人不想使用连接,而我真正想要的是翻转机制,它使第一行成为最后一行或最后一行成为第一行,具体取决于什么移动列的方向。

我已经有了以下代码,可以使列中的项目增加 1 行。但是最后一行目前保持不变,我丢失了第一行的数据。

--Calculate the height of the table
DECLARE @CouplesCount AS INT
SELECT @CouplesCount = COUNT(*) FROM Couples

--Shift the Secondary users down one row
UPDATE c1
SET c1.SecondaryId = c2.SecondaryId, c1.SecondaryMail = c2.SecondaryMail
FROM Couples c1 join
     Couples c2
     on c2.Id = c1.Id + 1
     WHERE c1.CouplesId <= @CouplesCount - 1

SELECT * FROM Couples

提前感谢任何可以帮助我的人。 p.s.我不能使用 mysql 代码

【问题讨论】:

如果表格多于两行,你要哪种逻辑呢?如果您可以用更多的行来扩展您的数据和结果,这可能会有所帮助。 我编辑了行数。我基本上希望它循环播放。 【参考方案1】:

如果您使用的 SQL Server 版本是 SQL Server 2012 或更高版本,则可以使用窗口函数LEADFIRST_VALUE

LEAD 从“下一个”行返回值(由ORDER BY 子句定义)。它将为最后一行返回NULL,因为那里没有“下一个”行。

所以,对于最后一行我们需要返回第一行,这可以通过FIRST_VALUE来完成。

样本数据

DECLARE @Couples TABLE (
    Id int, PrimaryId int, PrimaryMail nvarchar(100), 
    SecondaryId int, SecondaryMail nvarchar(100));

INSERT INTO @Couples VALUES
(1, 1, 'email1@something', 5, 'email2@something'),
(2, 2, 'email3@something', 6, 'email4@something'),
(3, 3, 'email5@something', 7, 'email6@something'),
(4, 4, 'email7@something', 8, 'email8@something');

查询

SELECT
    C.Id
    ,C.PrimaryId
    ,C.PrimaryMail
    ,ISNULL(LEAD(C.SecondaryId) OVER (ORDER BY C.Id),
        FIRST_VALUE(C.SecondaryId) OVER (ORDER BY C.Id))
    AS SecondaryId
    ,ISNULL(LEAD(C.SecondaryMail) OVER (ORDER BY C.Id),
        FIRST_VALUE(C.SecondaryMail) OVER (ORDER BY C.Id))
     AS SecondaryMail
FROM
    @Couples AS C
;

结果

+----+-----------+------------------+-------------+------------------+
| Id | PrimaryId |   PrimaryMail    | SecondaryId |  SecondaryMail   |
+----+-----------+------------------+-------------+------------------+
|  1 |         1 | email1@something |           6 | email4@something |
|  2 |         2 | email3@something |           7 | email6@something |
|  3 |         3 | email5@something |           8 | email8@something |
|  4 |         4 | email7@something |           5 | email2@something |
+----+-----------+------------------+-------------+------------------+

更新

如果您需要实际更改表本身,也很容易做到,只需将查询包装在 CTE 中并更新即可。

WITH
CTE
AS
(
    SELECT
        C.Id
        ,C.PrimaryId
        ,C.PrimaryMail
        ,C.SecondaryId
        ,C.SecondaryMail
        ,ISNULL(LEAD(C.SecondaryId) OVER (ORDER BY C.Id),
            FIRST_VALUE(C.SecondaryId) OVER (ORDER BY C.Id))
        AS NewSecondaryId
        ,ISNULL(LEAD(C.SecondaryMail) OVER (ORDER BY C.Id),
            FIRST_VALUE(C.SecondaryMail) OVER (ORDER BY C.Id))
         AS NewSecondaryMail
    FROM
        @Couples AS C
)
UPDATE CTE
SET
    SecondaryId = NewSecondaryId
    ,SecondaryMail = NewSecondaryMail
;

SELECT * FROM @Couples ORDER BY Id;

【讨论】:

非常感谢@Vladimir Baranov 的回答!可悲的是,我的水平仍然很低,以至于您看不到我的赞成票。 如果您觉得这个答案有用,您应该可以接受。获得足够的声望来投票应该很容易。您只需要 15 个。只需为某人的问题写一个好的答案并获得支持。或者对其他问题提出一些好的修改建议。

以上是关于SQL通过翻转将2列向下移动的主要内容,如果未能解决你的问题,请参考以下文章

向上或向下移动 HTML 表格单元格(不是行)

重力翻转

更改表中一行的主键(id)并将其他行向下移动

R方法通过将整个数据集向上移动一个小时/向下移动一个小时半年来将标准转换为夏令时?

pandas使用shift函数对数数据进行向上偏移(-1)或者向下偏移索引不移动,移动之后无值的赋值为NaN将原数据列与偏移后的数据列相加生成新的数据列

如何在 Oracle 表的列中向下移动值?