1

I couldn't think of a good way to word the title, if anyone can come up with something better please feel free. Basically there is an old VB6 app that pulls data from a db that I have more or less completely restructured and gives the user a dump of all of the product information at once. So I need to do some inner joins to get all of these tables together. I know how to do basic inner joins but I am stuck on one detail. There are a few tables where there are multiple entries for each item. For example, the CrossReference table may have multiple cross reference numbers for an item, or it may only have one, or it may have none at all. Is it possible to have those placed dynamically into separate columns. so this:

Item         CrossReferenceNumber 
XXXXX        crossref1 
XXXXX        crossref2 
XXXXX        crossref3

could become this (after a join with some other tables):

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

But if there were no cross references, there would be no cross reference columns. Is something like that possible or am I dreaming?

Nick
  • 1,903
  • 2
  • 21
  • 40
  • 1
    Why would you do that - that's not normalized thinking, and most likely you should rethink the goal here. – Kerrek SB Jul 12 '11 at 16:11
  • 1
    Which DBMS? If SQL Server, check out the documentation on the PIVOT operator. Also see this question for an example of something similar: http://stackoverflow.com/questions/1343145/tsql-pivot-without-aggregate-function – Kilanash Jul 12 '11 at 16:14
  • @Kerrek, I just need the datatable to look like that, I'm not creating a sql table with it like that. The VB6 app spins through and just prints the column name and a value associated with it. I didn't write the thing I just have to maintain it. It used to be one giant completely non normalized table, so I am just sending it back something similar to what it used to be. I am not a VB6 developer and don't feel like messing with the code. – Nick Jul 12 '11 at 18:17
  • sorry for off-topic, but are there any chances for SO community to place some common answers to "rows to columns" questions into community wiki? – andbi Jul 20 '11 at 20:21

1 Answers1

1

Oracle 11g and Sql Server 2005+ both contain a pivot command that will accomplish what you want.

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

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

Otherwise you would need to build a dynamic sql statement to achieve this.

Edit - Here you go (SQL Server version).

/* 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 */
clyc
  • 2,420
  • 14
  • 15
  • Pivot still seems to require me to specify the columns. So I would have to say that CrossReference1, CrossReference2, CrossReference3 are in the results, the problem is, there could (in theory) be 20 cross references, or there could be 0. I need a way to only show relavant ones. – Nick Jul 12 '11 at 18:35
  • @nick, you never specified which dbms you're using. I have something that you can use if it's sql server – clyc Jul 12 '11 at 19:38
  • You mentioned that you may have a solution? – Nick Jul 14 '11 at 14:09
  • Thank you, no rush my friend! – Nick Jul 15 '11 at 00:46
  • @Nick, I didn't forget about you. I posted a sample solution for you. – clyc Jul 20 '11 at 20:03