views:

94

answers:

2

Hey there, I have an sql database. In this database is 3 tables I need to query. The first table has all the item info called item and the other two tables has data for votes and comments called userComment and the third for votes called userItem

I currently have a function which uses this sql query to get the latest more popular (in terms of both votes and comments):

$sql = "SELECT  itemID, COUNT(*) AS cnt
FROM    (
        SELECT  `itemID`
        FROM   `userItem`
        WHERE  FROM_UNIXTIME( `time` ) >= NOW() - INTERVAL 1 DAY
        UNION ALL
        SELECT  `itemID`
        FROM    `userComment`
        WHERE  FROM_UNIXTIME( `time` ) >= NOW() - INTERVAL 1 DAY AND `itemID` > 0
        ) q
GROUP BY
        `itemID`
ORDER BY
        cnt DESC";

I know how to change this for either by votes alone or comments....

HOWEVER - I need to query the database to only return the itemID's of the ones which have specific conditions in only the item table these are WHERE categoryID = 'xx' AND typeID = 'xx'

If the sql ninja could please help me on this one? Do I have to first return the results from the above query and the for each in the array fetched then check each against the item table and see if it fits the conditions to build a new array - or is that overkill?

Thanks, Stefan

A: 

It's not clear to me exactly how your DB is setup or where some of these attributes are but it might be something like:

$sql = "SELECT  q.itemID, COUNT(*) AS cnt
FROM    (
        SELECT  `itemID`
        FROM   `userItem`
        WHERE  FROM_UNIXTIME( `time` ) >= NOW() - INTERVAL 1 DAY
        UNION ALL
        SELECT  `itemID`
        FROM    `userComment`
        WHERE  FROM_UNIXTIME( `time` ) >= NOW() - INTERVAL 1 DAY AND `itemID` > 0
        ) q inner join item i on q.itemID = i.itemID
WHERE i.categoryID = 'xx' AND i.typeID = 'xx'
GROUP BY
        q.`itemID`
ORDER BY
        cnt DESC";
BobbyShaftoe
Doesnt seem to be working? What extra info do you need which you were unsure about? the attributes such as categoryID and itemID are in the table called `item` where all the items are actually stored
Stefan
The inner join is acting as a filter for only those items with either votes or comments. Change it to a left join - does that help?
matt eisenberg
Returns: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'q.itemID = i.itemID WHERE i.categoryID = '1' AND i.typeID = '1' GROUP BY ' at line 10 - SELECT q.itemID, COUNT(*) AS cnt FROM ( SELECT `itemID` FROM `userItem` WHERE FROM_UNIXTIME( `time` ) >= NOW() - INTERVAL 1 DAY UNION ALL SELECT `itemID` FROM `userComment` WHERE FROM_UNIXTIME( `time` ) >= NOW() - INTERVAL 1 DAY AND `itemID` > 0 ) q left join item i q.itemID = i.itemID WHERE i.categoryID = '1' AND i.typeID = '1' GROUP BY q.`itemID` ORDER BY cnt DESC
Stefan
@Stefan, looks like I left off the "on" keyword.
BobbyShaftoe
This works HOWEVER for example: If i have something with 1 vote and a comment it comes under one with 1 vote and no comment? Why is this?
Stefan
It seemed when I swapped the comment statement before UNION ALL to above the vote statement to display the results better! :)
Stefan
A: 

I would be inclined to include the filter on each of the queries. I would need to verify but I would think that it would perform better as fewer rows are analyzed in the Group By. Thus, I would do something like (this is a guess since we are not told how the item table relates to the others):

$sql = "Select  itemID, Count(*) AS cnt
From    (
        Select ui.`itemID`
        From `userItem` ui
            Join `item` i
                On i.itemid = ui.itemid
        Where From_UnixTime( `time` ) >= Now() - Interval 1 Day
            And i.categoryID = 'xx'
            And i.typeid = 'xx'
        Union All
        Select uc.`itemID`
        From `userComment` uc
            Join `item` i
                On i.itemid= uc.itemid
        Where From_UnixTime( `time` ) >= Now() - Interval 1 Day
            And uc.itemID > 0
            And i.categoryID = 'xx'
            And i.typeid = 'xx'
        )  q
Group By `itemID`
Order By cnt Desc";
Thomas
Getting this response, any ideas? Column 'itemID' in field list is ambiguous - SELECT itemID, Count(*) AS cnt FROM ( SELECT `itemID` FROM `userItem` ui JOIN `item` i ON i.itemid = ui.itemid WHERE From_UnixTime( `time` ) >= Now() - Interval 7 Day AND i.categoryID = 'popular' UNION ALL SELECT `itemID` FROM `userComment` uc Join `item` i On i.itemid= uc.itemid Where From_UnixTime( `time` ) >= Now() - Interval 7 Day And uc.itemID > 0 And i.categoryID = 'popular' ) q Group By `itemID` Order By cnt Desc
Stefan
@Stefan - You simply need to alias `itemid` that is in each of the inner select clauses. I've updated my post to illustrate.
Thomas