'SQL Some vertical to horizontal field names/values
What I've read here doesn't quite answer what I'm trying to do. That's why I'm posting a request here and I'm confident to learn what I can do on this subject.
Here are my tables:
Customer:
| ID | Firstname | Lastname |
|----|-----------|----------|
| 1 | John | Lennon |
| 2 | Patti | Smith |
LinkedTable:
| ID | TableName |
|----|-----------|
| 1 | Customer |
LinkedTableField:
| ID | LinkedTableID | FieldName | FieldCaption |
|----|---------------|------------|--------------|
| 1 | 1 | SocksColor | Socks Color |
| 2 | 1 | Married | Married? |
LinkedTableFieldValue:
| ID | LinkedTableID | LinkedTableFieldID | OwnerID | STRValue |
|----|---------------|--------------------|---------|----------|
| 1 | 1 | 1 | 1 | Blue |
| 2 | 1 | 1 | 2 | Purple |
| 3 | 1 | 2 | 1 | Yes |
| 4 | 1 | 2 | 2 | No |
I've built this SQL View by this code:
SELECT LinkedTable.ID,
LinkedTableField.ID,
LinkedTableField.FieldName,
LinkedTableField.FieldCaption,
LinkedTableFieldValue.ID,
LinkedTableFieldValue.OwnerID,
LinkedTableFieldValue.STRValue
FROM ( (LinkedTable INNER JOIN LinkedTableField
ON LinkedTable.ID = LinkedTableField.LinkedTableID
) INNER JOIN LinkedTableFieldValue ON
( (LinkedTableField.ID = LinkedTableFieldValue.LinkedTableFieldID)
AND (LinkedTableField.LinkedTableID = LinkedTableFieldValue.LinkedTableID)
)
) as View1;
The displaying data of View1 is:
| LinkedTableID | LinkedTableFieldID | LinkedTableFieldValueID | FieldName | FieldCaption | OwnerID | STRValue |
|---------------|--------------------|-------------------------|------------|--------------|---------|----------|
| 1 | 1 | 1 | SocksColor | Socks Color | 1 | Blue |
| 1 | 1 | 2 | SocksColor | Socks Color | 2 | Purple |
| 1 | 2 | 3 | Married | Married? | 1 | Yes |
| 1 | 2 | 4 | Married | Married? | 2 | No |
Now, I can list Customer table linked to the View1 by this SQL View:
SELECT Customer.*,
View1.LinkedTableID,
View1.FieldName,
View1.STRValue
FROM (Customer LEFT JOIN View1 ON Customer.ID = View1.OwnerID) AS View2
WHERE View1.LinkedTableID = 1;
Here is the View2 result:
| ID | Firstname | Lastname | FieldName | STRValue |
|----|-----------|----------|------------|----------|
| 1 | John | Lennon | SocksColor | Blue |
| 2 | Patti | Smith | SocksColor | Purple |
| 1 | John | Lennon | Married | Yes |
| 2 | Patti | Smith | Married | No |
At this level, I'm not able to write SQL code to obtain this kind of result:
| ID | Firstname | Lastname | SocksColor | Married |
|----|-----------|----------|------------|---------|
| 1 | John | Lennon | Blue | Yes |
| 2 | Patti | Smith | Purple | No |
At least, is there a way to write a SQL code to display this kind of list under PostgreSQL?
It would be great!
Thank you for your help.
Solution 1:[1]
Here is the solution under postgres
CREATE TABLE Contacts (
CID integer,
FirstName text,
Lastname text
);
CREATE TABLE LkTables (
TID integer,
TableName text
);
CREATE TABLE LkFields (
FID integer,
LkTablesFID integer,
FieldName text,
Caption text
);
CREATE TABLE LkValues (
VID integer,
LkTablesVID integer,
LkFieldsVID integer,
OwnerID integer,
STRValue text
);
INSERT INTO Contacts VALUES
(1, 'John', 'Lennon'),
(2, 'Patti', 'Smith'),
(3, 'Eric', 'Clapton'),
(4, 'Marc', 'Knopfler');
INSERT INTO LkTables VALUES
(1, 'Contacts'),
(2, 'Items');
INSERT INTO LkFields VALUES
(1, 1, 'SocksColor', 'Socks Color'),
(2, 1, 'Married', 'Married?'),
(3, 1, 'KidsNumber', 'Number of Kids');
INSERT INTO LkValues VALUES
(1, 1, 1, 1, 'Blue'),
(2, 1, 1, 2, 'Purple'),
(3, 1, 2, 1, 'Yes'),
(4, 1, 2, 2, 'No'),
(5, 1, 3, 1, '4'),
(6, 1, 3, 2, '1'),
(7, 1, 3, 4, '7'),
(8, 1, 2, 3, 'Yes');
CREATE VIEW view1 AS
SELECT *
FROM ( (LkTables INNER JOIN LkFields
ON LkTables.TID = LkFields.LkTablesFID
) INNER JOIN LkValues ON
( (LkFields.FID = LkValues.LkFieldsVID)
AND (LkFields.LkTablesFID = LkValues.LkTablesVID)
)
) c;
CREATE VIEW view2 AS
SELECT *
FROM (Contacts LEFT JOIN view1 ON Contacts.CID = View1.OwnerID);
-- the result
SELECT *
FROM CROSSTAB(
'SELECT lastname, firstname, caption, strvalue FROM view2 ORDER BY 2,3',
$$VALUES ('Socks Color'::text), ('Married?'), ('Number of Kids')$$) AS ct ("LastName" text, "Firstname" text, "Socks Color" text, "Married" text, "Kids" text);
Visual result
| LastName | Firstname | Socks Color | Married | Kids |
|----------|-----------|-------------|---------|------|
| Clapton | Eric | null | Yes | null |
| Lennon | John | Blue | Yes | 4 |
| Knopfler | Marc | null | null | 7 |
| Smith | Patti | Purple | No | 1 |
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |