tags:

views:

90

answers:

4

I'm creating a 'similar items' link table.

i have a 2 column table. both columns contains product ids.

CREATE TABLE IF NOT EXISTS `prod_similar` (
  `id_a` int(11) NOT NULL,
  `id_b` int(11) NOT NULL
)    

INSERT INTO `prod_similar` (`id_a`, `id_b`) VALUES
(5, 10),
(5, 15),
(10, 13),
(10, 14),
(14, 5),
(14, 13);

I want to select 3 similar products, favouring products where the id is in the first col, 'id_a'

SELECT * FROM prod_similar WHERE id_a={$id} OR id_b={$id}
ORDER BY column(?) 
LIMIT 3
+3  A: 

Don't know, maybe this?

SELECT * 
FROM similar_items 
WHERE col_1={$id} OR col_2={$id} 
ORDER BY CASE WHEN col_1={$id} THEN 0 WHEN col_2={$id} THEN 1 END 
LIMIT 3
Jhonny D. Cano -Leftware-
+1  A: 

I am not sure I get the question, could you maybe post example data for the source table and also show what the result should look like.

If I got you right i would try something like

Select (case  
  when col_1={$ID}:  
    col1 
  when col_2={$ID}: 
    col2) as id from similar_items  WHERE col_1={$id} OR col_2={$id} 
LIMIT 3
Cilvic
+2  A: 

An easy way to do this is this:

ORDER BY NULLIF(col_1, {$id}) LIMIT 3

The CASE WHEN works as well, but this is bit simpler.

reko_t
im trying to finds some documentation for NULLIF()..what does it do in essence?i've re-explained my question above, should make more sense now!
Haroldo
NULLIF returns NULL if the first argument is equal to the second argument. In this case, if col_1 is equal to your argument, it will return NULL, putting first in the order by
Jhonny D. Cano -Leftware-
Jhonny beat me to it :)NULLIF() returns NULL if the first and second parameter are the same, otherwise it returns the first parameter. In short this means that if col_1 is the product ID, it returns NULL, otherwise it returns whatever is in col_1. In ascending ordering, NULL values come always first, hence this will prioritize the rows with product ID in col_1.
reko_t
would you say it's faster to use goran's UNION method?
Haroldo
can't say for sure, I'd test it
reko_t
@Haroldo: no, this should be faster. also I didn't get the condition that you'd favour id_a. going to edit my answer
Unreason
@reko_t i think this is faster because the union does to select, and then it has to check for repeated rows, on the other hand, this is just a simple function evaluation
Jhonny D. Cano -Leftware-
+2  A: 

I assume you have other columns as well

(SELECT 1 favouring, id_a id, [other columns]
FROM prod_similar
WHERE id_a = {$id})
UNION
(SELECT 2 favouring, id_b id, [other columns]
FROM prod_similar
WHERE id_b = {$id})
ORDER BY favouring, id
LIMIT 3;

In case you don't mind duplicates or there are none between id_a and id_b you can do UNION ALL instead which is considerably faster.

Unions are indication of denormalized data, denormalized data improves speed of certain queries and reduces speed of others (such as this).

Unreason
no other columns
Haroldo
@goran, this looks great except be sure to add parenthesis around the SELECT statements so the ORDER clause occurs on the final result set. Using the AS keyword for your aliases would also make it more readable.
Marcus Adams
@marcus, I am adding parenthesis, the docs at http://dev.mysql.com/doc/refman/5.1/en/union.html say to do so (for LIMIT too). As for aliases, no, for me it is more readable without it.
Unreason