PostgreSQL,高级交换

时间:2013-08-15 10:24:08

标签: postgresql

我在同一个表here的行中交换某些数据时得到了一些帮助 不幸的是,我不能在实践中应用这些解决方案,因为我代表的问题太弱,所以提供的解决方案我无法得到预期的结果 为此,我改进了示例并使其易于使用,同时尝试更有可能我的具体情况,希望这篇文章不会被视为重复或冒犯。

创建表格:

DROP TABLE IF EXISTS kalksad1;

CREATE TABLE kalksad1(
kalk_id     int PRIMARY KEY,
brkalk      integer, 
brred       integer, 
description text
);

INSERT INTO kalksad1 VALUES
  (12, 2, 5, 'text index 12 doc 2 row 5'),
  (26, 2, 1, 'text index 26 doc 2 row 1'),
  (30, 2, 2, 'text index 30 doc 2 row 2'),
  (32, 4, 1, 'text index 32 doc 4 row 1'),
  (36, 1, 1, 'text index 36 doc 1 row 1'),
  (37, 1, 2, 'text index 37 doc 1 row 2'),
  (38, 5, 1, 'text index 38 doc 5 row 1'),
  (39, 5, 2, 'text index 39 doc 5 row 2'),
  (42, 2, 3, 'text index 42 doc 2 row 3'),
  (43, 2, 4, 'text index 43 doc 2 row 4'),
  (46, 3, 1, 'text index 46 doc 3 row 1'),
  (47, 3, 2, 'text index 47 doc 3 row 2');

需要什么?

进行查询,仅在相同'brkalk'的'brred'列中交换数字。
“brred”和“brkalk”都是通过程序在外部定义的 例如,我们将采用brkalk = 2,brred = 3 这意味着我们应该只在WHEN brkalk = 2的行中交换brred值。

以下是两个提供的解决方案,可作为参考 如果它们起作用,这两种解决方案都会很有用 第一个因为它可以交换行而不管顺序和距离,第二个因为它只与第一行上下交换最常见的需求。 第二个解决方案的问题是我不知道它是什么交换但是交换第一行和最后一行而不是第3行和第2行 那应该修复。

在新情况下,第一个查询根本不起作用,所以如果有人可以修复它,我想。它可以用于交换行,无论外部参数的“方向”如何,例如交换行4和1。

只是澄清一下,当我说“交换行”时,我的意思是在'brred'列中交换属于同一'brkalk'的值(在这种情况下为2)。

首先查询:

    UPDATE kalksad1 dst 
        SET brred=src.brred 
        FROM kalksad1 src 
        WHERE src.brkalk='2' 
        AND dst.kalk_id IN(2,3) 
        AND src.kalk_id IN(2,3) 
        AND dst.kalk_id <> src.kalk_id;

第二次查询

    WITH cte1 AS (
        SELECT row_number() OVER(ORDER BY kalk_id ASC) AS row_num, kalk_id, brred 
        FROM kalksad1
        WHERE kalk_id >= 3 ORDER BY kalk_id LIMIT 2
        ) 
    UPDATE kalksad1 AS t 
        SET brred = COALESCE(c2.brred, t.brred) 
        FROM cte1 AS c1 
        LEFT OUTER JOIN cte1 AS c2 ON c2.row_num <> c1.row_num 
        WHERE t.kalk_id = c1.kalk_id AND brkalk='2';

要查看数据,最好使用:

SELECT * FROM kalksad1 WHERE brkalk='2' ORDER BY brred;

我希望有人根据描述的需要修复上层查询以使其可行,或提供可用于此类交换的新解决方案。

所以,感谢Roman和wildplasser,我得到了这个......

Private Function swap_row(ByVal doc_num As Integer, ByVal src_row As Integer, ByVal dest_row As Integer) As Integer

    Dim affected As Integer = 0
    Dim conn As NpgsqlConnection = getConnection()
    Dim t As NpgsqlTransaction = conn.BeginTransaction()

    Using cmd As New NpgsqlCommand( _
        "UPDATE " & myKalkSadTable & " AS dst SET brred = src.brred " & _
        "FROM " & myKalkSadTable & " AS src " & _
        "WHERE(src.brkalk = " & doc_num.ToString & ") " & _
        "AND dst.brkalk = " & doc_num.ToString & " " & _
        "AND dst.brred IN (" & src_row.ToString & "," & dest_row.ToString & ") " & _
        "AND src.brred IN (" & src_row.ToString & "," & dest_row.ToString & ") " & _
        "AND src.kalk_id <> dst.kalk_id", conn)

        affected = CInt(cmd.ExecuteNonQuery())
        cmd.Dispose()
    End Using

    If affected = 2 then t.Commit()
    t.Dispose()
    conn.Close()
    conn.Dispose()

    Return affected
End Function

Private Sub DataGridView2_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles DataGridView2.KeyDown

    If e.Control And e.KeyCode = Keys.Left Then
        swap_row(kalkbr, selected_row, selected_row - 1)
        Refreshlist(kalkbr)
    End If

    If e.Control And e.KeyCode = Keys.Right Then
        swap_row(kalkbr, selected_row, selected_row + 1)
        Refreshlist(kalkbr)
    End If

...等......

1 个答案:

答案 0 :(得分:1)

对于第一个,您必须在dst和src上过滤brkalk:

update kalksad1 as dst set
    brred = src.brred 
from kalksad1 as src 
where
    src.brkalk = 2 and dst.brkalk = 2 and
    dst.brred in (2,3) and
    src.brred in (2,3) and
    src.kalk_id <> dst.kalk_id;

sql fiddle demo

我认为第二个太复杂了,当我认为你想用精确的ID和下一个交换行时,我已经创建了它