Можно в FB подключить в запрос таблицу по ее названию?

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Aleksandr.
Сообщения: 63
Зарегистрирован: 18 май 2005, 19:13

Можно в FB подключить в запрос таблицу по ее названию?

Сообщение Aleksandr. » 13 сен 2005, 14:27

Проще всего смысл вопроса выразить в запросе:

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

SELECT "idt", "table_name", (SELECT COUNT(*) FROM "table_name") FROM master
то есть мне из таблицы master нужно получить коды, названия таблиц и число записей в таблице, чье название содержится в table_name. В MS SQL такая задача решалась созданием функции, внутри которой формировалась строка запроса и выполнялся EXEC этой строки. А как это можно сделать в FireBird?

McArty
Сообщения: 56
Зарегистрирован: 14 янв 2005, 09:31

Re: Можно в FB подключить в запрос таблицу по ее названию?

Сообщение McArty » 13 сен 2005, 14:41

Aleksandr. писал(а): В MS SQL такая задача решалась созданием функции, внутри которой формировалась строка запроса и выполнялся EXEC этой строки. А как это можно сделать в FireBird?
То же самое
СМ Execute statement

Aleksandr.
Сообщения: 63
Зарегистрирован: 18 май 2005, 19:13

Нифига не получается...

Сообщение Aleksandr. » 13 сен 2005, 15:22

Пытаюсь выполнить

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

CREATE PROCEDURE GET_RECCOUNT (
    TBLNAME VARCHAR(10)) RETURNS (RС INT)
AS
DECLARE VARIABLE S VARCHAR(40);
begin
  S='SELECT COUNT(*) FROM '||TBLNAME;
  EXECUTE S INTO RС;
  suspend;
end
, но непонятно ему EXECUTE S. Из Langref ничего вытянуть не смог по этому поводу, "Мир Interbase" ни в магазинах ни на каких books.ru не найдешь в наличии, слепым котенком себя чувствую...

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

Сообщение kdv » 13 сен 2005, 16:13

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

p.s. описание всех новых фишек идет в Release Notes.
см. www.ibase.ru/firebird.htm

Aleksandr.
Сообщения: 63
Зарегистрирован: 18 май 2005, 19:13

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

Сообщение Aleksandr. » 13 сен 2005, 16:42

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

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

Сообщение kdv » 13 сен 2005, 16:56

гм, не понял идею. и про запросы, которые "дольше" - муть какая то, явно.

Aleksandr.
Сообщения: 63
Зарегистрирован: 18 май 2005, 19:13

Не получается оптимизировать...

Сообщение Aleksandr. » 16 сен 2005, 19:17

делай запросы динамически на сервер и отправляй их с клиента, готовыми
Не получается что-то.
Тем, кто организовывал форумы, наверное, задача будет знакома.

Есть таблица Received наподобие форумных с полями Id, ParentId, TopId, где ParentId - код записи, ответом к которой является данная, а TopId - код записи, являющейся самой верхней в ветке. По некоторым причинам в отдельную таблицу Readed (id, ReadedId) вынесена информация, прочитана ли информация из данной записи, хранящая в ReadedId Id прочитанной записи.
Задача получить из таблицы все записи, имеющие TopId = null и число отсутствующих в Readed id. Такой вот запрос:

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

select A.Id, (select count(*) from Received where TopId=A.Id
and Id not in (select ReadedId from Readed))
from Received A
where TopId is null
выглядит по-дурацки и вызывает безумный тормоз, а попытка вынести получение count в калькулируемое поле на клиенте, которое вычислять придется опять же запросом, ничего не изменит. Какие есть еще решения?

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

Сообщение kdv » 19 сен 2005, 09:50

www.ibase.ru/devinfo/joins.htm

тут есть пример аналогичного вытаскивания информации, через left join.

Aleksandr.
Сообщения: 63
Зарегистрирован: 18 май 2005, 19:13

Не понимаю...

Сообщение Aleksandr. » 19 сен 2005, 11:55

Моя тупость меня удручает. Тема с join знакома давно, постоянно ими пользуюсь, но не могу найти применения им для своего случая :(.

Из статьи смутное ощущение, что как-то это можно сделать, выловил, но какие-то реле в мозгу в упор не переключаются...

Я попытался сделать такой запрос:

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

select A.ID, COUNT(B.ID) FROM Received A 
LEFT JOIN Received B ON B.TopID=A.ID
WHERE A.TopID IS NULL AND B.ID NOT IN (SELECT ReadedID FROM Readed)
GROUP BY A.ID
Но он выполняется ровно столько же, сколько приведенный вариант, с одной разницей - происходит, судя по быстрому скроллингу результатов, сразу весь пересчет, тогда как в первом случае он производился на каждом фетче.

И вообще, если честно, я просто не понимаю, почему такие запросы, проскакивающие на MS SQL за доли секунды, в FB выполняются по 3-4 минуты :(

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

Сообщение kdv » 19 сен 2005, 13:03

блин, ну чего ты эту readied прикручиваешь через not in....

тебе надо объединить ее как
received left join readed
и вывести только те (where), где received.id is null
И вообще, если честно, я просто не понимаю, почему такие запросы, проскакивающие на MS SQL за доли секунды, в FB выполняются по 3-4 минуты
нет идеальных оптимизаторов, и потом, лучше писать sql более понятно для сервера, чем "в лоб"....
not in можно заменить на not exists, но думаю это мало поможет. попробуй.

tie
Сообщения: 39
Зарегистрирован: 14 июл 2005, 12:12

Re: Не понимаю...

Сообщение tie » 19 сен 2005, 13:09

Попробуй через ХП
что-то вроде:

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

 CREATE PROCEDURE F_TABLE
RETURNS (
    ID_T INTEGER,
    NAME_T VARCHAR(10),
    COUNT_T INTEGER)
AS
DECLARE VARIABLE S VARCHAR(10);
begin
  for SELECT 
     idt, 
     table_name
     FROM master
  into
    :ID_T,
    :NAME_T
  do
  begin
    execute statement 'select count(*) from '||NAME_T 
    into :COUNT_T;
    suspend;
  end
end
а вызывай

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

 select  ID_T, NAME_T, COUNT_T from F_TABLE
Последний раз редактировалось tie 19 сен 2005, 13:13, всего редактировалось 1 раз.

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

Сообщение kdv » 19 сен 2005, 13:12

и ЧТО это ему даст, позвольте спросить, уважаемый tie?

tie
Сообщения: 39
Зарегистрирован: 14 июл 2005, 12:12

Re: Нифига не получается...

Сообщение tie » 19 сен 2005, 13:17

Вернись к началу!!!!
Aleksandr. писал(а):Пытаюсь выполнить

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

CREATE PROCEDURE GET_RECCOUNT (
    TBLNAME VARCHAR(10)) RETURNS (RС INT)
AS
DECLARE VARIABLE S VARCHAR(40);
begin
  S='SELECT COUNT(*) FROM '||TBLNAME;
  EXECUTE S INTO RС;
  suspend;
end
, но непонятно ему EXECUTE S. Из Langref ничего вытянуть не смог по этому поводу, "Мир Interbase" ни в магазинах ни на каких books.ru не найдешь в наличии, слепым котенком себя чувствую...
здесь просто маленькая ошибка
нужно писать

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

 execute statement S into :RC;
или
execute statement 'SELECT COUNT(*) FROM '||TBLNAME into :RC;     

tie
Сообщения: 39
Зарегистрирован: 14 июл 2005, 12:12

Сообщение tie » 19 сен 2005, 13:22

kdv писал(а):и ЧТО это ему даст, позвольте спросить, уважаемый tie?
увеличит скорость
будет работать оптимальней....

сначачала выбираем все что нам нужно, а потом считаем....

Aleksandr.
Сообщения: 63
Зарегистрирован: 18 май 2005, 19:13

Бесполезно

Сообщение Aleksandr. » 19 сен 2005, 13:55

kdv писал(а):
тебе надо объединить ее как
received left join readed
и вывести только те (where), где received.id is null
Пробовал, абсолютно без разницы. Вообще, самым печальным в этом является то, что изначально таблица readed пустая, и ускорение выполнения запроса дает только ее наполнение - по крайней мере, у меня появление в ней нескольких readedid сразу дает ускорение на несколько секунд :(.

to tie:

Большое спасибо, но подход через хранимую процедуру только усугубляет время полного фетча.
Кстати, это уже не первый случай, когда попытка перевести join в хранимую процедуру приводит к такому результату - fetch на вмещающееся в grid число записей делается быстрее, но FetchAll делается немного медленнее.

Aleksandr.
Сообщения: 63
Зарегистрирован: 18 май 2005, 19:13

Бесполезно

Сообщение Aleksandr. » 19 сен 2005, 14:00

Не понимаю, "Отправить" у меня постоянно вызывает окошко с текстом запроса к MySQL...

kdv писал(а):
тебе надо объединить ее как
received left join readed
и вывести только те (where), где received.id is null
Пробовал, абсолютно без разницы. Вообще, самым печальным в этом является то, что изначально таблица readed пустая, и ускорение выполнения запроса дает только ее наполнение - по крайней мере, у меня появление в ней нескольких readedid сразу дает ускорение на несколько секунд :(.

to tie:

Большое спасибо, но подход через хранимую процедуру только усугубляет время полного фетча.
Кстати, это уже не первый случай, когда попытка перевести join в хранимую процедуру приводит к такому результату - fetch на вмещающееся в grid число записей делается быстрее, но FetchAll делается немного медленнее.

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

Сообщение kdv » 19 сен 2005, 14:04

проблема в том, что "найти те, для которых нет соответствия", может выполниться только полной проверкой источника, то есть Received.

Aleksandr.
Сообщения: 63
Зарегистрирован: 18 май 2005, 19:13

А если такой вариант

Сообщение Aleksandr. » 19 сен 2005, 14:52

А никто не пробовал работать с локальной фильтрацией TPFIBDataSet?

В смысле, я думаю попробовать вариант в таблицу Readed добавить поле TopID, соответствующее TopID из Received, а на клиенте через свойство фильтр получать на лету число записей в Reaed... Я как-то пробовал с Filter работать, но что-то возникло впечатление, что локальный фильтр для TPFIBDataSet работает медленнее, чем через параметризованный WHERE...

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 19 сен 2005, 15:53

kdv писал(а):проблема в том, что "найти те, для которых нет соответствия", может выполниться только полной проверкой источника, то есть Received.
Вот поэтому я бы предложил вывернуть схему наизнанку - хранить идентификаторы непрочитанных сообщений. Но по-всякому достаточно двух таблиц так что "подстановка имени таблицы в запрос" напрочь не нужна.

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

Сообщение kdv » 19 сен 2005, 16:30

вообще с этими "непрочитанными" стрём. Допустим человек только зашел - у него непрочитанные все. Если прочитал, потом зашел еще раз - непрочитанных мало.
я, например, когда делал флаги чтения, я просто по чтению добавлял событие в лог. а там уже смотрел на критерии, если было событие, то тогда ок, если нет - другая реакция. То есть никогда такого чтобы "показать непрочитанные" - не делал. Собственно, если документы имели маркировку "читал-не читал", это было всегда видно (можно цветом отобразить), и при желании отслеживания непрочитанных ссылки на них валились в специальную приватную папку (при создании нового сообщения).

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

Если предположить, что здесь дан только пример, и что в реальной БД отслеживаются "чтение "всех сообщений и для всех пользователей, то собственно, таблица readied будет пухнуть на глазах почем зря. Я бы, например, сделал какой-нибудь "отсекатель", то есть, по умолчанию все сообщения старше 1-ой недели от текущего дня считал бы "прочитанными". И т.д, и т.п.

p.s. mysql на форуме глюкает ужасно... уже второй раз портится табла search_wordlist. а там всего 40 тысяч записей...

Ответить