【问题标题】:Dynamically display rows as columns将行动态显示为列
【发布时间】:2011-10-03 18:58:00
【问题描述】:

我想不出一个好的标题来表达,如果有人能想出更好的东西,请随意。基本上有一个旧的 VB6 应用程序可以从我或多或少完全重组的数据库中提取数据,并立即为用户提供所有产品信息的转储。所以我需要做一些内部连接来把所有这些表放在一起。我知道如何进行基本的内部连接,但我被困在一个细节上。有几个表,其中每个项目都有多个条目。例如,CrossReference 表可能有多个项目的交叉引用编号,或者它可能只有一个,或者它可能根本没有。是否可以将这些动态放置到单独的列中。所以 这个:

Item         CrossReferenceNumber 
XXXXX        crossref1 
XXXXX        crossref2 
XXXXX        crossref3

可能会变成这样(在与其他一些表连接之后):

Item  BasePart Size   CrossReferenceNumber1  CrossReferenceNumber2  CrossReferenceNumber3
XXXX  XXXX     Large  crossref1              crossref2              crossref3

但如果没有交叉引用,就不会有交叉引用列。这样的事情可能吗?还是我在做梦?

【问题讨论】:

  • 你为什么要这样做——这不是正常的思维方式,你很可能应该在这里重新考虑目标。
  • 哪个 DBMS?如果是 SQL Server,请查看 PIVOT 运算符的文档。另请参阅此问题以获取类似示例:stackoverflow.com/questions/1343145/…
  • @Kerrek,我只需要数据表看起来像那样,我不会用它创建一个 sql 表。 VB6 应用程序旋转并仅打印列名和与其关联的值。我没有写我只需要维护它的东西。它曾经是一个巨大的完全非标准化的表格,所以我只是将它送回类似于以前的东西。我不是 VB6 开发人员,不想乱写代码。
  • 抱歉跑题了,但是 SO 社区是否有机会将“行到列”问题的一些常见答案放入社区 wiki?

标签: sql sql-server-2008 dynamic inner-join


【解决方案1】:

Oracle 11g 和 Sql Server 2005+ 都包含一个可以完成您想要的操作的数据透视命令。

http://www.orafaq.com/wiki/PIVOT

http://msdn.microsoft.com/en-us/library/ms177410.aspx

否则您需要构建动态 sql 语句来实现此目的。

编辑 - 给你(SQL Server 版本)。

/* Begin Set up of test data */
IF EXISTS (SELECT 1 from sys.tables WHERE name = N'Item')
    DROP TABLE Item
GO

IF EXISTS (SELECT 1 from sys.tables WHERE name = N'CrossReference')
    DROP TABLE CrossReference
GO


CREATE TABLE Item
(
    Item        varchar(20),
    BasePart    varchar(20),
    Size        varchar(20)
);

CREATE Table CrossReference 
(
    Item        varchar(20),
    CrossReferenceNumber    varchar(20)
);

INSERT INTO Item VALUES ('item1', 'b1', 'Large');
INSERT INTO Item VALUES ('item2', 'bxx1', 'Large');
INSERT INTO Item VALUES ('item3', 'bddf1', 'Small');
INSERT INTO Item VALUES ('item4', 'be3f1', 'Small');
INSERT INTO Item VALUES ('item5', 'b13vx1', 'Small');

INSERT INTO CrossReference VALUES( 'item1', 'crossRef1')
INSERT INTO CrossReference VALUES('item1', 'crossRef2')
INSERT INTO CrossReference VALUES('item1', 'crossRef3')
INSERT INTO CrossReference VALUES('item1', 'crossRef4')
INSERT INTO CrossReference VALUES('item2', 'crossRef1')
INSERT INTO CrossReference VALUES('item2', 'crossRef1')
INSERT INTO CrossReference VALUES('item3', 'crossRef1')
INSERT INTO CrossReference VALUES('item4', 'crossRef2')
INSERT INTO CrossReference VALUES('item5', 'crossRef5')
INSERT INTO CrossReference VALUES('item5', 'crossRef1')
INSERT INTO CrossReference VALUES('item5', 'crossRef2')
INSERT INTO CrossReference VALUES('item5', 'crossRef3')
/* End of test data setup */

/* Begin of actual query */
DECLARE @xRefs VARCHAR(2000),
        @query VARCHAR(8000)

SELECT @xRefs = STUFF((SELECT DISTINCT '],[' + ltrim(CrossReferenceNumber)
                        FROM CrossReference
                        ORDER BY '],[' + ltrim(CrossReferenceNumber)
                        FOR XML PATH('')
                       ), 1, 2, '') + ']'

SET @query = 
    'SELECT * 
     FROM   Item i
            INNER JOIN 
            (
                SELECT * 
                FROM
                (
                    SELECT Item, CrossReferenceNumber
                    FROM CrossReference
                ) t
                PIVOT   (MAX(CrossReferenceNumber) FOR CrossReferenceNumber IN (' + @xRefs + ')) as pvt

            ) xRefs
                ON i.Item = xRefs.Item
     ORDER BY i.Item'

EXECUTE (@query)
/* end */

【讨论】:

  • Pivot 似乎仍然需要我指定列。所以我不得不说结果中有 CrossReference1、CrossReference2、CrossReference3,问题是,(理论上)可能有 20 个交叉引用,或者可能有 0 个。我需要一种只显示相关的方法。跨度>
  • @nick,您从未指定您使用的 dbms。如果是 sql server,我有一些你可以使用的东西
  • 您提到您可能有解决方案?
  • 谢谢你,我的朋友别着急!
  • @Nick,我没有忘记你。我为您发布了一个示例解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-25
  • 2012-08-31
  • 1970-01-01
  • 2017-03-14
相关资源
最近更新 更多