Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
loydall
Starting Member
33 Posts |
Posted - 2009-04-15 : 06:51:10
|
| Hi - lets say I have a table with the following data:id | fieldName--------------1 | Name2 | Age3 | Location4 | GenderAnd then I have a second table: FKfieldId | FieldValue | UserId--------------------------------1 | John | 12 | 34 | 13 | London | 14 | M | 11 | Sally | 22 | 31 | 23 | New York | 24 | F | 2So - you can see that the values from table 2 are based on the fields defined in table 1.What I want is to be able to select from table 1 to generate a table with the correct number of columns based on the number of records and then populate those columns with data from table 2 - so the resulting select would generate:Name | Age | Location |Gender-------------------------------------------John 34 London M Sally 31 New York F Any idea how I do this? |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2009-04-15 : 06:59:11
|
Yes. Use dynamic SQL. E 12°55'05.63"N 56°04'39.26" |
 |
|
|
loydall
Starting Member
33 Posts |
Posted - 2009-04-15 : 07:12:28
|
quote: Originally posted by Peso Yes. Use dynamic SQL. E 12°55'05.63"N 56°04'39.26"
Thanks - can you expand on that a little? Cheers. |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2009-04-15 : 07:27:39
|
[code]CREATE TABLE #Table1 ( id INT, fieldName VARCHAR(20) )INSERT #Table1SELECT 1, 'Name' UNION ALLSELECT 2, 'Age' UNION ALLSELECT 3, 'Location' UNION ALLSELECT 4, 'Gender'CREATE TABLE #Table2 ( FKfieldId INT, FieldValue VARCHAR(20), UserId INT )INSERT #Table2SELECT 1, 'John', 1 UNION ALLSELECT 2, '34', 1 UNION ALLSELECT 3, 'London', 1 UNION ALLSELECT 4, 'M', 1 UNION ALLSELECT 1, 'Sally', 2 UNION ALLSELECT 2, '31', 2 UNION ALLSELECT 3, 'New York', 2 UNION ALLSELECT 4, 'F', 2DECLARE @List VARCHAR(MAX), @pivot VARCHAR(MAX)SELECT @List = COALESCE(@List, 'SELECT p.UserID') + ',p.[' + CAST(id AS VARCHAR(11)) + '] AS ' + QUOTENAME(fieldName)FROM #Table1ORDER BY idSELECT @pivot = 'FROM #Table2 PIVOT (MAX(FieldValue) FOR FKFieldId IN ('SELECT @pivot = @pivot + QUOTENAME(id) + ','FROM #Table1ORDER BY IDSELECT @pivot = LEFT(@pivot, LEN(@pivot) - 1) + ')) AS p'EXEC (@List + @Pivot)DROP TABLE #Table1, #Table2[/code] E 12°55'05.63"N 56°04'39.26" |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2009-04-15 : 07:31:28
|
Adn then this code to run the stored procedure above from a viewEXEC master..sp_addlinkedserver @server = 'loopback', @srvproduct = '', @provider='SQLNCLI', @datasrc = 'phbgpela\sql2008'GOCREATE VIEW vwTestASSELECT *FROM OPENQUERY(loopback, 'EXEC my_sp_above')GOSELECT *FROM vwTestGODROP VIEW vwTestGOEXEC master..sp_dropserver @server = 'loopback'GO E 12°55'05.63"N 56°04'39.26" |
 |
|
|
madhivanan
Premature Yak Congratulator
22864 Posts |
|
|
loydall
Starting Member
33 Posts |
Posted - 2009-04-15 : 09:25:30
|
| Thanks,I've tried that code and it works exactly as I want it to - odd thing is, when I apply it to the actual tables I'm using I get:UserId Web Size CoName CoDescr-------------------------------------------------2103 NULL NULL Bobs Cars NULL2103 NULL NULL NULL We sell Cars2104 NULL NULL John's Computers NULL2104 NULL NULL NULL We sell computers2105 www.dfg.com NULL NULL NULL2105 NULL 1 - 500 NULL NULLSo - I can't seem to get it to generate just 1 row per userId - you can see that we have a value for user 2103 for the CoName and that creates a row and then another row is created for CoDescr..Like I say - your code works fine- it's just when I move it over to my existing tables...Hmm.. Any ideas? |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2009-04-15 : 09:42:20
|
Post your ACTUAL code for the stored procedure. Maybe something happens during your transformation to real world tables? E 12°55'05.63"N 56°04'39.26" |
 |
|
|
loydall
Starting Member
33 Posts |
Posted - 2009-04-15 : 09:51:49
|
| CREATE TABLE [dbo].[TF_CustomFields_CustomFields]( [FieldId] [int] IDENTITY(1,1) NOT NULL, [TableId] [int] NOT NULL, [FieldName] [varchar](50) NOT NULL) CREATE TABLE [dbo].[TF_CustomFields_CustomFieldValues]( [ValueId] [int] IDENTITY(1,1) NOT NULL, [FieldId] [int] NOT NULL, [FieldContent] [varchar](max) NULL, [PrimaryKeyValue] [varchar](50) NOT NULL)So - The 2nd table contains the values for the columns defined in the 1st table. FieldContent is the actual entry for that record - PrimaryKeyValue is used to extend other tables - mostly a user table so it's generally going to be a UserID value in that field (which is why I called it UserId)And then the code I used:DECLARE @List VARCHAR(MAX), @pivot VARCHAR(MAX)SELECT @List = COALESCE(@List, 'SELECT p.PrimaryKeyValue') + ',p.[' + CAST(FieldId AS VARCHAR(11)) + '] AS ' + QUOTENAME(fieldName)FROM TF_CustomFields_CustomFieldsORDER BY FieldIdSELECT @pivot = 'FROM TF_CustomFields_CustomFieldValues PIVOT (MAX(FieldContent) FOR TF_CustomFields_CustomFieldValues.FieldId IN ('SELECT @pivot = @pivot + QUOTENAME(FieldId) + ','FROM TF_CustomFields_CustomFieldsORDER BY FieldIdSELECT @pivot = LEFT(@pivot, LEN(@pivot) - 1) + ')) AS p'EXEC (@List + @Pivot) |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2009-04-15 : 09:54:59
|
Before EXEC, put two PRINT's therePRINT @ListPRINT @pivotSometimes, in SQL Server 2005, there is a bug with ORDER BY and concatenated lists.Then you copy and paste those two query parts into a query window and try to execute them. E 12°55'05.63"N 56°04'39.26" |
 |
|
|
loydall
Starting Member
33 Posts |
Posted - 2009-04-15 : 09:57:45
|
| SELECT p.PrimaryKeyValue,p.[1] AS [WebAddress],p.[2] AS [SizeOrganisation],p.[3] AS [CompanyName],p.[4] AS [CompanyDescription]FROM TF_CustomFields_CustomFieldValues PIVOT (MAX(FieldContent) FOR TF_CustomFields_CustomFieldValues.FieldId IN ([1],[2],[3],[4])) AS p |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2009-04-15 : 09:58:35
|
What happens when you try to execute the code below?quote: Originally posted by loydall SELECT p.PrimaryKeyValue,p.[1] AS [WebAddress],p.[2] AS [SizeOrganisation],p.[3] AS [CompanyName],p.[4] AS [CompanyDescription]FROM TF_CustomFields_CustomFieldValues PIVOT (MAX(FieldContent) FOR TF_CustomFields_CustomFieldValues.FieldId IN ([1],[2],[3],[4])) AS p
E 12°55'05.63"N 56°04'39.26" |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2009-04-15 : 10:00:40
|
Change this partFOR TF_CustomFields_CustomFieldValues.FieldId IN ('toFOR FieldId IN (' E 12°55'05.63"N 56°04'39.26" |
 |
|
|
loydall
Starting Member
33 Posts |
Posted - 2009-04-15 : 10:05:28
|
| Same thing - I get a row per entry - not a row per primaryKeyIdWorth pointing out - the TableId column in the 1st Table allows me to define multiple sets of custom fields - it's a foreign key to a TableData table.Not sure if that would effect things - essentially it means that if I have 4 columns defined in the 1st table - 2 of those Currently have tableId of 1 and 2 have TableID of 2. If you look at the results that I got earlier you'll see that the bottom two rows contain results for the 1st 2 columns - these are results that relate to a different TableId to the top results..Hope that makes sense - not sure if it is affecting things though..Thanks for all your help on this BTW.. |
 |
|
|
loydall
Starting Member
33 Posts |
Posted - 2009-04-15 : 11:31:17
|
| Any ideas? |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2009-04-15 : 12:14:42
|
Provide proper sample data to add to #Table2 table above, to demonstrate your scenario. E 12°55'05.63"N 56°04'39.26" |
 |
|
|
loydall
Starting Member
33 Posts |
Posted - 2009-04-15 : 12:50:18
|
| The following is the current data from TF_CustomFields_CustomFieldValues1 3 Bobs Cars 21032 4 We sell Cars 21033 3 John's Computers 21044 4 We sell computers 21045 1 www.dfg.com 21056 2 1 - 500 21059 5 1 smithg street 2103And table 1 (TF_CustomFields_CustomFields) contains the following data:1 1 WebAddress2 1 SizeOrganisation3 2 CompanyName4 2 CompanyDescription5 2 CompanyAddress |
 |
|
|
notmyrealname
98 Posts |
Posted - 2009-04-15 : 13:22:19
|
| Hi.This works for me. The query shows Table1 but it is actually querying what you call Table2. You can take out the 2nd line (INTO TableResults) if you don't want the data inserted into a new table. SELECT Table1.Name, T2.Age, T3.Location, T4.GenderINTO TableResultFROM Table1 INNER JOIN (SELECT CAST(Name AS int) AS Age, UserID FROM Table1 AS Table1_1 WHERE (ID = 2)) AS T2 ON Table1.UserID = T2.UserID INNER JOIN (SELECT CAST(Name AS nvarchar(10)) AS Location, UserID FROM Table1 AS Table1_2 WHERE (ID = 3)) AS T3 ON Table1.UserID = T3.UserID INNER JOIN (SELECT CAST(Name AS nvarchar(10)) AS Gender, UserID FROM Table1 AS Table1_3 WHERE (ID = 4)) AS T4 ON Table1.UserID = T4.UserIDWHERE (Table1.ID = 1)I'm assuming the list you have will always be complete. I.e. there will always be groups of four consecutive rows for each person. This would work even if they were jumbled up though.Hope this helps. |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2009-04-15 : 13:33:10
|
Works for meCREATE TABLE #Table1 ( fieldID INT, tableID INT, fieldName VARCHAR(20) )INSERT #Table1SELECT 1, 1, 'WebAddress' UNION ALLSELECT 2, 1, 'SizeOrganisation' UNION ALLSELECT 3, 2, 'CompanyName' UNION ALLSELECT 4, 2, 'CompanyDescription' UNION ALLSELECT 5, 2, 'CompanyAddress'CREATE TABLE #Table2 ( valueID INT, fieldID INT, fieldContent VARCHAR(MAX), primaryKeyValue VARCHAR(50) )INSERT #Table2SELECT 1, 3, 'Bobs Cars', 2103 UNION ALLSELECT 2, 4, 'We sell Cars', 2103 UNION ALLSELECT 3, 3, 'John''s Computers', 2104 UNION ALLSELECT 4, 4, 'We sell computers', 2104 UNION ALLSELECT 5, 1, 'www.dfg.com', 2105 UNION ALLSELECT 6, 2, '1 - 500', 2105 UNION ALLSELECT 9, 5, '1 smithg street', 2103DECLARE @List VARCHAR(MAX), @pivot VARCHAR(MAX)SELECT @List = COALESCE(@List, 'SELECT p.primaryKeyValue') + ',p.' + QUOTENAME(fieldID) + ' AS ' + QUOTENAME(fieldName)FROM #Table1ORDER BY fieldIDSELECT @pivot = 'FROM (select fieldid, fieldcontent, primarykeyvalue from #Table2) as t2', @pivot = @pivot + ' PIVOT (MAX(fieldContent) FOR FieldID IN ('SELECT @pivot = @pivot + QUOTENAME(fieldID) + ','FROM #Table1ORDER BY fieldIDSELECT @pivot = LEFT(@pivot, LEN(@pivot) - 1) + ')) AS p'EXEC (@List + @Pivot)DROP TABLE #Table1, #Table2 E 12°55'05.63"N 56°04'39.26" |
 |
|
|
|
|
|
|
|