문제

I have a MySQL database used for a mailing list, and I need to extract the data, so one member record is represented by one row. The mailing list stores the user attributes as EAV. I can extract all the details I need using the following SQL query, but each member record takes up multiple rows:

SELECT a.id, a.name, a.email, b.id, b.name, b.email, c.title, d.val
FROM lists a, listmembers b, fields c, fieldsdata d
WHERE a.id = b.nl
AND b.id = d.eid
AND c.id = d.fid
ORDER BY b.id, a.id, b.name

This returns something like this:

'6', 'Mailing List name', 'owner@mailinglist.com', '10478', 'username', 'mailinglistmember@emailaddress.com', 'Firstname', 'John'
'6', 'Mailing List name', 'owner@mailinglist.com', '10478', 'username', 'mailinglistmember@emailaddress.com', 'Lastname', 'Smith'
'6', 'Mailing List name', 'owner@mailinglist.com', '10478', 'username', 'mailinglistmember@emailaddress.com', 'Country', 'UK'
'6', 'Mailing List name', 'owner@mailinglist.com', '10478', 'username', 'mailinglistmember@emailaddress.com', 'Town', 'Cambridge'
'6', 'Mailing List name', 'owner@mailinglist.com', '10478', 'username', 'mailinglistmember@emailaddress.com', 'Shoesize', '7'
'6', 'Mailing List name', 'owner@mailinglist.com', '10478', 'username', 'mailinglistmember@emailaddress.com', 'Favourite Colour', 'Purple'

I need to flatten this into one row using SQL, only requiring values relating to the keys firstname, lastname, town and country

The database is not huge, the fieldsdata table being the largest with about 5500 rows.

Seems like a real pain, so any pointers would be gratefully received. !

도움이 되었습니까?

해결책 2

You can use MAX with CASE to pivot your results if I'm understanding your question correctly:

SELECT l.id, l.name, l.email, lm.id, lm.name, lm.email, 
   MAX(CASE WHEN f.title = 'Firstname' THEN fd.val END) FirstName,
   MAX(CASE WHEN f.title = 'Lastname' THEN fd.val END) Lastname,
   MAX(CASE WHEN f.title = 'Country' THEN fd.val END) Country,
   MAX(CASE WHEN f.title = 'Town' THEN fd.val END) Town
FROM lists l
   JOIN listmembers lm ON l.id=lm.nl
   JOIN fieldsdata fd ON fd.eid = lm.id
   JOIN fields f ON f.id = fd.fid 
GROUP BY l.id, lm.id

This assumes the id field from your lists table is your unique identifier. If not, you'll need to add additional fields to your GROUP BY (most likely the id field from your listmembers table).

다른 팁

For anyone (like me) that finds this question where your query relates to SQL Server instead of MySQL, there is the option of a Pivot query.

SELECT id, name, email, id2, name2, email2, [Firstname], [Lastname], 
    [Country], [Town]
FROM (select id, name, email, id2, name2, email2, title, val from yourresults) ps
PIVOT (
        MAX(val) 
        FOR title IN ([Firstname], [Lastname], [Country], [Town])
    ) as pvt

See SQL fiddle (working from sgeddes SQL fiddle above - thanks)

Or in MS Access:

TRANSFORM Max(val)
SELECT id, name, email, id2, name2, email2
FROM yourresults
GROUP BY id, name, .email, id2, name2, email2
PIVOT title In ("FirstName","LastName","Country","Town");

EAV tables are a poor design choice and should only be used if you cannot know in advance what fields are needed. Fields such as firstname can be known that you will need them in advance and should be in proper related tables. If you want to use EAV for everything at least stop using a relational datbase and use a NOSQL database designed for this.

To get the result you want you will need to join to the EAV tables once for each type of data you want.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top