我能否在表格中逻辑地重新排序列?

104

如果我在 Microsoft SQL Server 上向表格添加一列,我能控制这个列在查询时的逻辑顺序吗?

我不想改变磁盘上列的物理布局,但是我希望尽可能按逻辑方式将列分组,以便像SQL Server Management Studio这样的工具方便地显示表格内容。

我知道我可以通过进入表格的“设计”模式并拖动列的顺序来实现这一点,但我希望能够在原始的SQL中进行排序,以便我可以从命令行执行排序脚本。


虽然回答有些晚了,但是看一下这个链接吧。http://blog.sqlauthority.com/2013/03/11/sql-server-how-to-add-column-at-specific-location-in-table/ - sqluser
请参考以下链接:https://dev59.com/w2855IYBdhLWcg3wViu3 和 https://dev59.com/DW435IYBdhLWcg3wlRMf。这些链接与SQL Server列的重新排序和在两个其他列之间添加列有关。 - Tim Abell
更多相关内容请参考:https://dev59.com/R3VD5IYBdhLWcg3wRpaX 和 http://dba.stackexchange.com/questions/18719/does-the-order-of-columns-in-a-tables-definition-matter - Tim Abell
另一个相关的问题是,当对SQL Server列进行排序时,性能和空间是否重要? - Tim Abell
微软连接:更改列顺序的ALTER TABLE语法(https://connect.microsoft.com/SQLServer/Feedback/Details/739788)- 响应通常是无用的WONTFIX。 - Tim Abell
9个回答

85

如果不创建新表,程序化地进行列重排是不安全的。

当您提交重新排序时,Enterprise Manager会创建一个新表,移动数据,然后删除旧表并将新表重命名为现有名称。

如果您想要特定顺序/分组的列而不改变它们的物理顺序,则可以创建一个视图,该视图可以是任何您想要的样子。


48
我认为这里所有人都没有意识到的是,尽管不是每个人都必须处理在全国甚至全球范围内安装了10、20或1000个相同软件系统的实例,但我们这些设计商业销售软件的人确实需要如此。因此,随着时间推移,我们会扩展系统,通过添加字段来扩展表以满足新的功能需求,并且当发现某些字段应该属于现有表时,将其加入现有表格中。因此,在十年的扩展、增长、添加字段等过程中,我们有时需要从设计、支持到挖掘原始数据/故障排除来调试新功能错误。如果您有30、40、50甚至90个字段的表格(即使在严格规范化的数据库中),那么不能在前几个字段中看到所需的主要信息将令人极度恼火。
我经常希望能够做到这一点,就是出于这个原因。但是,除非像SQL一样完全按照我的要求构建一个新表的创建脚本,编写插入脚本,然后删除所有现有约束、关系、键和索引等等,再将“新”表重命名为旧名称,然后读取所有这些键、关系、索引等等...... 除此之外,没有其他方法。
这不仅是繁琐、耗时,而且......再过五年,就需要再次进行这样的操作。它非常接近于值得这么大量的工作,然而关键是,我们需要这种能力的次数不会只有一次,因为我们的系统将继续成长、扩展并以设计添加字段的方式以奇怪的顺序进行。
大多数开发者从单个系统的角度考虑,该系统只服务于单个公司或非常具体的硬盒市场。在其市场空间中巨大进步的“现成”但显著的设计师和开发领袖将始终面临这个问题,并且将需要一种创造性的解决方案。如果有人有这种方法,这可以轻松地为我的公司节省十几个小时,而无需滚动或记住源数据表中“那个”字段位于何处。

1
我们曾经遇到同样的问题,并创建了一个存储过程来自动化此过程(重命名、创建新表、复制、重新创建所有外键、约束等)。您只需要传递表名和新列顺序即可。如果这实际上可以为您的公司节省数十个小时的工作时间,那么您应该投入时间编写类似的脚本。对我们来说,只需要大约2-3天就可以拥有一个稳定的脚本,我们通常使用它来重新排序列。它处理我们在SqlServer中使用的所有功能(例如部分索引、索引视图等),仅包含约400行代码。 - Andreas
5
我不知道为什么他们不能通过某种方式抽象出列布局。它不必物理上重新排列列!在SQL Server中,博士级别及以上的工程非常惊人。考虑到查询计划生成的复杂性、统计信息和索引,竟然还没有人站起来说“让我们只制作一个代表逻辑顺序的表。'FieldID Guid'、'OrderBy int'。完成了。然后SSMS或'SELECT *'使用它。如果你是完美的DBA并且不想要它,那就关掉它。非常令人沮丧。现在我的表已经足够大了,我无法再进行暴力破解。 - Simon_Weaver
我知道这是一个旧评论,但是在数据库项目中的Visual Studio会在您更改表模式并点击发布时自动创建用于物理列重新排序的SQL脚本。 - Muflix
1
所有这些真正需要的不是对引擎进行任何根本性的改变:我们只需要微软声明一个众所周知的“扩展属性”名称以用于逻辑列排序,并且当在编辑器/设计器中显示列时,SSMS和其他工具开始尊重那个扩展属性。[我已经为此提出了 SQL Server 功能请求 - 如果有足够的人点赞,他们最终将不得不停止忽视它] (https://feedback.azure.com/d365community /idea/ff4becca-c1b3-ec11-a81c-6045bd7d1bee) :) - Dai

6
当管理工具执行此操作时,它会创建一个临时表,将所有内容复制到该表中,删除原始表并重命名临时表。没有简单的等价T-SQL语句。
如果你不想这样做,你可以创建一个视图,按你想要的顺序排列列,并使用它?
编辑:被打败了!

5
如果我理解你的问题正确,你想要影响现有查询返回的列的顺序,对吗?
如果所有的查询都是用“SELECT * FROM TABLE”编写的,则它们将按SQL中的布局显示在输出中。
如果您的查询是使用“SELECT Field1,Field2 FROM TABLE”编写的,则它们在SQL中的排列顺序并不重要。

1
有一种方法,但仅限于查询本身的临时性。例如,
假设您有5个表。 表名为T_Testing
FirstName,LastName,PhoneNumber,Email和Member_ID
您希望它列出他们的ID,然后是姓氏,然后是名字,然后是电话,然后是电子邮件。
您可以根据选择来执行此操作。
Select Member_ID, LastName, FirstName, PhoneNumber, Email
From T_Testing

除此之外,如果您出于某种原因只想在名字前显示姓氏,也可以按照以下方式进行操作:
Select LastName, *
From T_Testing

如果您要使用Where或OrderBy函数,则需要将其标识为Table.Column,以确保正确执行操作。

例如:

Select LastName, *
From T_Testing
Order By T_Testing.LastName Desc

我希望这能有所帮助,因为我自己需要做这件事情,所以我找到了解决方法。

1
在这个查询语句 Select LastName, * From T_Testing 中,你会得到 LastName 两次。 - sqluser

1
  1. 将您现有的表格脚本化到查询窗口。
  2. 针对测试数据库运行此脚本(删除Use语句)。
  3. 使用SSMS进行所需的列更改。
  4. 单击生成更改脚本(默认情况下,最左侧和最底部的按钮栏上的图标)。
  5. 使用此脚本来操作您实际的表格。

该脚本实际上只是创建了一个带有所需列顺序的第二个表格,将所有数据复制到其中,删除原始表格,然后将次要表格重命名为原始表格。尽管这样做可以节省您自己编写脚本的时间,但它并没有提供解释。


1
无法更改列的顺序而不重新创建整个表。如果您只有几个数据库实例,可以使用SSMS进行此操作(选择表格并单击“设计”)。
如果您有太多实例需要手动处理,则应尝试使用此脚本: https://github.com/Epaminaidos/reorder-columns

1
  1. 在SSMS中以设计模式打开您的表:

    Table in SSMS in design mode

  2. 重新排列您的列:

    Table in SSMS in design mode with new column

    重要的是不要保存您的更改。

  3. 单击“生成更改脚本”按钮:

    Generate Change Script button

  4. 现在会打开一个窗口,其中包含应用此更改的脚本:

    Generated script

    从窗口中复制文本。

在这个例子中,它生成了以下代码:
/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_MyTable
    (
    Id int NOT NULL,
    Name nvarchar(30) NULL,
    Country nvarchar(50) NOT NULL
    )  ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_MyTable SET (LOCK_ESCALATION = TABLE)
GO
IF EXISTS(SELECT * FROM dbo.MyTable)
     EXEC('INSERT INTO dbo.Tmp_MyTable (Id, Name, Country)
        SELECT Id, Name, Country FROM dbo.MyTable WITH (HOLDLOCK TABLOCKX)')
GO
DROP TABLE dbo.MyTable
GO
EXECUTE sp_rename N'dbo.Tmp_MyTable', N'MyTable', 'OBJECT' 
GO
COMMIT

正如您所看到的,它所做的是:1)创建一个新的临时表,2)将数据复制到临时表中,3)删除原始表,4)将临时表重命名为原始表的名称。


0

可以使用SQL直接修改系统表来完成。例如,请看这里:

在中间添加新列 - 修改表

然而,除非绝对必要,否则我不建议玩弄系统表。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接