问题
I've been trying to order the ID's of the Objects contained in my Table. For this, I'm using the following hierarchy, which is based on the order of attributes within the 'IN' clause:
ORDER BY
First: ID's that match ALL the attributes: 'Solid' and 'Metal' and 'Red'
Second: ID's that match the attributes: 'Solid' and 'Metal'
Third: ID's that match just the attribute: 'Solid'
Fourth: ID's that match attributes: 'Metal' and 'Red'
Fifth: ID's that match just the attribute: 'Metal'
Sixth: ID's that match just the attribute: 'Red'
The main query I'm using is:
SELECT objectattributelink.ID, COUNT(*) Attributes
FROM objectattributelink, attributelist
WHERE objectattributelink.ID = attributelist.AttributeID
AND attributelist.AttributeDesc IN ('Solid', 'Metal', 'Red')
AND objectattributelink.AttributeID BETWEEN 1000 AND 1200
GROUP BY objectattributelink.ID
ORDER BY COUNT(*) DESC
Which returns all the ID's in a simplified order. In this case, the ones on the top (matching 3 attributes) would be ok, but for the rest the order is random.
My current solution is running 6 different queries, but I want to know if it can be done in one.
What I'm basically doing for each query is:
One with: IN ('Solid', 'Metal', 'Red') and HAVING Attributes = 3, Second one with: IN ('Solid', 'Metal') and HAVING Attributes = 2, Third one with: IN ('Solid'), Fourth one with: IN ('Metal', 'Red') and HAVING Attributes = 2, Fifth one with: IN ('Metal') and Sixth one with IN ('Red')
回答1:
The following query does the ordering:
SELECT oal.ID, COUNT(*) Attributes
FROM objectattributelink oal join
(select al.*,
(case when AttributeDesc = 'Solid' then 1 else 0 end) as IsSolid,
(case when AttributeDesc = 'Metal' then 1 else 0 end) as IsMetal,
(case when AttributeDesc = 'Red' then 1 else 0 end) as IsRed
from attributelist al
) al
on oal.ID = al.AttributeID
where al.AttributeDesc IN ('Solid', 'Metal', 'Red')
AND oal.AttributeID BETWEEN 1000 AND 1200
GROUP BY oal.ID
ORDER BY (case when max(IsSolid) = 1 and max(IsMetal) = 1 and max(IsRed) = 1 then 1
when max(IsSolid) = 1 and max(IsMetal) = 1 then 2
when max(IsSolid) = 1 then 3
when max(IsMetal) = 1 and max(IsRed) = 1 then 4
when max(IsMetal) = 1 then 5
when max(IsRed) = 1 then 6
end);
To facilitate writing the logic the query introduces three new variables for each value. The max()
function then determines if the group has those variables.
I also fixed the join syntax to use the on
clause and introduced table aliases for readability.
EDIT:
I think you can also do the order by
using:
order by max(IsSolid) * 4 + max(IsMetal) * 2 + max(IsRed);
来源:https://stackoverflow.com/questions/18244765/order-grouped-values-by-custom-rank-sql