如何将多行中的特定字段“合并”到一个单行中的多个不同字段中?

时间:2013-02-16 23:05:00

标签: sql-server-2008 tsql

情况: 3个源表:

1。用户(包含唯一ID和用户特定属性,如firstNamegivenNameStreetAddress等)

2。 MigrationFeatures (包含唯一ID和Feature_Name

第3。 Link_Users_and_Features (包含来自UsersFeatures的唯一ID以及Status列(int))

在链接表中,对于每个用户,行数与Feature表中的行数完全相同,并且每个行(每个用户)只链接到一个Feature。每个链接行还包含一个状态值列,该列可以具有不同的值 - 根据特定用户的特定Feature的迁移状态。

目标

拥有一个完全动态的查询/ SP,为每个用户返回一行,并为该特定用户提供每个Feature的迁移状态 - 每个迁移状态列将根据来自的Feature_Name命名来自Feature表的相应Features。当我在Feature表中添加额外的Feature时,不必手动修改所需的查询代码。

提示:Feature表已经有一个插入触发器,它为每个用户创建了这个附加列,并且相关列上存在参照完整性,因此所有用户将始终拥有所有{的链接表中的所有相应行{1}}。

我为什么要这样做:

到目前为止,我有一个包含所有用户特定列(Features等)的表,以及所有迁移功能状态列(Name, givenName, StreetAddress,等),其中包含所有迁移状态数据所有用户。

不幸的是,这是完全静态的,每当我添加新的SIDhist migrated, homefolder migrated,时,我都必须修改这个主表。将来,技能较低的人员将使用底层系统,他们不会进入数据库代码或模式,只会将记录添加到FeatureFeature表中。

这里是创建用户DB的代码:

user

这里是创建Features表的代码:

CREATE TABLE [dbo].[Users](
        [Users_ID] [int] IDENTITY(1,1) NOT NULL,
        [FMOUser_givenName] [nvarchar](max) NULL,
        [FMOUser_sn] [nvarchar](max) NULL,
        [FMOUser_streetAddress] [nvarchar](max) NULL,
        [ExcludeFromMigration] [bit] NULL,
     CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED 
    (
        [Users_ID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    GO

创建链接表的代码:

CREATE TABLE [dbo].[Features](
    [Features_ID] [int] IDENTITY(1,1) NOT NULL,
    [Feature_Name] [nvarchar](max) NOT NULL
 CONSTRAINT [PK_Features] PRIMARY KEY CLUSTERED 
(
    [Features_ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

我已经研究过什么了?

我找到了以下示例:

http://www.dbforums.com/microsoft-sql-server/1673127-view-multiple-records-single-row.html

这确实将新列名称下的多行中的单个列放在一行中,但它不是动态的 - 意味着:它不会从{{1}的相应“功能”行中提取目标列名称}表也不能处理动态数量的CREATE TABLE [dbo].[link_Users__with__Features]( [link_Users__with__Features_ID] [int] IDENTITY(1,1) NOT NULL, [FMO_Users_ID] [int] NOT NULL, [Features_Migration_Core_ID] [int] NOT NULL, [StatusValue] [int] NOT NULL, [Description] [nvarchar](max) NULL, CONSTRAINT [PK_link_Users__with__Features] PRIMARY KEY CLUSTERED ( [link_Users__with__Features_ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]

由于我对T-SQL比较陌生,我失去了如何解决这一挑战。

由于这是我在堆栈溢出时的第一个问题,如果我错过了正式,请原谅我。请纠正我,我会做得更好: - )

提示:我已经提出了我的问题所提议的“重复”,但似乎没有一个甚至与我的问题略有匹配。

2 个答案:

答案 0 :(得分:0)

以下代码完成了我在初始问题中所要求的内容:(请注意我已经引入了一个额外的视图:view_Users_ _StatusValues,它们将用户,链接表和功能绑定在一起)

灵感来自:http://www.mssqltips.com/sqlservertip/2783/script-to-create-dynamic-pivot-queries-in-sql-server/

代码:

use [your_database]

-- *** Get the column names for the target 'table' out from the features table
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
SET @columns = N'';
SELECT @columns += N',' + QUOTENAME(Feature_Name)
  FROM (SELECT p.Feature_Name FROM dbo.Features AS p
  INNER JOIN dbo.link_Users__with__Features AS o
  ON p.Features_ID = o.Features_ID
  GROUP BY p.Feature_Name) AS x;

-- *** remove unneccessary, leading ',' ***
set @columns = STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '')
-- print @columns

-- *** Create the SQL code which will produce the correct output table ***
SET @sql = N'
select * from dbo.view_FMO_Users__and__StatusValues
pivot(
        max(StatusValue) -- use any aggregate function (needed for pivoting) 
        for Feature_Name in (' + @columns + ')) as FeatureStatusValue'

-- PRINT @sql;
EXEC sp_executesql @sql;

答案 1 :(得分:0)

我个人要注意的问题:如何从透视有意义的名称中给输出列:

(select 
            Betrieb = [200], IP = [310], port = [311]    -- Give friendly names to output columns
 from 

(select i.INTERFACEID, ioptions.OPTION_IDENTIFIER, ioptions.value from 
(tac.I_A_INTERFACE_OPTIONS ioptions join tac.G_M_INTERFACES i on i.INTERFACEID = ioptions.INTERFACEID)
 where (OPTION_IDENTIFIER=200 or OPTION_IDENTIFIER=310 or OPTION_IDENTIFIER=311) and i.TYPE = 700) 
  temp

pivot(
        max(value) -- use any aggregate function (needed for pivoting) 
        for OPTION_IDENTIFIER in (
        [310],[311],[200])
        ) as output
)