Вопрос

I have a SQL SELECT statement in which I'm using 3 tables. I'm using INNER JOINs to join the tables, however I've come across a bit of an issue because two of the columns that I'd like the join conditional to be based on are different data types; One is an integer - the id of the products table and can be seen below as p.id. The other is a comma delimited string of these id's in the order table. customers can order more than one product at a time, so the product id's are stored as a comma delimited list.

here's how far I've gotten with the SQL:

"SELECT o.transaction_id, o.payment_status, o.payment_amount, o.product_id, o.currency, o.payment_method, o.payment_time, u.first_name, u.last_name, u.email, p.title, p.description, p.price
FROM orders AS o
INNER JOIN products AS p ON ( NEED HELP HERE--> p.id IN o.product_id comma delimited list)
INNER JOIN users AS u ON ( o.user_id = u.id ) 
WHERE user_id =  '39'
ORDER BY payment_time DESC 
LIMIT 1";

Perhaps I could use REGEX? currently the comma delimited list reads as '2,1,3' - however the number of characters isn't limited - so I need a conditional to check if my product id (p.id) is in this list of o.product_id?

Это было полезно?

Решение

What you have is a perfect example for one-to-many relationship where you have one order and several items attached to it. You should have a link table like

order_product - which makes the connection between a orderid and productid where you can also put specific data for the relationship between the two (like when the item was added, quantity, etc)

Then you make the join using this table and you have same field types everywhere.

simple example:

select 
    /* list of products */
from
    order o,
    order_product op,
    product p
where 
    o.id = 20
and o.id = op.orderid
and op.productid = p.id

Другие советы

This in one of those very common nightmares when working with legacy database.

The rule is simple: never ever store multiple values in one table columns. This is known as first normal form.

But how to deal with that in existing DB?

The good thing™

If you have the opportunity to refactor your DB, extract the "comma separated values" to their own table. See http://sqlfiddle.com/#!2/0f547/1 for a basic example how to do that.

Then to query the tables you will have to use a JOIN as explained in elanoism's answer.

The bad thing™

I you can't or don't want do that, you probably have to rely on the FIND_IN_SET function.

SELECT * FROM bad WHERE FIND_IN_SET(target_value, comma_separated_values) > 0;

See http://sqlfiddle.com/#!2/29eba/2

BTW, why is this bad thing™? Because as you see, it is not easy to write query against multi-valued columns -- but, probably more important, you are not able to use index on that columns, nor, as a consequence, to easily perform join operations or enforce referential integrity.

The so-so thing™

As a final note, if the set of possible value is small (less that 65), an alternative approach would be to change the column type to a SET().

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top