【问题标题】:GROUP_CONCAT returns 1 row for 0 resultsGROUP_CONCAT 为 0 个结果返回 1 行
【发布时间】:2015-12-28 18:00:48
【问题描述】:

我希望这是有道理的。

我有一个通过 PHP 运行的查询,作为查询的一部分,我正在使用 GROUP_CONCAT。它工作得很好,可以做我想做的一切,但如果结果为空,它仍然会返回 1 个带有一系列 NULL 值的结果。我知道是 GROUP_CONCAT 影响了这一点,因为如果我从查询中删除它,问题就不会发生。

另外,我很清楚我可以通过读取数组中的第一个变量来简单地用 PHP 解决这个问题,检查空值然后假设它是一个空字符串,但我更好奇为什么会发生这种情况如果有更好的方法,我可以在这里编写我的 SQL。

我不知道它是否会有所帮助,但这是我的查询

SELECT 
        m.id, m.RNID, m.DisplayLogoPath, m.DisplayName, m.TagLine, 
        (acos(sin(:lat)*sin(radians(m.Lat)) + cos(:lat)*cos(radians(m.Lat))*cos(radians(m.Lng)-:lon)) * :R) As Distance,
        a.Add1, a.Add2, a.City as CityOther, a.State as StateOther, a.Zip as ZipOther,
        g.primary_city, g.state, g.zip,
        p.AreaCode, p.Prefix, p.LineNum,
        h.Open, h.Close, h.Open24, h.Closed24,
        GROUP_CONCAT(DISTINCT(ra.Name)) as AlcoholArray,
        GROUP_CONCAT(DISTINCT(rc.Name)) AS CuisineArray,
        GROUP_CONCAT(DISTINCT(rd.Name)) AS DiningArray,
        k.id AS KidsMenu

        FROM 20_00_locations m

        /*Address*/
        LEFT JOIN 20_01_addresses a
        ON a.RestID = m.id
        AND a.active = 1
        AND a.Type = 1

        /*Geographic ref data*/
        LEFT JOIN 80_00_geo_data g
        ON g.id = a.CSZID

        /*Phone*/
        LEFT JOIN 20_01_phones p
        ON p.RestID = m.id
        AND p.active = 1
        AND p.Type = 1

        /*Restaurant hours*/
        LEFT JOIN 60_20_1_hours h
        ON m.HoursTempID = h.TempID
        AND h.DayNum = 1 /*Assigned dynamically*/

        /*Check the kids menu status - if Null, no kids menu. If id has value, kids menu*/
        LEFT JOIN 20_02_config k
        ON k.RestID = m.id
        AND k.active = 1
        AND k.OptID = 8
        and k.TypeID = 29

        /*Config used to get cuisine, alcohol, dining, etc*/
        LEFT JOIN 20_02_config c
        ON c.RestID = m.id
        AND c.active = 1

        /*Cusine types*/
        LEFT JOIN 80_00_master rc
        ON rc.IntID = c.OptID
        AND rc.ParID = 29
        AND c.TypeID = 29
        AND c.OptID <> 8

        /*Alcohol types*/
        LEFT JOIN 80_00_master ra
        ON ra.IntID = c.OptID
        AND ra.ParID = 30
        AND c.TypeID = 30

        /*Dining types*/
        LEFT JOIN 80_00_master rd
        ON rd.IntID = c.OptID
        AND rd.ParID = 31
        AND c.TypeID = 31

        /*Menu table*/
        WHERE (acos(sin(:lat)*sin(radians(m.Lat)) + cos(:lat)*cos(radians(m.Lat))*cos(radians(m.Lng)-:lon)) * :R) < :rad
        AND m.Lat Between :minLat And :maxLat
        AND m.Lng Between :minLon And :maxLon
        AND m.active = 1
        AND m.Published = 1

        ORDER BY Distance

【问题讨论】:

  • 这不是完整的查询...你有分组依据吗?
  • 我现在已经添加了完整的查询。
  • 没有完整的查询也没关系;) 但最好指定你没有 group by
  • 有道理。我没有分组,但我猜我应该看看它;)
  • 我刚试了一下,分组解决了这个问题。非常简单,但它却让我望而却步。感谢您的反馈。如果您想发布它@fthiella,我很乐意为答案 +1

标签: php mysql group-concat


【解决方案1】:

关于您的查询的几件事,您说您没有 GROUP BY 但您正在选择一些非聚合列:

SELECT
  m.id, m.RNID, m.DisplayLogoPath, m.DisplayName, m.TagLine, ...

并且您正在使用一些聚合函数 GROUP_CONCAT:

GROUP_CONCAT(DISTINCT(ra.Name)) as AlcoholArray,
GROUP_CONCAT(DISTINCT(rc.Name)) AS CuisineArray,
GROUP_CONCAT(DISTINCT(rd.Name)) AS DiningArray,

因此您的查询将始终返回 1 行,但 m.id、m.RNID 等的值将不确定(它们可能来自第一行,或来自任何其他行)。

因此您可能希望删除所有非聚合列,并使用 HAVING 子句:

SELECT GROUP_CONCAT(...)
FROM ...
HAVING COUNT(*)>0

但是!您可能只是缺少一个 GROUP BY,我认为这应该足够了:

GROUP BY m.id

请注意,这不符合 SQL,但 MySQL 会很乐意执行它,并且(如果我理解正确的话)即使它不被认为是好的做法,它也会返回正确的结果。

但我更愿意将您的查询重写为:

SELECT
  m.id, ...,
  ra.AlcoholArray,
  rc.CuisineArray,
  ...
FROM
  20_00_locations m LEFT JOIN 20_01_addresses a ON ...
  LEFT JOIN 80_00_geo_data g ON ...
  ...
  LEFT JOIN (
    SELECT IntID, GROUP_CONCAT(Name) AS CuisineArray
    FROM 80_00_master
    WHERE
      rc.ParID = 29
    GROUP BY IntID
  ) rc ON rc.IntID = c.OptID
...

使用子查询。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-22
    相关资源
    最近更新 更多