根据group by,top 1 row和where case更新

时间:2018-02-05 14:05:12

标签: sql tsql greatest-n-per-group

我有一张表如下:
table select
这是此选择的结果:

http://localhost/users?fields=id,email&expand=profileAge

现在,我想要做的是:对于每个SELECT ParentID, ID, [Default], IsOnTop, OrderBy FROM [table] WHERE ParentID IN (SELECT ParentID FROM [table] GROUP BY ParentID HAVING SUM([Default]) <> 1) ORDER BY ParentID 组,将其中一行设置为默认值(ParentID),其中使用此逻辑选择行:
 如果组有一行[Default] = 1,则取此行,否则按IsOnTop = 1排序前1行。
关于如何在SQL中执行此操作,我完全无能为力,我有超过40个这样的组,因此我想请求您的帮助,最好是对您的查询进行一些解释。

3 个答案:

答案 0 :(得分:3)

只需在每个ParentID组中分配一个行号,即可稍微修改当前查询。行号分配的排序逻辑是IsOnTop值为1的记录首先出现,然后OrderBy列确定位置。我更新CTE的条件是只有每个ParentID组中的第一条记录被指定为Default值为1。

WITH cte AS (
    SELECT ParentID, ID, [Default], IsOnTop, OrderBy,
        ROW_NUMBER() OVER (PARTITION BY ParentID
                           ORDER BY IsOnTop DESC, OrderBy) rn
    FROM [table]
    WHERE ParentID IN (SELECT ParentID FROM [table]
                       GROUP BY ParentID HAVING SUM([Default]) <> 1)
)

UPDATE cte
SET [Default] = 1
WHERE rn = 1;

答案 1 :(得分:2)

可能会有更快的方法,但这就是我要做的。 首先创建一个CTE

首先,我们根据IsOnTop = 1创建一个CTE,在其中我们在ParentID上添加一个row_number。否则,它会根据OrderBy列选择第一行。

然后我们使用rownumber 1更新行。

WITH FindSoonToBeDefault AS (
     SELECT ParentID, ID, [Default], IsOnTop, OrderBy, row_number() OVER(PARTITION BY ParentID ORDER BY IsOnTop DESC, [OrderBy] ASC) AS [rn]
     FROM [table]
 WHERE ParentID IN (SELECT ParentID
     FROM [table]
     GROUP BY ParentID
     HAVING SUM([Default]) <> 1)
 ORDER BY ParentID
)
UPDATE FindSoonToBeDefault
SET [Default] = 1
WHERE [rn] = 1

在屏幕截图中,第12行将是默认值。 第13行不会。

答案 2 :(得分:0)

(1-IsOnTop)*OrderByIsOnTopOrderBy合并到一个结果中,该结果可以排名,以便最低值是您想要的值。使用派生表来确定每个ParentID的最低结果,然后JOIN来确定您的默认值。

UPDATE [table]
SET [Default] = 1
FROM [table]
INNER JOIN 
(
    SELECT ParentID, MIN((1-IsOnTop)*OrderBy) DefaultRank
    FROM [table]
    GROUP BY ParentID
) AS rankForDefault
ON rankForDefault.ParentID=[table].ParentID
AND rankForDefault.DefaultRank=(1-[table].IsOnTop)*[table].OrderBy