2

I have 2 tables, items and members :

CREATE TABLE IF NOT EXISTS `items` (
`id` int(5) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`member` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `members` (
  `id` int(5) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

What if, for example I have a record inside items, such as

INSERT INTO  `test`.`items` (
`id` ,
`name` ,
`member`
)
VALUES (
NULL ,  'xxxx',  '1, 2, 3'
);

in members :

INSERT INTO `members` (`id`, `name`) VALUES
(1, 'asdf'),
(2, 'qwert'),
(3, 'uiop'),
(4, 'jkl;');

and I'd like to display items.member data with members.name, something like 1#asdf, 2#qwert, 3#uiop??

I've tried the following query,

SELECT items.id, items.name, GROUP_CONCAT(CONCAT_WS('#', members.id, members.name) ) as member

FROM `items` 
LEFT JOIN members AS members on (members.id = items.member)
WHERE items.id = 1

But the result is not like I expected. Is there any other way to display the data via one call query? Because I'm using PHP, right now, i'm explode items.member and loop it one by one, to display the members.name.

4

2 に答える 2

3

You could look into using FIND_IN_SET() in your join criteria:

FROM items JOIN members ON FIND_IN_SET(members.id, items.member)

However, note from the definition of FIND_IN_SET():

A string list is a string composed of substrings separated by “<code>,” characters.

Therefore the items.member column should not contain any spaces (I suppose you could use FIND_IN_SET(members.id, REPLACE(items.member, ' ', '')) - but this is going to be extremely costly as your database grows).

Really, you should normalise your schema:

CREATE TABLE memberItems (
  item_id   INT(5) NOT NULL,
  member_id INT(5) NOT NULL,
  FOREIGN KEY   item_id REFERENCES   items (id),
  FOREIGN KEY member_id REFERENCES members (id)
);

INSERT INTO memberItems
  (item_id, member_id)
SELECT items.id, members.id
FROM   items
  JOIN members ON FIND_IN_SET(members.id, REPLACE(items.member,' ',''))
;

ALTER TABLE items DROP member;

This is both index-friendly (and therefore can be queried very efficiently) and has the database enforce referential integrity. Then you can do:

FROM items JOIN memberItems ON memberItems.item_id = items.id
           JOIN members     ON members.id = memberItems.member_id

Note also that it's generally unwise to use GROUP_CONCAT() to combine separate records into a string in this fashion: your application should instead be prepared to loop over the resultset to fetch each member.

于 2012-12-02T15:03:21.247 に答える
0

Please take a look at this sample:

SQLFIDDLE

Your query seems to work for what you have mentioned in the question... :)

SELECT I.ID, I.ITEM,
GROUP_CONCAT(CONCAT("#",M.ID,
M.NAME, " ")) AS MEMB

FROM ITEMS AS I
LEFT JOIN MEMBERS AS M
ON M.ID = I.MID
WHERE i.id = 1
;

EDITTED ANSWER This query will not work for you¬ as your schema doesn't seem to have any integrity... or proper references. Plus your memeber IDs are delimtted by a comma, which has been neglected in this answer.

于 2012-12-02T15:13:27.073 に答える