Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2004.07.25;
Скачать: [xml.tar.bz2];

Вниз

Как застраховаться от нулевых вложенных запросов?   Найти похожие ветки 

 
Boroda Oleg   (2004-06-30 21:39) [0]

Если при написании запроса используются вложенные запросы, то иногда случается ситуация, когда вложеный запрос выдает пустое значение (возможно NULL), и расчет дальше не идет. Возможно ли как-то застраховаться от этого нуля.
Подробнее:
Имеем таблицу Table. В ней поля: ID, DOLG
Имеем таблицу OPLATA. В ней поля: ID_table, SUMM
Значения ID и ID_TABLE - цедые, DOLG и SUMM - с точкой.

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

SELECT T.DOLG
      (SELECT SUM(OP.SUMM) FROM OPLATA OP
       WHERE (OP.ID_TABLE = T.ID)) S_OPL,
      T.DOLG-
      (SELECT SUM(OP.SUMM) FROM OPLATA OP
       WHERE (OP.ID_TABLE = T.ID)) OSTATOK
FROM TABLE T

Если имеется хотя-бы одна оплата, значения S_OPL и OSTATOK считаются правильно. Если нет ни одной оплаты, оба они пусты (хотя, по идее OSTATOK должен быть равен DOLG). Как с этим бороться?

И еще, вдогонку. Если мы, предположим, имеем два поля DOLG1 и DOLG2 - как научить SQL понимать выражение:
Если DOLG2 = 0, то результат = DOLG1
иначе результат = DOLG2


 
P.N.P. ©   (2004-06-30 22:06) [1]

Можно UDF написать с проверкой значений,
или готовую взять где-нибудь


 
Fay ©   (2004-06-30 22:35) [2]

fb15 + coalesce


 
Vemer ©   (2004-07-01 00:53) [3]

Сделай ХП с проверкой по COUNT..


 
Boroda Oleg   (2004-07-01 09:32) [4]

У меня тоже мысли насчет процедуры или функции... Только вот, хоть убей, не помню, как ее в SQL засунуть. Народ, подскажите, плис формат.


 
Johnmen ©   (2004-07-01 09:35) [5]

Наиболее "дешёвый" вариант с дополнительными бонусами - перейти на FB1.5


 
Desdechado ©   (2004-07-01 10:33) [6]

чтобы NULL превратить в 0, используй функцию из UDF-библиотеки RFunc


 
Boroda Oleg   (2004-07-01 11:17) [7]

ЛЮДИ!!!!
Как эту дурную процедуру или функцию вызвать в SQL запросе ???


 
Johnmen ©   (2004-07-01 11:18) [8]

Какую функцию ?


 
Boroda Oleg   (2004-07-01 11:28) [9]

Любую. Как составить запрос так, чтобы в нем вызвать функцию?

Имеется процедура MyProcedure(A : integer):integer
(как точно писать не знаю, пишу как в Дельфе)

Нужно вызвать ее в SQL запросе, что-то типа:

SELECT ID, NAME, DOLG,
      MyProcedure(DOLG) OSTATOK, ...
      ^^^^^^^^^^^^^^^^^
      какой формат вызова правильный? У меня на MyProcedure плюется как на заразу.
 И еще, если возвращаются 2 цифры, как это писать нужно (в смысле вызывать).


 
asp ©   (2004-07-01 11:33) [10]

Boroda Oleg   (30.06.04 21:39) > СУБД?


 
Johnmen ©   (2004-07-01 11:36) [11]

>Boroda Oleg   (01.07.04 11:28) [9]

>Имеется процедура MyProcedure(A : integer):integer

Может это ф-ия всё-таки ?
И где она имеется ?
И вообще на ibase.ru ходил ?


 
Boroda oleg   (2004-07-01 11:55) [12]

>> Имеется процедура MyProcedure(A : integer):integer

> Может это ф-ия всё-таки ?
> И где она имеется ?
> И вообще на ibase.ru ходил ?

Процедура. Сам я ее нарисовал.
На ibase.ru счас пойду, только что там искать....


 
Johnmen ©   (2004-07-01 11:57) [13]

>Процедура. Сам я ее нарисовал.

:)
Процедура, возвращающая значение, обычно называется функцией...
Где ты ее нарисовал ?


 
Соловьев ©   (2004-07-01 11:59) [14]


> Имеется процедура MyProcedure(A : integer):integer

хранимая?


 
kaif ©   (2004-07-01 12:36) [15]

Вообще-то, ИМХО, не стоит так организовывать сами таблицы.
Нормальная система учата платежей бывает устроена иначе, например, так:

ID   OP_DATE      PLATELSCHIK  DEBIT  CREDIT
=============================================
1   "01.01.2004"      113      1000    0      //начисление долга
2   "05.01.2004"      113         0    200    //платеж
3   "05.01.2004"      113         0    100    //платеж
4   "05.01.2004"      113         0    500    //платеж

Тогда если нужно узнать, сколько кто должен, делается простой запрос:
SELECT PLATELSCHIK, SUM(DEBIT - CREDIT) DOLG
FROM TABLE1
GROUP BY PLATELSCHIK

И никаких проблем с NULL и т.п. вещами.

С уважением.


 
Boroda Oleg   (2004-07-01 12:38) [16]

Господа!!!

Дошел сам.

Процедура вызывается:
SELECT OPLAT FROM MyProcedure (ID)

Вот блин!!


 
Boroda Oleg   (2004-07-01 12:42) [17]

2 kaif
У меня задача несколько иная: учет должников.
Т.е. у каждого есть некий долг. И, по идее, этот долг должен гаситься - или одной суммой, или частями (что реально происходит чаще). Поэтому сам долг - в первой таблице, а опаты - во второй.


 
kaif ©   (2004-07-01 12:51) [18]

2 Boroda Oleg  
А что, то, что я написал, разве это не учет должников?
А теперь скажи, что получится при твоем подходе и при том, что я показал, если чел задолжал 1000, а потом заплатил 600, а потом задолжал еще 1000 и потом разом заплатил 1400. В моей таблице после запроса его долг будет равен ровно 0. А в твоей системе таблиц как учесть такие 4 операции?


 
kaif ©   (2004-07-01 12:57) [19]

И еще с чего ты взял, что бывают только должники? А если кто-то предоплатил что-то? Тогда что, будешь ему в таблицу долгов "минус" писать, а в таблицу "оплат" писать отгрузку ему "товара/услуги"? Чем начисление долга отличается от начисления платежа, чтобы видеть в этом отношение один-ко-многим? Только потому что "как правило" платят частями? Но вот простой пример, что я привел:
1000
    600
1000
    1400
-----------
0

Где здесь можно один-ко-многим углядеть?
И "одного такого случая" достаточно.

Хотя, как говорится, дело хозяйское...


 
kaif ©   (2004-07-01 13:01) [20]

Самое интересное произойдет в твоей системе при "предоплате". Представим себе физиономию клиента, которому отказали в предоплате, мотивировав это нарушением внешнего ключа в 2 таблицах. Типа "если угодно с нами работать, будьте добры стать должником". Предоплату не принимаем.


 
Boroda Oleg   (2004-07-01 13:44) [21]

Опять ты не так понял.

Ведется учет ТОЛЬКО ДОЛЖНИКОВ.

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

Вообще - цель программы - учет дебиторской задолженности. Дебитором клиент становится только если он не расплатился в рамках договорных обязательств.


 
TohaNik ©   (2004-07-01 13:56) [22]

>Если человек расплатился, он из программы либо вообще удаляется, либо каким-то образом блокируется. Даже если он переплатил, то разбираться с ним будет его менеджер.

Рекет какойто:))


 
Boroda oleg   (2004-07-01 15:09) [23]

Люди, а как все-таки два или больше значения получить при вызове хранимой процедуры из SQL запроса? У меня в процедуре вернуться должно 2 значения. При выполнении:

SELECT OPLAT FROM MyProcedure (ID)

выдается, естественно 1 значение. Сколько я не пытался воткнуть возле OPLAT еще оду переменную - SQL редактор плюется как на бешенного. Как до нее добраться то?


 
Dazhan   (2004-07-01 17:02) [24]

Зечем вести учет ТОЛЬКО ДЕБИТОРОВ в  двух таблицах с геморройем, когда можно вести учет ВСЕХ ЧУВАКОВ в одной таблице без геморойя?
Если же нужны ТОЛЬКО ДОЛЖНИКИ, то получать их детским запросом:

SELECT SUM(DEBIT-CREDIT), PLATELSCHIK
FROM TABLE1
GROUP BY PLATELSCHIK
HAVING SUM(DEBIT-CREDIT) > 0

Если слова DEBIT CREDIT пугают, то для понятности можно их назвать: POPAL и ZAPLATIL
:)


 
stud ©   (2004-07-01 17:12) [25]

можно и в двух таблицах вести, а у каждого клиента добавить поле баланс например, который будет автоматически изменяться в зависимости от операции (платеж или услуги) и не надо никаких процедур и объединений таблиц. все одним запросом из одной таблицы и клиент и его долг - не долг


 
Boroda Oleg   (2004-07-01 17:17) [26]

Оно конечно хорошо, но только в случае, если мне кто-то платит каждый день по 1 000 р. (при сумме долга в 1 000 000), то у меня только на этого должника возникнет 1 000 записей. Хотя сейчас и веники по 200 Гиг держат, но с такими тратами скоро и их не хватит. :))

Люди, и подскажите кто, если знает, как все-таки два или больше значения получить при вызове хранимой процедуры из SQL запроса? Подробнее расписал чуть выше.


 
stud ©   (2004-07-01 17:20) [27]

так создай в ней два выходных параметра


 
stud ©   (2004-07-01 17:21) [28]

begin
 select1 ...... into par1
 select2 ...... into par2
 suspend;
end


 
Boroda oleg   (2004-07-01 19:07) [29]

Угу. Так я и сделал (не совсем так, но похоже).

Как теперь это в SQL запрос вставить?

SELECT DB.ID_DEBIT, DB.CHECKED, DB.COLOR, DB.OTDEL, DB.KLIENT,
      (SELECT OSTAT FROM getostatok (DB.ID_DEBIT)) OSTATOK,
      (SELECT DOLG FROM getdolg (DB.ID_DEBIT)) REALDOLG
           ^^^^^^^^^^^^^^ - вот сюда
FROM DEBIT DB, OTDEL OT, KLIENT KL
WHERE (OT.id_otdel = DB.otdel)
 AND (KL.id_klient = DB.klient)

У меня сейчас 2 процедуры, но делают они одно практически и то же. Я пытался свести в одну процедуру, и она при отладке выдает оба параматра. Но как вставить их в SQL запрос, чтобы одной коммандой их получить оттуда - увы, не смог.


 
stud ©   (2004-07-02 09:19) [30]

так как обычная процедура выбора вызывается
select * from my_proc(param....) [order by...]


 
Rutven ©   (2004-07-02 14:56) [31]


> Оно конечно хорошо, но только в случае, если мне кто-то
> платит каждый день по 1 000 р. (при сумме долга в 1 000
> 000), то у меня только на этого должника возникнет 1 000
> записей.

Так эта 1000 записей у тебя будет в любом случае :)


 
stud ©   (2004-07-02 15:10) [32]

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


 
Boroda Oleg   (2004-07-02 16:28) [33]

2 Rutven: "Жирность" базы где хранятся сами задолженности - 24 поля, имеются строки по 50 символов.
"Жирность" базы с оплатами - 4 поля из них одна строка10, дата, целое и decimal15,2
Что больше весит?

2stud: Спасибо! Как я сам не догадался...
А насчет процедуры - оно может и грамотней так будет. Действительно, возможностей на порядок больше. Хотя запросы как-то привычнее...


 
Petr V.Abramov   (2004-07-03 00:49) [34]

> Опять ты не так понял.

> Ведется учет ТОЛЬКО ДОЛЖНИКОВ.
 
 А если будет (неявная) возможность вести и учет переплат, вам надают по шее???
 Вы уперлись  в частную задачу, и нарвались на геморрой (причем именно от непонимания задачи общей), с которым 33 поста люди бьются. kaif © предложил Вам решение общей задачи и без геморроя.
 Совет: послушайте kaif ©

> Ведется учет ТОЛЬКО ДОЛЖНИКОВ.
> то разбираться с ним будет его менеджер.

У фирмы, на которую Вы работаете, есть два магазина: в центре Москвы и у кольцевой дороги вокруг Урюпинска. Соответствующий менеджер убеждает Вас, что цены в этих магазинах одинаковы, всегда были одинаковы и будут одинаковы вечно.
Вы должны понимать, что в этом случае вечность может закончиться через неделю, и если
цены в магазинах не будут выравниваться системой автоматически до окончания вечности;
цены в магазинах не смогут стать разными сразу после ее окончания,
то Вы спроектировали систему плохо.

(с) "Записки автоматизатора"

P.S. "Застраховаться от этого нуля" можно, испольуя
 table left join oplata



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2004.07.25;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.54 MB
Время: 0.034 c
14-1089278711
ПИТОН
2004-07-08 13:25
2004.07.25
Объявления


14-1088754425
AlexG
2004-07-02 11:47
2004.07.25
Установка Delphi без установки


8-1083819071
Kerget Ruslan
2004-05-06 08:51
2004.07.25
Проблемы при работе с TShockwaveFlash


4-1086877966
HMENU
2004-06-10 18:32
2004.07.25
Меню на API


3-1088827535
Gamar
2004-07-03 08:05
2004.07.25
Как пролистать DataSource.DataSet в качестве поля компонента?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский