简体   繁体   English

如何在T-SQL中实现这一点?

[英]How do I pivot this in T-SQL?

How do I get this: 我如何得到这个:

entityid    name                 stringvalue
----------- -------------------- --------------------
1           ShortDescription     Coal
1           LongDescription      BlackCoal
1           ShortDescription     Gold
1           LongDescription      WhiteGold
1           ShortDescription     Steel
1           LongDescription      StainlessSteel

To become this: 要成为这个:

entityid    ShortDescription     LongDescription
----------- -------------------- --------------------
1           Coal                 BlackCoal
1           Gold                 WhiteGold
1           Steel                StainlessSteel

The code I have so far is: 到目前为止,我的代码是:

    select *
from (select entityid, cast(name as nvarchar(20)) as name, cast(stringvalue as nvarchar(20)) as stringvalue from metapropertyvalue) as d
pivot
(
    max(stringvalue)
    for [name] in ([ShortDescription],[LongDescription])
)
as p

Many thanks everyone, 非常感谢大家,

Matt. 马特

将表的布局放在一边,为了做您想做的事情,您不应该使用PIVOT,您需要为此的子查询。

The pivot keyword is for aggregation use pretty much exclusively. pivot关键字几乎完全用于聚合。 You'll likely have to do this manually via subqueries. 您可能必须通过子查询手动执行此操作。

That aside, your table layout is a really bad idea. 这且不说,你的表格布局是一个非常糟糕主意。 I've done this before, I know lots of other people that have done this before, it does NOT scale well. 我这样做过,我知道很多之前已经这样做了其他人的,它不能很好地扩展。 The biggest problem is that you can't properly define indices on your data. 最大的问题是您无法在数据上正确定义索引。 You should seriously consider just changing the table directly to your "pivoted" format as that's a proper relational style for it anyways. 您应该认真考虑将表直接更改为“透视”格式,因为无论如何这都是一种合适的关系样式。

Assuming that your DBRM can't be changed, this is the closest I can get after a several workarounds: 假设您的DBRM无法更改,这是我通过以下几种解决方法可以获得的最接近的结果:

select TOP 1 Id
    , LEFT(ShortDescription, LEN(ShortDescription) - 1) as ShortDescription
    , LEFT(LongDescription, LEN(LongDescription) - 1) as LongDescription
from (
    select Entity_Id as Id
            , (
                select StringValue + N', ' as [text()]
                    from MyEntities
                    where [Name] LIKE N'ShortDescription'
                    FOR XML PATH(N'')
            ) as ShortDescription
            , (
                select StringValue + N', ' as [text()]
                    from MyEntities
                    where [Name] LIKE N'LongDescription'
                    FOR XML PATH(N'')
            ) as LongDescription
        from MyEntities
) e

Which will result in output: 这将导致输出:

Id | ID | ShortDescription | 简短说明| LongDescription 详细描述

1 | 1 | Coal, Gold, Steel | 煤炭,黄金,钢铁| BlackCoal, WhiteGold, StainlessSteel 黑煤,白金,不锈钢

And I doubt this is functional, though I don't know your situation. 而且我怀疑这是否有用,尽管我不知道您的情况。

Only consider doing so if you manage to format the data before display to the GUI or something like that. 仅当您设法在显示到GUI或类似的东西之前格式化数据时,才考虑这样做。

By the way, the PIVOT stuff and such aggregation will only work when the data consists of numbers. 顺便说一下,只有当数据由数字组成时,PIVOT填充和此类聚合才起作用。 There would have been other ways to achieve this desired result if your [Name] and StringValue columns would have been of numerics. 如果您的[Name]StringValue数字,则可能会有其他方法来实现此期望的结果。

On the other hand, we're facing a design smell here. 另一方面,我们在这里面临设计异味。

Instead of designing a table like you did and always have to "pivot" it and do some complex code to retrive the information from it, in addition to always mention in the [Name] column whether it is a ShortDescription or a LongDescription, I would recommend the following to design the table the way you want data for output, as it is the normality, if I may say so. 除了总是在[Name]列中提及它是ShortDescription还是LongDescription之外,除了像您一样设计表并始终“旋转”表并执行一些复杂的代码以从表中检索信息之外,如果可以这样说,建议您按照以下说明以希望数据输出的方式设计表,因为这是正常现象。

IF OBJECT_ID(N'MyEntitiesTable') IS NOT NULL
    DROP TABLE MyEntitiesTable
GO

CREATE TABLE MyEntitiesTable (
    EntityId int IDENTITY(1, 1) NOT NULL PRIMARY KEY
    ShortDescription nvarchar(10) NOT NULL
    LongDescription nvarchar(50) NOT NULL
)
GO

insert into MyEntities (ShortDescription, LongDescription) values (N'Coal', N'BlackCoal')
GO
insert into MyEntities (ShortDescription, LongDescription) values (N'Gold', N'WhiteGold')
GO
insert into MyEntities (ShortDescription, LongDescription) values (N'Steel', N'WhiteSteel')
GO

This way, all you will be required to write as a query is the following: 这样,您将需要编写的所有内容如下:

select EntityId
        , ShortDescription
        , LongDescription
    from MyEntitiesTable

As for the EntityId field, if you absolutely want it to be always the number 1, then you can omit the IDENTITIY(1, 1) PRIMARY KEY thing within the table creation. 至于EntityId字段,如果您绝对希望它始终是数字1,则可以在表创建中省略IDENTITIY(1, 1) PRIMARY KEY However, I strongly recommend you let it there as this defines your primary key, and no table within your model should have no primary key. 但是,强烈建议您在此放置它,因为它定义了主键,并且模型中的任何表都不应有主键。

The reason for this prefered approach is that for each description you have to add to your data table, you will have to perform two INSERTs statements. 采用这种首选方法的原因是,对于必须添加到数据表中的每个描述,您将必须执行两个INSERTs语句。 This is overkilling the transactions against your database, plus, making it very hard to exploit, as you can see with your current situation. 正如您在当前情况中所看到的那样,这使数据库中的事务变得过分杀伤,而且使利用变得非常困难。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM