如何根据另一行sql server的值更新行

时间:2017-06-07 14:07:17

标签: sql sql-server

我想知道基于另一行更新行的最佳方法是什么,比方说我有这样的表:

ID   |   NAME    |  VALUE  |
----------------------------
 1   |   a  |   10   |
 2   |   b  |  NULL  |
 3   |   c  |  NULL  |
 4   |   d  |  NULL  |
 5   |   a  |   10   |
 6   |   b  |  NULL  |
 7   |   c  |  NULL  |
 8   |   d  |  NULL  |
 9   |   a  |  NULL  |
.
.
.

现在我需要一个UPDATE查询,将所有名称= d的行与name = a的行进行比较,如果name = a的行的值= 10,则name = d的行将得到value = 10然后使用name = a的行将设置为NULL,否则将设置为NULL。就像我需要按顺序在行的值(a到d,b到c,c到d,d到a)之间切换。在每4行(a,b,c,d)中,总共只有一行,该值不为空。

我希望很清楚。 谢谢!

1 个答案:

答案 0 :(得分:1)

我认为我并不完全理解你在这里想要达到的目标,但是这里有一些事情要开始讨论:

--Create sample data
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
    DROP TABLE #temp;
CREATE TABLE #temp (ID INT, NAME VARCHAR(50), [VALUE] INT);
INSERT INTO #temp SELECT 1, 'a', 10;
INSERT INTO #temp SELECT 2, 'b', NULL;
INSERT INTO #temp SELECT 3, 'c', NULL;
INSERT INTO #temp SELECT 4, 'd', NULL;
INSERT INTO #temp SELECT 5, 'a', 10;
INSERT INTO #temp SELECT 6, 'b', NULL;
INSERT INTO #temp SELECT 7, 'c', NULL;
INSERT INTO #temp SELECT 8, 'd', NULL;
INSERT INTO #temp SELECT 9, 'a', NULL;

所有这一切都是为了交换a和d,如果a中有值:

WITH Best AS (
    SELECT NAME, MAX([VALUE]) AS MAXVALUE FROM #temp GROUP BY NAME)
UPDATE
    t
SET
    [VALUE] = 
        CASE 
            WHEN t.NAME = 'a' AND b.MAXVALUE IS NOT NULL THEN NULL
            WHEN t.NAME = 'd' AND b.MAXVALUE IS NOT NULL THEN b.MAXVALUE 
        END
FROM
    #temp t
    CROSS JOIN Best b 
WHERE
    t.NAME IN ('a', 'd')
    AND b.NAME = 'a';

SELECT * FROM #temp;

完成后,我可以看到所有值都已移至d行。但这并不能解决b到c,c到d等问题。这有点像你想要的吗?

现在看起来你实际上需要分别处理每组四行,所以这可能会更好吗?

WITH Groups AS (
    SELECT ID, (ID - 1) / 4 AS group_id, NAME, [VALUE] FROM #temp),
Best AS (
    SELECT group_id, NAME, MAX([VALUE]) AS MAXVALUE FROM Groups GROUP BY group_id, NAME)
UPDATE
    t
SET
    [VALUE] = 
        CASE 
            WHEN t.NAME = 'a' AND b.MAXVALUE IS NOT NULL THEN NULL
            WHEN t.NAME = 'd' AND b.MAXVALUE IS NOT NULL THEN b.MAXVALUE 
        END
FROM
    #temp t
    INNER JOIN Groups g ON g.ID = t.ID
    INNER JOIN Best b ON b.group_id = g.group_id
WHERE
    t.NAME IN ('a', 'd')
    AND b.NAME = 'a';

这是给你的一个新查询,现在我终于想到我明白应该做什么了。首先,这是我对你真正想要的东西的理解:

  • 您拥有按ID排序的数据;
  • 数据分为4组,从“a”开始,然后是“b”,然后是“c”,然后是“d”;
  • 对于每组4个项目,找到具有非NULL值的单个项目;
  • 向前移动这个,即如果a值是,则将其移至b等
  • d值再次向后移动;
  • 每个小组独立于其他小组。

我创建了一组略有不同的数据,以显示这在实践中有效:

--Create sample data
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
    DROP TABLE #temp;
CREATE TABLE #temp (ID INT, NAME VARCHAR(50), [VALUE] INT);
INSERT INTO #temp SELECT 1, 'a', 10;
INSERT INTO #temp SELECT 2, 'b', NULL;
INSERT INTO #temp SELECT 3, 'c', NULL;
INSERT INTO #temp SELECT 4, 'd', NULL;
INSERT INTO #temp SELECT 5, 'a', NULL;
INSERT INTO #temp SELECT 6, 'b', NULL;
INSERT INTO #temp SELECT 7, 'c', NULL;
INSERT INTO #temp SELECT 8, 'd', 5;
INSERT INTO #temp SELECT 9, 'a', NULL;
INSERT INTO #temp SELECT 10, 'b', 90;
INSERT INTO #temp SELECT 11, 'c', NULL;
INSERT INTO #temp SELECT 12, 'd', NULL;

...这是我修改过的查询:

WITH Groups AS (
    SELECT 
        (ID - 1) / 4 AS group_id,
        ID, 
        NAME, 
        [VALUE] 
    FROM 
        #temp),
Best AS (
    SELECT 
        group_id, 
        ID,
        NAME,
        [VALUE]
    FROM 
        Groups
    WHERE
        [VALUE] IS NOT NULL)
UPDATE
    t
SET
    [VALUE] = 
        CASE 
            WHEN t.NAME = 'a' AND b.NAME = 'a' THEN NULL
            WHEN t.NAME = 'a' AND b.NAME = 'd' THEN b.[VALUE]
            WHEN t.NAME = 'b' AND b.NAME = 'b' THEN NULL
            WHEN t.NAME = 'b' AND b.NAME = 'a' THEN b.[VALUE]
            WHEN t.NAME = 'c' AND b.NAME = 'c' THEN NULL
            WHEN t.NAME = 'c' AND b.NAME = 'b' THEN b.[VALUE]
            WHEN t.NAME = 'd' AND b.NAME = 'd' THEN NULL
            WHEN t.NAME = 'd' AND b.NAME = 'c' THEN b.[VALUE]
        END
FROM
    #temp t
    INNER JOIN Groups g ON g.ID = t.ID
    INNER JOIN Best b ON b.group_id = g.group_id;

所以我的数据就像这样开始:

ID  NAME    VALUE
1   a   10
2   b   NULL
3   c   NULL
4   d   NULL
5   a   NULL
6   b   NULL
7   c   NULL
8   d   5
9   a   NULL
10  b   90
11  c   NULL
12  d   NULL

...当我运行UPDATE查询时:

ID  NAME    VALUE
1   a   NULL
2   b   10
3   c   NULL
4   d   NULL
5   a   5
6   b   NULL
7   c   NULL
8   d   NULL
9   a   NULL
10  b   NULL
11  c   90
12  d   NULL

如果我再次运行查询,那么一切都会再移动一步:

ID  NAME    VALUE
1   a   NULL
2   b   NULL
3   c   10
4   d   NULL
5   a   NULL
6   b   5
7   c   NULL
8   d   NULL
9   a   NULL
10  b   NULL
11  c   NULL
12  d   90

如果这仍然不是您想要的,那么要么在第一次/第二次迭代后显示您认为值应该是什么,要么在之前提出一个新的 - >以你的问题为例。

希望这将是最后的尝试:D

WITH Groups AS (
    SELECT 
        (ID - 1) / 4 AS group_id,
        ID, 
        NAME, 
        [VALUE] 
    FROM 
        #temp),
Best AS (
    SELECT 
        group_id, 
        ID,
        NAME,
        [VALUE]
    FROM 
        Groups
    WHERE
        [VALUE] IS NOT NULL)
UPDATE
    t
SET
    [VALUE] = 
        CASE 
            --a to d
            WHEN t.NAME = 'd' AND b.NAME = 'a' THEN b.[VALUE]

            --b to c
            WHEN t.NAME = 'c' AND b.NAME = 'b' THEN b.[VALUE] 

            --c to d (seems wrong?)
            WHEN t.NAME = 'd' AND b.NAME = 'c' THEN b.[VALUE]

            --d to a
            WHEN t.NAME = 'a' AND b.NAME = 'd' THEN b.[VALUE]

            --Set the moving item to NULL
            WHEN t.NAME = b.NAME THEN NULL
        END
FROM
    #temp t
    INNER JOIN Groups g ON g.ID = t.ID
    INNER JOIN Best b ON b.group_id = g.group_id;
相关问题