2015-09-30 3 views
1

Надеюсь, это имеет смысл.GROUP_CONCAT возвращает 1 строку для 0 результатов

У меня есть запрос, что я выполняю 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 
+1

Это не полный запрос ... у вас есть группа? – fthiella

+0

Я добавил полный запрос сейчас. – b3tac0d3

+0

все было нормально без полного запроса;) но лучше указать, что у вас нет группы по – fthiella

ответ

2

Несколько вещей о запросе, вы сказали, что вы не имеете 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 
... 

с использованием подзапросов.