Hey all,
I'm getting crazy on a problem with left join in SQLite. Either I didn't understand something, or there's a bug somewhere.
Here's a sample of my DB

CREATE TABLE Media (
MediumId INTEGER PRIMARY KEY,
...
)
CREATE TABLE MediumPropMap (
MediumId INTEGER NOT NULL, (foreign key from Media)
PropId INTEGER NOT NULL, (foreign key from Property)
UNIQUE (MediumId, PropId)
)

CREATE TABLE Property ( PropId INTEGER PRIMARY KEY,
PropValueId INTEGER NOT NULL, (foreign key from PropValue)
PropNameId INTEGER NOT NULL, (foreign key from PropName)
UserId INTEGER NOT NULL
)

CREATE TABLE PropValue (
PropValueId PRIMARY KEY,
Text TEXT
)

CREATE TABLE PropName (
PropNameId PRIMARY KEY,
Text TEXT
)

Now what I'm trying to do is to get an SQL query that would return all the media sorted by one of their property (or few properties at the same time), *taking into account that not all the media have that property*. The answer is, of course, to use left joins, and my first attempt was :

SELECT m.MediumID AS id, IFNULL(pn.Text, '') AS name, IFNULL(pv.Text, '') AS value
FROM Media AS m
LEFT JOIN MediumPropMap AS mpm ON mpm.MediumID=m.MediumID
LEFT JOIN Property AS p ON mpm.PropID=p.PropID
LEFT JOIN PropName AS pn ON p.PropNameID=pn.PropNameID
LEFT JOIN PropValue AS pv ON p.PropValueID=pv.PropValueID

WHERE pn.Text='myprop' AND p.UserID=1
GROUP BY id ORDER BY value
;

This doesn't work, as I could see in other threads. It returns only the media that have the property 'myprop', apparently the where clause is applied on the global result, but why ?

anyway, second attempt :

SELECT m.MediumID AS id, IFNULL(pn.Text, '') AS name, IFNULL(pv.Text, '') AS value
FROM Media AS m
LEFT JOIN MediumPropMap AS mpm ON mpm.MediumID=m.MediumID
LEFT JOIN PropName AS pn ON (pn.Text='myprop')
LEFT JOIN Property AS p ON (p.PropNameID=pn.PropNameID AND mpm.PropID=p.PropID AND p.UserID=1)
LEFT JOIN PropValue AS pv ON p.PropValueID=pv.PropValueID

GROUP BY id
ORDER BY value
;

Not right either, returns now the correct count of media, but none of my properties that I'm looking for.

Another attempt, trying to get things simpler :

SELECT mpm.MediumID AS id, IFNULL(pv.Text,'') as value
FROM Media AS mpm
INNER JOIN PropName AS pn ON pn.Text='rating'
LEFT JOIN Property AS p ON (mpm.PropID=p.PropID AND p.PropNameID=pn.PropNameID AND p.UserID=1)
LEFT JOIN PropValue AS pv ON p.PropValueID=pv.PropValueID
GROUP BY id
ORDER BY value
;

Now the result is really far from what I'm looking for. Things are getting to get weird here...

I finally found one that was working :

SELECT m.MediumID AS id, IFNULL(pn0.Text, '') AS name, IFNULL(pv.Text, '') AS value
FROM Media AS m
LEFT JOIN MediumPropMap AS mpm ON ( mpm.MediumID=m.MediumID AND mpm.PropID IN (SELECT p.PropID FROM Property AS p, PropName AS pn WHERE pn.Text='myprop' AND p.PropNameID=pn.PropNameID)
)
LEFT JOIN Property AS p ON mpm0.PropID=p.PropID
LEFT JOIN PropName AS pn ON p.PropNameID=pn.PropNameID
LEFT JOIN PropValue AS pv ON p.PropValueID=pv.PropValueID

GROUP BY id
ORDER BY  value
;

But this one gets really long when used on a property that has many different values in the DB, I believe sqlite is here creating an intermediate result table and therefore get things really long to process.

Any other ideas ? And can someone explain why the first attempts weren't working ?

Thanks,

- Alex

Reply via email to