Swap values for two rows in the same table in SQL Server

后端 未结 8 1968
北海茫月
北海茫月 2020-12-17 14:59

I want to swap the values from two rows in a table. I have the rows IDs of the two rows. Is there any query to do that? Here is an example. Before the query I have this:

相关标签:
8条回答
  • 2020-12-17 15:05

    None of the above examples is practical ... It should look like the following update section:

    /*******************************************************************************/
    /*  DATA TABLE IS PREPARING                                                    */
    /*******************************************************************************/
    IF EXISTS (SELECT TOP 1 * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TEST' AND TABLE_SCHEMA = 'dbo')
    DROP TABLE [dbo].[TEST];
    
    CREATE TABLE [dbo].[TEST](
      [ID]       int           IDENTITY(1,1) NOT NULL,
      [Name]     varchar(50)   NULL,
      [Surname]  varchar(50)   NULL,
      [AGE]      int           NULL,
      CONSTRAINT [PK_TEST] PRIMARY KEY CLUSTERED 
        ( [ID] ASC ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    /*******************************************************************************/
    /*  INSERTING TEST VALUES                                                      */
    /*******************************************************************************/
    INSERT INTO dbo.TEST (Name, Surname, AGE)
    SELECT 'Sevim'        , 'PARLAYAN' , 36   UNION ALL
    SELECT 'Uğur'         , 'PARLAYAN' , 41   UNION ALL
    SELECT 'Berkan Cahit' , 'PARLAYAN' , 17   UNION ALL
    SELECT 'Miray Çağla'  , 'PARLAYAN' , 6    ;
    
    SELECT * FROM dbo.TEST ORDER BY ID;
    
    
    -- At this point maybe the trigger can be disabled...
    
    /*******************************************************************************/
    /*  I'm swapping Uğur and Sevim rows (So, rows into 1 and 2 do swapping )...   */
    /*******************************************************************************/
    UPDATE  TT
    SET     TT.Name     = ZZZ.Name
         ,  TT.Surname  = ZZZ.Surname
         ,  TT.AGE      = ZZZ.AGE
    FROM     dbo.TEST as TT
    JOIN     (
               SELECT TOP 1 * FROM dbo.TEST WHERE ID = 2 /* Big key value first     */  UNION ALL
               SELECT TOP 1 * FROM dbo.TEST WHERE ID = 1 /* Then small key value... */
             ) as ZZZ on ZZZ.ID in (1, 2)
    WHERE   TT.ID in (1, 2) ;
    
    -- At this point maybe the trigger can be activated...
    
    SELECT * FROM dbo.TEST ORDER BY ID
    
    0 讨论(0)
  • 2020-12-17 15:06

    Simple update works:

    UPDATE myTable
    SET 
    col1 = CASE WHEN col1 = 1 THEN 5 ELSE 1 END,
    col2 = CASE WHEN col2 = 2 THEN 6 ELSE 2 END,
    col3 = CASE WHEN col3 = 3 THEN 7 ELSE 3 END 
    

    Result: row values are swapped.

    0 讨论(0)
  • 2020-12-17 15:12

    I had a similar issue recently I had a column for ordering the output and wanted to allow moving the order around. I was looking for the answer and ran across this question. This didn't sufficiently answer my particular query but maybe my solution will help others.

    I had my database look like so

    Table:Order_Table

    Index_Column,Order_Column,Text
    1           ,1           ,"Second Test text"
    2           ,2           ,"First Test text"
    

    I wanted to be able to swap them around using pdo in php. Ultimately I found a way to do it with one SQL query

    UPDATE `Order_Table` AS o 
    INNER JOIN (SELECT `Index_Column`, `Order_Column` FROM `Order_Table` 
    WHERE `Index_Column` IN (:Index1,:Index2)) 
    AS t ON o.`Index_Column` <> t.`Index_Column` 
    SET o.`Order_Column` = t.`Order_Column` 
    WHERE o.`Index_Column` IN (:Index1,:Index2)
    
    0 讨论(0)
  • 2020-12-17 15:13

    If it's just one value that has to be swapped between two rows :

    UPDATE task t1 SET ordre = (SELECT ordre FROM task t2 WHERE t1.id <> t2.id AND id IN (26,25)) WHERE id IN (26,25)
    
    0 讨论(0)
  • 2020-12-17 15:18

    If you only need to swap a couple of rows, then yeah, you can brute force it with tailor-made case statements and join statements like in the other answers. But if you need to operate on many rows, that's going to be a pain.

    A Simple, Scalable Solution

    WITH map AS (
        SELECT *
        FROM (VALUES
            (1, 2),  -- Here's an example of swapping two rows:
            (2, 1),  -- 1 <- 2,  2 <- 1
    
            (3, 4),  -- Here's an example of rotating three rows:
            (4, 5),  -- 3 <- 4,  4 <- 5,  5 <- 3
            (5, 3),
    
            (6, 7)   -- Here's an example of just copying one row to another: 3 <- 5
        ) AS a (destID, srcID)
    )
    UPDATE destination
    SET
        ColumnA = source.ColumnA,
        ColumnB = source.ColumnB,
        ColumnC = source.ColumnC
    FROM
        SomeTable AS destination
        JOIN map ON map.destID = destination.ID
        JOIN SomeTable AS source ON source.ID = map.srcID
    

    Notes

    • You can do two-row swaps, many-row swaps, and copies. It's flexible.
    • Specify as many destination/source row pairs as needed. Only destination rows will be updated.
    • Specify the columns you want to be copied over. Only those columns will be updated.
    • There's no temporary table to clean up.
    • It's easy to reuse since the row IDs are listed in a single, obvious place.
    0 讨论(0)
  • 2020-12-17 15:20

    If you want to swap values from one row to the other for two known IDs try something like this:

    --need to store the original values
    SELECT
        *,CASE WHEN id=123 then 987 ELSE 123 END AS JoinId
        INTO #Temp
        FROM YourTable
        WHERE ID in (123,987)
    
    --swap values
    UPDATE y
        SET col1=t.col1
            ,col2=t.col2
        FROM YourTable        y
            INNER JOIN #Temp  t ON y.id =t.JoinId
        WHERE ID in (123,987)
    
    0 讨论(0)
提交回复
热议问题