Проблема с условием выбора

IBX, FIBPlus, UIB, ADO, .Net и прочее-прочее-прочее, в общем все, что относится к созданию приложений, работающих с InterBase, Firebird и Yaffil - клиент-серверных, трехзвенных, консольных и т.п.

Модератор: kdv

Ответить
ostin
Сообщения: 10
Зарегистрирован: 10 сен 2007, 19:32

Проблема с условием выбора

Сообщение ostin » 23 дек 2007, 21:02

Помогите разобраться. Мне нужно выбрать из таблице записи с возможность отфильтровать ее по 4 полям или по 3, вообщем зависит от пользователя по каким параметрам ему нужно получит отчет, все поля не null.
Так я представляю себе эту процедуру так,

Код: Выделить всё

CREATE PROCEDURE new (
    a integer,
    b integer,
    c integer,
    d integer)
RETURNS (
    id INTEGER)
AS
BEGIN
for select id
 from table1
  where field1 = :a and field2 = :b and field3 = :c and field4 = :d
      into :id
  do
 suspend;
END
где может быть так
where field1 = 1 and field2 = 2 and field3 = 3 and field4 = 4
или так
where field1 is not null and field2 = 1 and field3 = 2 and field4 = 3
каким способом можно это реализовать.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 23 дек 2007, 23:04

а зачем для этого процедуру городить?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 24 дек 2007, 12:03

Самое правильное решение тут - это формировать запрос динамически на клиенте по заданным условиям фильтра. И едиственное решение в случае большого числа фильтруемых записей.

Есть ещё путь, но это только когда некуда деваться, а именно
where (Field1 is null or Field1 = :a) and (Field2 is null or Field2 = :b) ...
Это позволит отключить фильтр по полю, если передать в параметр null.
Однако, если записей не 100, то производительность упадёт катастрофически (индексы не используются для отбора по таким условиям), выборка 1 записи, попадающей под условия, будет выполняться столько же, сколько целиком выборка без условий.

Кузнецов Евгений
Сообщения: 144
Зарегистрирован: 16 фев 2006, 22:36

Сообщение Кузнецов Евгений » 24 дек 2007, 12:59

WildSery писал(а): Самое правильное решение тут - это формировать запрос динамически на клиенте по заданным условиям фильтра. И едиственное решение в случае большого числа фильтруемых записей.
В FB 2 можно выкрутиться через IS NOT DISTINCT FROM

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 24 дек 2007, 13:31

Кузнецов Евгений писал(а):В FB 2 можно выкрутиться через IS NOT DISTINCT FROM
Что-то не могу сообразить, какое должно быть условие.
Ведь если параметр будет NULL, то и найдены будут только значения NULL?

Кузнецов Евгений
Сообщения: 144
Зарегистрирован: 16 фев 2006, 22:36

Сообщение Кузнецов Евгений » 24 дек 2007, 14:58

WildSery писал(а): Ведь если параметр будет NULL, то и найдены будут только значения NULL?
Стормозил, каюсь - IS DISTINCT ничем не поможет.

Единственное замечание - для
WildSery писал(а): where (Field1 is null or Field1 = :a) and (Field2 is null or Field2 = :b) ...
индексы всё же могут использоваться.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 24 дек 2007, 15:40

Кузнецов Евгений писал(а):индексы всё же могут использоваться.
Это каким образом?

Кузнецов Евгений
Сообщения: 144
Зарегистрирован: 16 фев 2006, 22:36

Сообщение Кузнецов Евгений » 24 дек 2007, 16:12

WildSery писал(а):Это каким образом?
Ну для

Код: Выделить всё

select * from test_table2
where  (Field1 is null or Field1 = :a) and
(Field2 is null or Field2 = :a)
план следующий

Код: Выделить всё

PLAN (TEST_TABLE2 INDEX (TEST_W2, TEST_W2, TEST_W1, TEST_W1))
Test_w1 - индекс по Field1
Test_w2 - индекс по Field2

DMA
Сообщения: 6
Зарегистрирован: 24 дек 2007, 17:03

Сообщение DMA » 24 дек 2007, 17:09

А может так: select * from test_table2
where (Field1 = :a or :a is null) and
(Field2 = :b or :b is null) and
(Field3 = :c or :c is null) and
(Field4 = :d or :d is null)

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 24 дек 2007, 17:16

Тьфу ты, точно.
Прошу прощения, это я пример неправильный изначально написал, и больше на него не смотрел, и получается что гоню ерунду.
На самом деле, я хотел написать

Код: Выделить всё

where  (cast(:a as int) is null or Field1 = :a) and (cast(:b as int) or Field2 = :b)
Вариант без каста прокатит в случае процедуры, где тип параметра явно определён.

ostin
Сообщения: 10
Зарегистрирован: 10 сен 2007, 19:32

Сообщение ostin » 26 дек 2007, 19:51

Спасибо всем кто ответил мне. прочитав все я буду искать наилучшие вариант решения моей проблемы. Спасибо еще раз

Ответить