2013-06-26 4 views
0

У меня есть следующие таблицы в базе данных MySQL:SQL запроса получить наименьшее значение из соответствующей записи, подзапрос

mechanics: id, name, distance 
mechanic_zones: mechanic_id, zone, radius 

Стол механика записывает механику, идентификатор, имя, и их расстояние от работы (это фактически рассчитывается почтовый индекс механиком и почтовый индекс работы, но я упростил это для ясности)

таблица mechanic_zones позволяет механику определить радиусы для их зон и используется для определения цены на работу

mechanics: 
1, Jon, 5.4 
2, Paul, 6.5 
3, George, 20 


mechanic_zones: 
1, a, 5 
1, b, 10 
1, c, 20 
2, a, 10 
2, b, 20 
2, c, 50 
3, a, 5 
3, b, 10 
3, c, 15 

У Jon есть свои зоны, определяемые как: a - 5 миль, b - 10 миль и c - 20 миль.

Пол имеет свои зоны, определяемые как: a - 10 миль, b - 20 миль и c - 50 миль.

Джордж имеет свои зоны, определяемые как: a - 5 миль, b - 10 миль и c - 15 миль.

Я хочу, чтобы найти самую низкую зону для механика для работы. В примере Jon 5,4 милях от работы, Павел 6,5, и Джордж 20.

Так что запрос должен вернуть что-то вроде:

mechanic_id, name, zone, distance 
2, Paul, A, 6.5 
1, Jon, B, 5.4 

Работа находится в зонах Павла А потому, что в 6,5 милях его в пределах 10 миль, определенных как зона A.

Его в зоне Бона Джона, потому что его больше, чем его 5 миль зоны А, но меньше, чем его 10-мильный предел для его зоны B.

Это не для зоны для Джорджа, как его больше, чем его 20 миль C зоны.

Это, насколько я получил:

SELECT id, name, (distance * 1) as distance_to_job, min(mz.`zone`) as min_zone, min(mz.radius) as min_radius, max(mz.`zone`) as max_zone, max(mz.radius) as max_radius 
FROM mechanics m, mechanic_zones mz 
WHERE m.id = mz.mechanic_id 
GROUP BY m.id, postcode 
HAVING distance_to_job < max_radius 
ORDER BY distance_to_job ASC, radius ASC 

Который (я думаю) дает мне всю механику, которые находятся в зоне, но на самом деле не выяснить, какая зона расстояние в.

Любая помощь очень ценится

ответ

1

Вы должны использовать дополнительный подзапрос, чтобы выяснить, что минимальный радиус в механике (где радиус больше, чем расстояние), а затем вы можете присоединиться к этой обратно на два столы и получить всю информацию столбца вам нужно от двух таблиц:

SELECT m.ID, mz.Zone, m.distance, mz.radius 
FROM Mechanics m 
     INNER JOIN mechanic_zones mz 
      ON mz.Mechanic_ID = m.ID 
     INNER JOIN 
     ( SELECT m.ID, 
        MIN(mz.radius) AS radius 
      FROM Mechanics m 
        INNER JOIN mechanic_zones mz 
         ON mz.Mechanic_ID = m.ID 
      WHERE mz.radius > M.distance 
      GROUP BY m.ID 
     ) MinZone 
      ON MinZone.ID = m.ID 
      AND MinZone.radius= mz.radius 
ORDER BY mz.Zone; 

Example on SQL Fiddle

Если вы на самом деле не хотят знать radiu s выбранной зоны и зоны с наименьшим радиусом всегда будет иметь самое низкое письмо, которое вы можете просто использовать:

SELECT m.ID, mz.MinZone, m.distance 
FROM Mechanics m 
     INNER JOIN 
     ( SELECT m.ID, 
        MIN(mz.Zone) AS Zone 
      FROM Mechanics m 
        INNER JOIN mechanic_zones mz 
         ON mz.Mechanic_ID = m.ID 
      WHERE mz.radius > M.distance 
      GROUP BY m.ID 
     ) MinZone 
      ON MinZone.ID = m.ID 
ORDER BY MinZone.Zone; 

Example on SQL Fiddle

EDIT

Ваша скрипка очень близко к тому, что я буду использовать, но я бы использовал следующее, чтобы расчет проводился только один раз:

SELECT m.id, m.name, m.distance, m.radius, m.zone 
FROM ( SELECT m.ID, 
        m.Name, 
        m.Distance, 
        MIN(mz.radius) AS radius 
      FROM ( SELECT ID, Name, (1 * Distance) AS Distance 
         FROM Mechanics 
        ) m 
        INNER JOIN mechanic_zones mz 
         ON mz.Mechanic_ID = m.ID 
      WHERE mz.radius > M.distance 
      GROUP BY m.ID, m.Name, m.Distance 
     ) m 
     INNER JOIN mechanic_zones mz 
      ON mz.Mechanic_ID = m.ID 
      AND mz.radius = m.radius; 

Example on SQL Fiddle

Причина в том, что ваш запрос имеет столбцы в списке выбора, а не в группе по, так что нет никакой гарантии, что радиус возвращается будет самая низкая. Например, если изменить порядок, в котором записи будут вставлены в mechanic_zones (as in this fiddle) вы результаты становятся:

ID NAME DTJ  RADIUS ZONE 
1 Jon  2  10  a 
2 Paul 11  50  b 
3 George 5  5  a 

Вместо

ID NAME DTJ  RADIUS ZONE 
1 Jon  2  5  a 
2 Paul 11  20  b 
3 George 5  5  a 

Как вы можете увидеть радиус для Джона является неправильным. Объяснить это ниже - выдержка из объяснения, которое я написал о коротких моментах приведения MySQL в неявную группировку.


Я бы посоветовал, чтобы избежать неявной группировки, предлагаемый MySQL, где это возможно, при этом я имею в виду в том числе столбцов в списке выбора, даже если они не содержится в агрегатной функции или группы по п.

Представьте себе следующую простую таблицу (T):

ID | Column1 | Column2 | 
----|---------+----------| 
1 | A | X  | 
2 | A | Y  | 

В MySQL вы можете написать

SELECT ID, Column1, Column2 
FROM T 
GROUP BY Column1; 

Это фактически разрушает SQL Standard, но он работает в MySQL, однако проблема в том, что не недетерминированно, результат:

ID | Column1 | Column2 | 
----|---------+----------| 
1 | A | X  | 

не является более или менее правильно, чем

ID | Column1 | Column2 | 
----|---------+----------| 
2 | A | Y  | 

Так что вы говорите, дайте мне одну строку для каждого отдельного значения Column1, что оба результата множества удовлетворяют, так как вы знаете, какой из них вы получите? Ну вы этого не сделаете, это, кажется, довольно распространенное заблуждение, что вы можете добавлять и ORDER BY положение, чтобы повлиять на результаты, так, например, следующий запрос:

SELECT ID, Column1, Column2 
FROM T 
GROUP BY Column1 
ORDER BY ID DESC; 

гарантировало бы, что вы получите следующий результат:

ID | Column1 | Column2 | 
----|---------+----------| 
2 | A | Y  | 

из-за ORDER BY ID DESC, однако это не так (as demonstrated here).

MMySQL documents состояния:

Сервер может свободно выбрать любое значение из каждой группы, так что, если они не совпадают, значение, выбранное неопределенно. Более того, выбор значений из каждой группы не может зависеть от добавления предложения ORDER BY.

Таким образом, даже если у вас есть такой порядок, это не применяется до тех пор, пока не будет выбрана одна строка для каждой группы, и эта одна строка не определена.

SQL-стандарт разрешает столбцы в списке выбора, не содержащиеся в GROUP BY или агрегатной функции, однако эти столбцы должны быть функционально зависимыми от столбца в GROUP BY. Например, идентификатор в таблице образцов является PRIMARY KEY, поэтому мы знаем, что он уникален в таблице, поэтому следующий запрос соответствует стандарту SQL и будет работать в MySQL и не работать во многих СУБД в настоящее время (во время написания Postgresql является ближайшим СУБД я знаю правильно реализации стандарта):

SELECT ID, Column1, Column2 
FROM T 
GROUP BY ID; 

Поскольку идентификатор уникален для каждой строки, может быть только одно значение Column1 для каждого идентификатора, одно значение Column2 не существует никакой двусмысленности что возвращать для каждой строки.

+0

Спасибо, Гарет. Я думаю, что ошибался в том, что расчет расстояния не имеет значения (он действительно работает на расстоянии, используя почтовый индекс механики), но поскольку он рассчитан, я не могу тогда ссылаться на него в результате: я думаю, это иллюстрирует это: http://sqlfiddle.com/#!2/e4b60/11, еще раз спасибо за ваш ответ – jx12345

+0

Я обновил вопрос, чтобы уточнить – jx12345

+0

В какой момент рассчитано расстояние? – GarethD