Mysql 如何在组_concat中执行子查询

Mysql 如何在组_concat中执行子查询,mysql,sql,Mysql,Sql,我有以下数据模型: `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 - i

我有以下数据模型:

`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
我想构造一个查询,它将为我提供所有在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
这给了我一个小组会议,向我展示了我所拥有的:

id  name    group_concat(distinct store order by store) 
1   Titanic Google,iTunes                               
2   Avatar  iTunes                                       
但是,我该如何构造一个查询,以包括该项目是否在谷歌上,并使用case语句或任何需要的内容

id  name    group_concat(distinct store order by store) on_google 
1   Titanic Google,iTunes                                true
2   Avatar  iTunes                                       false
它基本上是执行一个像“%google%”这样的组concat,而不是一个普通的where子句


下面是我当前查询的一个SQL链接:

我会像下面这样做

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

语法可能有点不对劲,因为我现在无法测试它,但我相信这就是您想要的精神。交叉应用也是一个非常有效的连接,它总是很有用的

使用条件聚合来确定标题是否在指定的存储中

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

countcase当store='google'然后1 end>=1将1分配给包含google的行后,对给定标题的所有行进行计数。否则,它们将被赋值为null,而计数将忽略null。此后,如果标题上至少有一个谷歌商店,则if会检查其数量并对其进行分类。

这将为您提供不在谷歌上的版本价格数字,以及谷歌上的版本价格数字。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
或者对于与vkp类似的另一种解决方案:

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可以省略,因为如果没有提供ELSE,它是隐含的;但是为了清楚起见,我加入了。

这可能是上述答案中效率最低的一个,但是下面的子查询可以工作,使用%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
你可以:

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;
如果需要筛选记录,则在查询中添加:

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;

谷歌商店在哪里?为你过滤东西不是group_concat的工作,除了不同的东西。过滤是在where子句中完成的。您希望得到什么?1 |泰坦尼克号|谷歌、iTunes还是仅仅1 |泰坦尼克号| iTunes?@MarcB请查看最新问题。我从未听说过交叉申请。这对mysql有效吗?另外,您可以在这里的sqlfiddle上尝试它,以测试它是否有效:给我几分钟,我会响应!在调查之后,我在MySQL中没有看到任何交叉应用。对不起!我想这个解决方案只适用于MSSQL,可能也适用于SQL。非常好,这个方法很好,而且比我目前的子查询方法要好得多。请您在回答中解释一下下面这行内容以及它是如何工作的?如果countcase当store='google'时,则1 end>=1,'true','false'与在谷歌上一样。如何使用ifcount。。。与正常情况不同?添加了解释。@David542我刚刚编辑了它,我将一些id字段颠倒了。第二种解决方案效果很好。第一个问题我在运行查询时仍然遇到一些问题。@David542我想现在已经解决了第一个问题;我省略了一个ON,并在第二个左连接到version_price的条件中使用了错误的别名。