Я запускаю PHP + MySQL на своем ПК с Windows 8. У меня есть таблица mytable
как mytable
ниже;
╔═════════╦══════╦═════╗ ║ product ║ tag ║ lot ║ ╠═════════╬══════╬═════╣ ║ 1111 ║ 101 ║ 2 ║ ║ 1111 ║ 102 ║ 5 ║ ║ 2222 ║ 103 ║ 6 ║ ║ 3333 ║ 104 ║ 2 ║ ║ 4444 ║ 101 ║ 2 ║ ║ 5555 ║ 101 ║ 2 ║ ║ 5555 ║ 102 ║ 5 ║ ║ 6666 ║ 102 ║ 2 ║ ║ 6666 ║ 103 ║ 5 ║ ║ 7777 ║ 101 ║ 2 ║ ║ 7777 ║ 102 ║ 5 ║ ║ 7777 ║ 103 ║ 6 ║ ║ 8888 ║ 101 ║ 1 ║ ║ 8888 ║ 102 ║ 3 ║ ║ 8888 ║ 103 ║ 5 ║ ║ 9999 ║ 101 ║ 6 ║ ║ 9999 ║ 102 ║ 8 ║ ╚═════════╩══════╩═════╝
У меня есть вход 101
, 102
. Я хочу, чтобы выход понравился;
2,5 6,8
Запрос будет искать комбинации 101,102
, 101,102
и возвращает те же самые комбинации с другим номером партии . Наряду с этим, я хочу избежать дублирования строк. Здесь 1111
и 5555
имеют те же теги с одинаковыми номерами партий для tag
s (одни и те же комбинации с одинаковыми лотами), поэтому я хочу только одну строку вместо двух строк. Несмотря на то, что 8888
имеет теги 101
и 102
с разными lot
s, его нельзя рассматривать для листинга, так как он включает в себя также тэг 103
. Короче говоря, я хочу продукты с точной комбинацией 101, 102
, и я не хочу продуктов с любыми дополнительными тегами, и я не хочу ничего с отсутствующими тегами.
У меня есть запрос, как показано ниже;
SELECT DISTINCT GROUP_CONCAT(m.lot) FROM mytable m WHERE m.tag IN (101,102) AND (SELECT COUNT(m.product) FROM mytable m2 WHERE m.product = m2.product)>1 GROUP BY m.product;
который возвращается;
2,5 2 5,2 1,3 6,8
Как я могу это исправить? Есть ли лучший способ выполнить то, что я ищу?
Вот скрипка, начинающаяся с http://sqlfiddle.com/#!9/d11d6
Я предлагаю использовать для этого простое соединение:
SELECT DISTINCT a.lot, b.lot FROM mytable a INNER JOIN mytable b ON b.product = a.product AND NOT EXISTS (SELECT * FROM product WHERE tag NOT IN (a.tag, b.tag)) WHERE a.tag = 101 and b.tag = 102
Мне интересно, делает ли это то, что вы хотите:
select group_concat(lot order by lot) from mytable group by product having group_concat(tag order by tag) = '101,102';
Кажется, это возвращает желаемые результаты. Это будет немного более эффективно с предложением where
:
select group_concat(lot order by lot) from mytable where tag in ('101', '102') group by product having group_concat(tag order by tag) = '101,102';
Выполняя группу по продукту, а предложение HAVING явно ищет ТОЛЬКО те продукты, которые имеют как 101, так и 102 и NO OTHER. Как только каждый продукт имеет квалификацию, включены конкатенированные партии. Если у другого есть такая же конкатенация, возвращается только один набор. Из-за ваших повторяющихся записей одного и того же тега 101 внутри продукта мне остается только, если один из них найден независимо от его дублирования, следовательно, MAX () для 101 и 102 оба = 1 соответственно.
select DISTINCT group_concat( DISTINCT m.lot ORDER BY m.lot ASC SEPARATOR ',' ) from myTable m group by m.product having MAX( case when m.tag = '101' then 1 else 0 end ) = 1 AND MAX( case when m.tag = '102' then 1 else 0 end ) = 1 AND sum( case when m.tag in ( '101', '102' ) then 0 else 1 end ) = 0;
И если вы хотите увидеть, как сравнивается каждый отдельный продукт, удалите предложение HAVING, чтобы увидеть их соответствующие значения
select m.product, group_concat( DISTINCT m.lot ORDER BY m.lot ASC SEPARATOR ',' ), sum( case when m.tag in ( '101', '102' ) then 1 else 0 end ) as WantTags, sum( case when m.tag in ( '101', '102' ) then 0 else 1 end ) as OtherTags from myTable m group by m.product
Я создал экземпляр SQLFiddle для вас. Немного незначительных вещей. Я изменил имена столбцов на «tag1», «lot1».
select DISTINCT group_concat( DISTINCT m.lot1 ORDER BY m.lot1 ASC SEPARATOR ',' ) from myTableXYZ m group by m.product having MAX( case when m.tag1 = 101 then 1 else 0 end ) = 1 AND MAX( case when m.tag1 = 102 then 1 else 0 end ) = 1 AND sum( case when m.tag1 in ( 101, 102 ) then 0 else 1 end ) = 0;
Поэтому мой запрос выполняется против вашего SQLFiddle и имеет результаты
2,5 1,3,5 6,8