2016-06-28 3 views
1

У меня есть следующие модели данных:Как сделать подзапрос в GROUP_CONCAT

`title` 

- id 
- name 

`version` 

- id 
- name 
- title_id 

`version_price` 

- id 
- version_id 
- store 
- price 

А вот пример данных:

`title` 

- id=1, name=titanic 
- id=2, name=avatar 

`version` 

- id=1, name="titanic (dubbed in spanish)", title_id=1 
- id=2, name="avatar directors cut", title_id=2 
- id=3, name="avatar theatrical", title_id=2 

`version_price` 

- id=1, version_id=1, store=itunes, price=$4.99 
- id=1, version_id=1, store=google, price=$4.99 
- id=1, version_id=2, store=itunes, price=$5.99 
- id=1, version_id=3, store=itunes, price=$5.99 

Я хочу построить запрос, который даст мне все заголовки, которые имеют версию version на iTunes, но не на Google. Как мне это сделать? Вот то, что я до сих пор:

select 
    title.id, title.name, group_concat(distinct store order by store) 
from 
    version inner join title on version.title_id=title.id inner join version_price on version_price.version_id=version.id 
group by 
    title_id 

Это дает мне GROUP_CONCAT, который показывает мне, что у меня есть:

id name group_concat(distinct store order by store) 
1 Titanic Google,iTunes        
2 Avatar iTunes          

Но как бы я построить запрос включить ли элемент на Google (используя случай заявление или что бы ни необходимости)

id name group_concat(distinct store order by store) on_google 
1 Titanic Google,iTunes        true 
2 Avatar iTunes          false 

Это будет в основном будет делать group_concat LIKE '%google%' вместо нормальной, где положение.

Вот ссылка для SQL скрипку текущего запроса у меня есть: http://sqlfiddle.com/#!9/e52b53/1/0

+0

'где магазин <> 'google''? это не задача group_concat для фильтрации вещей для вас, за исключением «отличительного» материала. фильтрация выполняется в предложениях 'where'. –

+0

что вы ожидаете получить? '1 | Титаник | Google, iTunes' или просто '1 | Титаник | iTunes'? – Alex

+0

@MarcB посмотрите пожалуйста обновленный вопрос. – David542

ответ

1

Используйте условную агрегацию, чтобы определить, указано ли название в указанном хранилище.

select title.id, title.name, group_concat(distinct version_price.store order by store), 
if(count(case when store = 'google' then 1 end) >= 1,'true','false') as on_google 
from version 
inner join title on version.title_id=title.id 
inner join version_price on version_price.version_id=version.id 
group by title.id, title.name 

count(case when store = 'google' then 1 end) >= 1 подсчитывает все строки для данного заголовка после присвоения 1 к строкам, которые имеют google в них. (Или иначе они будут назначены null, а count игнорирует нули.) После этого if проверяет count и классифицирует заголовок, если на нем есть как минимум один google.

+0

очень хорошо, это хорошо работает, и этот подход намного лучше, чем мой текущий подзапрос. – David542

+0

Вы могли бы объяснить в своем ответе следующую строку и как она работает? 'if (count (case when store = 'google' then 1 end)> = 1, 'true', 'false') как on_google'. Как использовать 'if (count (...))' отличный, чем обычный 'case'? – David542

+0

добавлено объяснение. –

0

Я хотел бы сделать это, как показано ниже

SELECT 
    * 
FROM 
    title t 
INNER JOIN 
    version v ON 
     v.title_id = t.id 
CROSS APPLY (
    SELECT 
     * 
    FROM 
     version_price vp 
    WHERE 
     vp.store <> 'google' 
) c ON c.version_id == v.id 

Синтаксис может быть только немного не так как я не могу проверить его прямо сейчас, но я считаю, что это дух того, что вы хотите. Cross apply также очень эффективное соединение, которое всегда полезно!

+0

Я никогда не слышал о применении креста. Это верно для mysql? Кроме того, вы можете попробовать его на sqlfiddle здесь, чтобы проверить, работает ли это: http://sqlfiddle.com/#!9/e52b53/1/0 – David542

+0

Дайте несколько минут, и я отвечу! – NewDeveloper

+0

Изучив, я не видел «Cross Apply» в MySQL. Извини за это! Я думаю, это решение работает только в MSSQL и, возможно, в SQL. – NewDeveloper

1

Это даст вам количество версий цены не на google, а число на google. (COUNT не подсчитывает нулевые значения.)

SELECT t.id, t.name 
    , COUNT(DISTINCT vpNotG.id) > 0 AS onOtherThanGoogle 
    , COUNT(DISTINCT vpG.id) > 0 AS onGoogle 
FROM title AS t 
    INNER JOIN version AS v ON t.id=v.title_id 
    LEFT JOIN version_price AS vpNotG 
     ON v.id=vpNotG.version_id 
     AND vpNotG.store <> 'Google' 
    LEFT JOIN version_price AS vpG 
     ON v.id=vpG.version_id 
     AND vpG.store = 'Google' 
GROUP BY t.id 

или другое решение аналогичной ВКП:

SELECT t.id, t.name 
    , COUNT(DISTINCT CASE WHEN store = 'Google' THEN vp.id ELSE NULL END) AS googlePriceCount 
    , COUNT(DISTINCT CASE WHEN store = 'iTunes' THEN vp.id ELSE NULL END) AS iTunesPriceCount 
    , COUNT(DISTINCT CASE WHEN store <> 'Google' THEN vp.id ELSE NULL END) AS nonGooglePriceCount 
FROM title AS t 
    INNER JOIN version AS v ON t.id = v.title_id 
    INNER JOIN version_price AS vp ON v.id = vp.version_id 
GROUP BY t.id 

Примечание: ELSE NULL может быть опущен, так как если не предоставляется ИНАЧЕ подразумевается; но я включил для ясности.

+0

Я получаю сообщение об ошибке при попытке этого запроса. – David542

+0

@ David542 Я только что отредактировал его, у меня было какое-то из полей id. – Uueerdo

+0

второе решение отлично работает. Во-первых, у меня все еще возникают проблемы с запросом. – David542

0

Это может быть самым неэффективным из вышеуказанных ответов, но следующий подзапрос будет работать, используя %like% условие:

select *, case when stores like '%google%' then 1 else 0 end on_google 
from (select title.id, title.name, group_concat(distinct store order by store) stores 
from version inner join title on version.title_id=title.id inner join version_price 
on version_price.version_id=version.id group by title_id) x 

id name stores on_google 
1 Titanic Google,iTunes 1 
2 Avatar iTunes 0 
1

http://sqlfiddle.com/#!9/b8706/2

вы можете просто:

SELECT 
    title.id, 
    title.name, 
    group_concat(distinct version_price.store), 
    MAX(IF(version_price.store='google',1,0)) on_google 
FROM version 
INNER JOIN title 
ON version.title_id=title.id 
INNER JOIN version_price 
ON version_price.version_id=version.id 
GROUP BY title_id; 

и добавьте HAVING в запрос, если необходимо, чтобы записи были отфильтрованы:

SELECT 
    title.id, 
    title.name, 
    group_concat(distinct version_price.store), 
    MAX(IF(version_price.store='google',1,0)) on_google 
FROM version 
INNER JOIN title 
ON version.title_id=title.id 
INNER JOIN version_price 
ON version_price.version_id=version.id 
GROUP BY title_id 
HAVING on_google; 
Смежные вопросы