Mysql4: SQL для выбора одной или нулевой записи - PullRequest
1 голос
/ 27 февраля 2009

Таблица раскладки:

CREATE TABLE t_order  (id INT, custId INT, order DATE)

Я ищу команду SQL для выбора не более одной строки на заказ (клиент, которому принадлежит заказ, определяется полем с именем custId).

Я хочу выбрать ОДИН заказов клиента (неважно, какой из них, скажем, отсортированный по id), если для какой-либо строки не указана дата заказа.

Я хочу получить пустой Resultset для customerId, если уже есть запись с заданной датой заказа.

Вот пример. Для каждого клиента должен быть не более одного заказа (один без указания даты). Заказы, которые уже имеют значение даты, вообще не должны появляться.

  +---------------------------------------------------------+
  |id    |    custId       |  date                          |
  +---------------------------------------------------------+
  | 1              10         NULL                          |
  | 2              11         2008-11-11                    |
  | 3              12         2008-10-23                    |
  | 4              11         NULL                          |
  | 5              13         NULL                          |
  | 6              13         NULL                          |
  +---------------------------------------------------------+
                           |
                           |
                           |      Result
                         \ |  /
                          \  /
  +---------------------------------------------------------+
  |id    |    custId       |  date                          |
  +---------------------------------------------------------+
  | 1              10         NULL                          |
  |                                                         |
  |                                                         |
  |                                                         |
  | 5              13         NULL                          |
  |                                                         |
  +---------------------------------------------------------+
                                powered be JavE

Edit: Я выбрал ответ Главича как правильный, потому что он обеспечивает правильный результат со слегка измененными данными:

  +---------------------------------------------------------+
  |id    |    custId       |  date                          |
  +---------------------------------------------------------+
  | 1              10         NULL                          |
  | 2              11         2008-11-11                    |
  | 3              12         2008-10-23                    |
  | 4              11         NULL                          |
  | 5              13         NULL                          |
  | 6              13         NULL                          |
  | 7              11         NULL                          |
  +---------------------------------------------------------+

Ответ Sfossen не сработает, когда клиенты появляются более двух раз из-за ограничения предложения where a.id! = B.id.

Ответ Quassnoi не работает для меня, так как я запускаю версию сервера 4.0.24, которая выдает следующую ошибку: альтернативный текст http://img25.imageshack.us/img25/8186/picture1vyj.png

Ответы [ 4 ]

2 голосов
/ 28 февраля 2009

Для конкретного клиента это:

SELECT *
FROM t_order
WHERE date IS NULL AND custId=? LIMIT 1

Для всех клиентов это:

SELECT a.*
FROM t_order a 
    LEFT JOIN t_order b ON a.custId=b.custID and a.id != b.id
WHERE a.date IS NULL AND b.date IS NULL
GROUP BY custId;
1 голос
/ 28 февраля 2009

В этом запросе будет использоваться один индекс передачи при custId.

Для каждого отдельного custId он будет использовать один подзапрос над тем же индексом.

Нет GROUP BY, нет TEMPORARY и нет FILESORT - эффективно, если ваш стол большой.

SELECT VERSION()

--------
'4.1.22-standard'

CREATE INDEX ix_order_cust_id ON t_order(custId)

SELECT id, custId, order_date
FROM (
  SELECT o.*,
    CASE
      WHEN custId <> @c THEN
        (
        SELECT 1
        FROM   t_order oi
        WHERE  oi.custId = o.custId
          AND  order_date IS NOT NULL
        LIMIT 1
        )
    END AS n,
    @c <> custId AS f,
    @c := custId
  FROM
    (
    SELECT @c := -1
    ) r,
    t_order o
  ORDER BY custId
) oo
WHERE n IS NULL AND f

---------
1, 10, ''
5, 13, ''
1 голос
/ 27 февраля 2009

Попробуйте это:

SELECT to1.*
FROM t_order AS to1
WHERE
    to1.date IS NULL AND 
    to1.custId NOT IN (
        SELECT to2.custId
        FROM t_order AS to2
        WHERE to2.date IS NOT NULL
        GROUP BY to2.custId
    )
GROUP BY to1.custId

Для MySQL 4:

SELECT to1.*
FROM t_order AS to1
LEFT JOIN t_order AS to2 ON
    to2.custId = to1.custId AND
    to2.date IS NOT NULL
WHERE
    to1.date IS NULL AND 
    to2.id IS NULL
GROUP BY to1.custId
0 голосов
/ 28 февраля 2009

Сначала отфильтруйте строки с датами, а затем отфильтруйте все строки с похожей строкой с меньшим идентификатором. Это должно работать, потому что совпадающая запись с наименьшим идентификатором является уникальной, если идентификатор уникален.

select * from t_order o1
    where date is null
      and not exists (select * from t_order o2
                         where o2.date is null
                           and o1.custId = o2.custId
                           and o1.id > o2.id)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...