Первое - группировка, не знаю, прокатит или нет, но можно попробовать.
Код:
SELECT
RASSTOYANIE,
PEREVOZCHIK,
CASE
WHEN RASSTOYANIE <= 200 THEN 1
WHEN RASSTOYANIE > 200 AND RASSTOYANIE <= 400 THEN 2
WHEN RASSTOYANIE > 400 AND RASSTOYANIE <= 600 THEN 3
ELSE 4
END AS CATEGOTIYA
FROM VEDOMOST
SORT BY CATEGOTIYA
-- Если здесь не возьмет, то сортировать по полю RASSTOYANIE
-- Это не имеет значения
Это получение. Такой запрос можно и группировать.
Теперь что по поводу установки.
Фактически, тебе надо посчитать кол-во элементов и поделить их в соотв. пропорции (кстати, а у тебя в таблице перевозчиков суммарная доля не больше 100%?).
Тут делаем в несколько шагов.
1. Устанавливаем всем расстояниям <= 200 значение "компания" (делаем запросом, что бы не нагружать сеть - пусть СУБД трудится):
Код:
UPDATE VEDOMOST
SET PEREVOZCHIK = 'компания'
WHERE RASSTOYANIE <= 200
2. Теперь нам надо установить общее кол-во записей для распределения по другим перевозчикам. Опять же делаем всего 1 запрос:
Код:
SELECT count(*) FROM VEDOMOST WHERE RASSTOYANIE > 200
Фактически мы получим кол-во неустановленных строк.
Здесь маленнькая ремарка.
В эти 2 выборки не попадут ведомости, у которых значение расстояния не установлено, т.е. равно NULL. Что бы их добавить в тот или иной запрос, надо в конце добавить "OR RASSTOYANIE IS NULL" (без кавычек, соответсвенно).
3. Теперь нам надо посчитать сколько на 1% доли перевозчиков приходится записей в ведомосях.
Здесь, во первых, стахуемся от того, что суммарная доля м.б. > 100%.
Да, предполагаем, что там у тебя хранятся проценты, т.е. числа от 0 до 100.
Код:
SELECT SUM(DOLYA) FROM PEREVOZCHIKI
Тут мы получили суммарную долю всех перевозчиков в %%.
4. Теперь вычисляем сколько нам надо записей на 1%.
Это уже делаем в Delphi, хотя можно было сделать и за 1 шаг вместе с пп. 2 и 3, но тут есть специфичность от БД, так что не будем торопиться.
Код:
var
ItemsPerPercent : Integer;
begin
// Query1 - запрос из шага 2
// Query2 - запрос из шага 3
ItemsPerPercent := Round(Query1.Fields[0].AsInteger/Query2.Fields[0].AsInteger);
If ItemPerPercent = 0 Then Inc(ItemPerPercent);
Очередное замечание. If ItemPerPercent = 0 Then Inc(ItemPerPercent) - страховка от ошибки, когда на 1% приходится меньше 1 записи. В приципе, в таком случае кому-то недостанется чего везти, но это уже их пробема.
5. Теперь нам надо расставить перевозчиков.
Собственно, надо взять каждого перевозчика и посчитать сколько записей приходится на его долю, а затем пройти по ведомостям нужное кол-во строк и поставить их в значение этого перевозчика. Тут нам потребуется 2 запроса и маленький код на Delphi.
Запрос А. Получение перевозчиков. При этом сортируем их обратно пропорционально их доле (наиболее вероятно, что тебе все-таки хочется перевозчиков с большой долей удержать, загрузив их работой).
Код:
SELECT PEREVOZCHIK, DOLYA
FROM PEREVOZCHIKI
ORDER BY DOLYA DESC
Запрос Б. Получение неназначенных ведомостей. Кстати, их тоже можно как-нить отсортировать, но тут я не знаю от чего это может зависей. Запрос аналогичен запросу шага 2, но тут мы получаем список, а не одно число. Здесь нас интересует просто поле, где надо указать перевозчика, т.к. остальны ерасчеты мы уже сделали, ну и поле ID (надеюсь ты его не забыл) для идентификации записи.
Код:
SELECT ID, PEREVOZCHIK FROM VEDOMOST WHERE RASSTOYANIE > 200
И теперь маленький кусочек на Delphi, который расставит перевозчиков.
Сами значения будут устанавливаться с помощью запроса, т.к. мне прсто так удобнее.
Код:
const
UPD_QUERY = 'UPDATE VEDOMOST SET PEREVOZCHIK = ''%s'' WHERE ID = %d';
var
N : Integer;
C : Integer;
begin
// Query3 - запрос А
// Query4 - запрос Б
// Query5 - параметризованный запрос, которым мы и будем ставить значения.
Query3.Open;
Query4.Open;
Query5.SQL.Clear;
Query3.First;
Query4.First;
C := 0;
N := Query3.FieldByName['DOLYA'].AsInteger * ItemsPerPercent; // Кол-во записей для перевозчика.
While Not Query4.Eof Do
Begin
Query5.SQL.Clear;
Query5.SQL.Add(Format('UPD_QUERY',[ Query3.FieldByName('PEREVOZCHIK'].AsString,Query4.FieldByName['ID'].AsInteger));
Query5.ExecSQL;
Inc(C);
If C > N Then
Begin
Query3.Next;
N := Query3.FieldByName['DOLYA'].AsInteger * ItemsPerPercent; // Кол-во записей для перевозчика.
C := 0;
End;
Query4.Next;
End;
Собственно, что делается.
N - число записей в ведомостях, которые надо поставить для текущего перевозчика в соответсвии с его долей.
С - текущий счетчик.
Бежим по ведомостям и ставим туда текущего перевозчика. Если для текущего перевозчика мы посавили нужное кол-во ведомостей, то переходим с следующему, пересчитываем N и сбрасываем С.
PS. Можно написать и короче. Для себя бы я сократил всю эту кашу на треть и сделал бы это скорее на сервере (принцип не отличается) в виде хранимой процедуры, а с клиента (из Дельфей) просто дергал бы эту процедуру и выводил результат. Но зато тут подробно рассмотрен алгоритм решения такой задачи.