Как выбрать строку для определенного (или дать предпочтение в выборе) в MySQL? - PullRequest
2 голосов
/ 20 июня 2010

Нужна ваша помощь, ребята в формировании запроса.

Пример. Компания - Прокат автомобилей

Таблица - Автомобили

ID  NAME       STATUS
1   Mercedes   Showroom
2   Mercedes   On-Road

Теперь, как мне выбрать только одну запись из этой таблицы, которая удовлетворяет следующим условиям?

  1. Если «Мерседес» доступен в автосалоне, выбрать только этот ряд. (то есть строка 1 в приведенном выше примере)

  2. Но если в автосалоне нет ни одного Мерседеса, возьмите любой из рядов. (то есть строка 1 или строка 2) - (это просто означает, что все Mercedes находятся в пути)

Использование различных данных здесь не помогает, поскольку идентификаторы также извлекаются в операторе выбора

Спасибо!

Ответы [ 4 ]

3 голосов
/ 20 июня 2010

Вот общий способ решения этой проблемы:

SELECT *,
CASE STATUS
WHEN 'Showroom' THEN 0
ELSE 1
END AS InShowRoom
FROM Cars
WHERE NAME = 'Mercedes'
ORDER BY InShowRoom
LIMIT 1

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

SELECT ID, NAME, IFNULL(c2.STATUS, c1.STATUS)
FROM Cars c1
LEFT OUTER JOIN Cars c2
ON c2.NAME = c1.NAME AND c2.STATUS = 'Showroom'
GROUP BY NAME
ORDER BY NAME
2 голосов
/ 20 июня 2010

Вы можете использовать функцию FIND_IN_SET() для этого.

SELECT *
FROM Cars
WHERE NAME = 'Mercedes'
ORDER BY FIND_IN_SET(`STATUS`,'Showroom') DESC
LIMIT 1

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

ORDER BY FIND_IN_SET(`STATUS`,'On-Road,Showroom' ) DESC

Чтобы получить «лучший» статус для всех автомобилей, вы можете просто сделать это:

SELECT *
FROM Cars
GROUP BY NAME
ORDER BY FIND_IN_SET(`STATUS`,'Showroom') DESC
1 голос
/ 20 июня 2010
SELECT * FROM cars 
  WHERE name = 'Mercedes' 
  AND status = 'Showroom' 
UNION SELECT * FROM cars 
  WHERE name = 'Mercedes' 
LIMIT 1;

РЕДАКТИРОВАТЬ Удалено ВСЕ в СОЮЗЕ, так как в любом случае нам нужны только отдельные строки.

0 голосов
/ 20 июня 2010

MySQL не имеет функций ранжирования / аналитики / управления окнами, но вы можете использовать переменную для имитации функциональности ROW_NUMBER (когда вы видите "-", это комментарий):

SELECT x.id, x.name, x.status
  FROM (SELECT t.id,
               t.name,
               t.status,
               CASE 
                 WHEN @car_name != t.name THEN @rownum := 1 -- reset on diff name
                 ELSE @rownum := @rownum + 1 
               END AS rank,
               @car_name := t.name -- necessary to set @car_name for the comparison
          FROM CARS t 
          JOIN (SELECT @rownum := NULL, @car_name := '') r
      ORDER BY t.name, t.status DESC) x  --ORDER BY is necessary for rank value
 WHERE x.rank = 1

Упорядочение по статусу DESC означает, что «Showroom» будет в верхней части списка, поэтому он будет оценен как 1. Если у названия автомобиля нет статуса «Showroom», строка, оцененная как 1, будет быть какой бы ни был статус после "Showroom". Предложение WHERE вернет только первую строку для каждого автомобиля в таблице.

Статус, являющийся типом данных на основе текста, говорит мне, что ваши данные не нормализованы - я мог бы добавить записи с "Showroom", "SHOWroom" и "showROOM". Они были бы действительны, но вы смотрите на использование таких функций, как LOWER & UPPER, когда вы группируете вещи для подсчета, суммирования и т. Д. Использование функций также сделает индекс столбца бесполезным ... Вы захотите рассмотреть возможность создания таблицы CAR_STATUS_TYPE_CODE и использовать отношение внешнего ключа, чтобы убедиться, что неверные данные не попадают в вашу таблицу:

DROP TABLE IF EXISTS `example`.`car_status_type_code`;
CREATE TABLE  `example`.`car_status_type_code` (
  `car_status_type_code_id` int(10) unsigned NOT NULL auto_increment,
  `description` varchar(45) NOT NULL default '',
  PRIMARY KEY  (`car_status_type_code_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
...