使用sql查询对记录进行重新排序(重写为单个查询)

时间:2018-10-02 03:22:43

标签: mysql sql

我有一个sliders表。

+----+-----+---------+
| id | pos | content |
+----+-----+---------+
| 1  | 0   | image   |
+----+-----+---------+
| 2  | 1   | image   |
+----+-----+---------+
| 3  | 2   | video   |
+----+-----+---------+
| 4  | 3   | video   |
+----+-----+---------+
| 5  | 4   | image   |
+----+-----+---------+

我想要此记录的顺序为:

  1. 图片
  2. 视频
  3. ...其他一切

当前,我在pos列中表示职位。按数字排列,其中0是第一个,最大是最后一个。

我需要使用一个查询来重新排列它,但是目前,我正在使用3个查询来完成此操作。

第一个是:UPDATE sliders SET pos = pos + 2

这将返回:

+----+-----+---------+
| id | pos | content |
+----+-----+---------+
| 1  | 2   | image   |
+----+-----+---------+
| 2  | 3   | image   |
+----+-----+---------+
| 3  | 4   | video   |
+----+-----+---------+
| 4  | 5   | video   |
+----+-----+---------+
| 5  | 6   | image   |
+----+-----+---------+

然后,我将找到第一个视频,以及第一个将其位置设置为第一和第二的图像。

UPDATE sliders SET pos = 0 WHERE id = (SELECT MIN(id) FROM sliders WHERE content='image')
UPDATE sliders SET pos = 1 WHERE id = (SELECT MIN(id) FROM sliders WHERE content='video')

这将返回:

+----+-----+---------+
| id | pos | content |
+----+-----+---------+
| 1  | 0   | image   |
+----+-----+---------+
| 2  | 2   | image   |
+----+-----+---------+
| 3  | 1   | video   |
+----+-----+---------+
| 4  | 5   | video   |
+----+-----+---------+
| 5  | 6   | image   |
+----+-----+---------+

我不介意是否有间隔,只要有序即可。

问题是,是否有其他方法可以做到这一点,如果可能的话,一个没有间隙或任何内容的查询?

预期输出:

+----+-----+---------+
| id | pos | content |
+----+-----+---------+
| 1  | 0   | image   |
+----+-----+---------+
| 2  | 2   | image   |
+----+-----+---------+
| 3  | 1   | video   |
+----+-----+---------+
| 4  | 3   | video   |
+----+-----+---------+
| 5  | 4   | image   |
+----+-----+---------+

如果没有其他方法,我想我可以坚持3个查询。

2 个答案:

答案 0 :(得分:1)

我认为这无法更新单个查询,因为我们应该知道min(pos),但应该更新pos
而且mysql不能使用with
因此,如果您可以进行查看,也许是可能的。

这是视图。
new_pos col是新职位。 (1.图片,2。视频,您不介意是否有差距...)

create view newSliders as (
select id,
       pos,
       case content when 'image' then case pos when (select min(pos) from sliders where content = 'image') then 0
                                               else pos+2
                                      end
                    when 'video' then case pos when (select min(pos) from sliders where content = 'video') then 1
                                               else pos++2
                                      end
       end as new_pos,
       content
  from sliders
)

这是更新单个查询。

update sliders
   set pos = (select new_pos from newSliders where id = sliders.id);

希望对您有帮助。

答案 1 :(得分:0)

这将在sql server中为您完成。您将不得不在mysql中调整over子句。

首先创建测试数据:

declare @t table(id int, pos int, content varchar(20))
insert @t values (1,0,'image')
,(2,1,'image')
,(3,2,'video')
,(4,3,'other')
,(5,4,'image')
select * from @t

id  pos content
1   0   image
2   1   image
3   2   video
4   3   other
5   4   image

使用row_number进行更新

;with t as (
    select id, content, pos,
    row_number() over(order by case content when 'image' then 1 when 'video' then 2 else 3 end,id) rn
    from @t
)
update t set pos=rn

结果:

select * from @t

id  pos content
1   1   image
2   2   image
3   4   video
4   5   other
5   3   image

如果您使用的是不支持CTE的旧版mysql,则此操作相同:

update t set pos=p.rn
from @t t
join (
    select id, content, pos,
    row_number() over(order by case content when 'image' then 1 when 'video' then 2 else 3 end,id) rn
    from @t
) p on p.id=t.id