|
|
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
Всем доброго времени суток! :) Столкнулся с неразрешимой на сегодняшний момент для меня проблемой. Посоветуйте, пожалуйста, как можно ее решить. Общие сведения (предыстория): Необходимо разработать приложения для бухгалтерского учета, в котором должна быть возможность использования бухгалтерских проводок. Все это реализуется на базе MS SQL server 2008. Приложение при помощи ОДНОГО запроса считывает данные, которые касаются проводок. При помощи другого запроса записывают данные в базу. Проблема в том, что не получается создать нединамический запрос к базе для считывания данных. Т.е пока есть решение только с использованием динамического запроса, от которого, понятное дело, хочется уйти. Создал следующую модель базы данных (схема в аттаче): Схема и краткое описание структуры таблиц: Account - счета, таблица для хранения счетов бухгалтерского учета. LedgerAccount - субконто счетов. Здесь есть связь с таблицей Object для того, что бы понимать какой субконто соотносится с какими справочниками, например Субконто Договора" можно сопоставить значениям из справочника(объекта системы) "Договора". AccountLedgerAccount - Привязка субконто к счетам. Transaction - бухгалтерские проводки LedgerAccountValue - значения субконто счетов в определенной проводке. Object - перечень всех объектов в системе, под объектами понимаем все справочники, журналы, отчеты. Обьект собирается во вьюхе, условно считаем, что это одна таблица. Начало описания проблем: Все значения субконто счетов в проводках храняться в таблице LedgerAccountValue и для того, что бы выбрать нужное значение субконто по проводке пишется примерно следующий запрос: Код: sql 1. 2. -- цепляем счета по Дебету и по Кредиту Код: sql 1. 2. -- цепляем субконто счетов кредита и дебета Код: sql 1. 2. /* далее нужно выцепить ЗНАЧЕНИЕ субконто. Предполагается, что этим значением является одна из записей из справочников или журналов системы (ссылка на договор, контрагента и т.д.) и хранится это значение в поле ReferenceId проблема в том, что далее в запросе нужно подцепить нужную таблицу, а какую нужно цеплять таблицу(вьюху) зависит от того, какое именно субконто стоит в данном счете. Например, если у нас одно из субкон контрагенты тогда нужно цеплять таблицу Contragent: */ Код: sql 1. --если же субконто договора, тогда нужно цеплять таблицу Dogovor: Код: sql 1. Проблема в том, что в ReferenceId таблицы LedgerAccountValue может быть значение из многих таблиц (объектов). Понимаю, что это неправильно (подскажите, пожалуйста, как можно это сделать правильно?). Для вывода значений субконто пока вижу только путь с использованием динамического запроса: Для этого вытаскиваем имя таблицы(вьюхи) -- цепляем таблицу субконто Код: sql 1. и тогда в la1.ObjectId - будет ID объекта системы, по которому я уже смогу выйти на название таблицы Код: sql 1. ob.ViewName - имя таблицы (вьюхи) , котрую нужно цеплять и дальше написать финальный динамический запрос для выемки значение субконто из таблицы. Хотелось бы реализовать все это таким образом, что бы при добавлении новых субконто в счета, а так же добавлении новых счетов с субконтами, не было необходимости переписывать хранимые процедуры и менять exe-шник, и не использовать динамические запросы. (Не слишком ли это многого я хочу ?) Чувствую, что чем дальше иду, тем больше делаю ошибок в проектировании базы. Подскажите, пожалуйста, какие есть еще альтернативные варианты для решения моей задачи. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.07.2015, 22:39 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
unimilk проблема в том, что далее в запросе нужно подцепить нужную таблицусквозная нумерация id у разных объектов или guid. И джойнь их всех, только в одной будут непустые значения ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.07.2015, 23:42 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
SERG1257, приветствую! :) Спасибо за ответ. Боюсь, сейчас вариант с сквозными ID достаточно проблематично реализовать, т.к. сейчас в системе уже существует большое количество объектов(таблиц) с большим количеством внешних связей, и изменять их Id на сквозной это очень большие трудозатраты. Нет ли еще какого-либо пути? может, можно как-то изменить структуру базы данных, относящуюся к проводкам? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.07.2015, 09:51 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
SERG1257, + в случае добавления нового субконто каждый раз нужно будет править запрос, который начитывает данные, а это тоже крайне нежелательно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.07.2015, 09:56 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
это значение в поле ReferenceId проблема в том, что далее в запросе нужно подцепить нужную таблицу, а какую нужно цеплять таблицу(вьюху) зависит от того, какое именно субконто стоит в данном счете. Это не проблема. делаете ф-цию: параметры ReferenceId, DocTypeID... и в ней извлекаете сколь угодно сложным образом нужные значения. При появлении новых таблиц достаточно поправить код этой ф-ции. Код приложения останется неизменным. зы: ф-ции ацки рулят. Код сокращается в разы. Читабельность - во много раз. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.07.2015, 10:19 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
unimilkНапример, если у нас одно из субкон контрагенты тогда нужно цеплять таблицу Contragent: */ Код: sql 1. --если же субконто договора, тогда нужно цеплять таблицу Dogovor: [src] join Dogovor dog1 on dog1.DogovorId = laD.ReferenceId Как вы определяете условие "ЕСЛИ". Где у вас хранится признак что именно для конкретной записи "субконто"? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.07.2015, 10:53 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
Сквозные ID в принципе необязательны (хотя с ними система будет аккуратнее) - достаточно вместо Код: sql 1. писать Код: sql 1. И т.п. unimilkSERG1257, + в случае добавления нового субконто каждый раз нужно будет править запрос, который начитывает данные, а это тоже крайне нежелательно. Нет - только при добавлении нового типа субконто. Например, решаем "теперь у нас в системе могут быть субконто Контрагенты" - тогда да, надо будет переписывать запрос, чтобы добавить приведенную мной строчку. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.07.2015, 11:20 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
unimilk, Если нельзя сделать сквозную нумерацию, то Если типов субконто не очень много(не более 10ти), то можно обойтись набором left join'ов Помним, что у оптимизатора сносит крышу на более чем 10ти таблицах. Так что наши джойны можно смело помечать хинтом loop Так же, если вы уверены, что расположили таблицы в запросе в правильном порядке, следует использовать хинты force order и можно ещё maxdop 1 Как-то так: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. Примерно то же самое получится, если как предлагали создать функцию. Минусы очевидны - большие затраты на соединения в случае большого количества типов субконто; изменение кода при добавлении нового типа субконто Возможно есть смысл создать индексированную вьюху(type ASC), которая объединяет все таблицы.(uinon all) А вот если таблиц очень много. Тогда действительно стоит выбрать динамический запрос. Не надо его сильно пугаться. Это даст выигрыш в производительности, ну и со временем менять ничего не придётся. и помним, что это небезопасно, например если ob.ViewNam выдаст несуществующую таблицу и.т.п А если всё таки есть возможность перенести данные. То можно создать табличку для субконто, куда внести все существующие поля из всех таблиц с составным индексом (тип, refId) - после переноса данных переписать код и грохнуть таблички. Но надо быть готовым к тому, что статистика по таблице будет никакая и оптимизатор может начать творить чушь. Вертикальное хранение то ещё зло, поэтому рекомендовать этот вариант не буду. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.07.2015, 12:25 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
unimilkSERG1257, приветствую! :) Спасибо за ответ. Боюсь, сейчас вариант с сквозными ID достаточно проблематично реализовать, т.к. сейчас в системе уже существует большое количество объектов(таблиц) с большим количеством внешних связей, и изменять их Id на сквозной это очень большие трудозатраты. Нет ли еще какого-либо пути? может, можно как-то изменить структуру базы данных, относящуюся к проводкам? Ты совершил кардинальную ошибку при проектировании твоей БД (нарушение доменной целостности), теперь нужны кардинальные усилия для её преодоления, всё логично. Можно и без сквозного ID. У тебя есть вид этого субконто. Делай LEFT JOIN-ы на все возможные таблицы с этим субконто, и потом CASE-ом выбирай по виду субконто нужный объект из, скажем, 10. Будет много JOIN-ов, и будет большой длинный CASE, но это всё не страшно для запроса. Запрос будет статическим. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.07.2015, 17:14 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
unimilkSERG1257, + в случае добавления нового субконто каждый раз нужно будет править запрос, который начитывает данные, а это тоже крайне нежелательно. Ничего, поправишь... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.07.2015, 17:15 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
LSVэто значение в поле ReferenceId проблема в том, что далее в запросе нужно подцепить нужную таблицу, а какую нужно цеплять таблицу(вьюху) зависит от того, какое именно субконто стоит в данном счете. Это не проблема. делаете ф-цию: параметры ReferenceId, DocTypeID... и в ней извлекаете сколь угодно сложным образом нужные значения. При появлении новых таблиц достаточно поправить код этой ф-ции. Код приложения останется неизменным. зы: ф-ции ацки рулят. Код сокращается в разы. Читабельность - во много раз. Функции в запросах ненужны и вредны. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.07.2015, 17:15 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
Вот всё правильно написал, а все же... так зашёлПомним, что у оптимизатора сносит крышу на более чем 10ти таблицах. Так что наши джойны можно смело помечать хинтом loop С какой стати? Т.е. 10 таблиц -- всё будет ок, а вот если вдруг 11-ую добавим -- сразу слёт крыши ? У нас тут даже СУБД в обсуждении не зафиксирована, а ты такие вещи говоришь... Тем более, что все эти 10-20 JOIN-ов будут LEFT OUTER, и оптимизатору не нужно будет думать, какая таблица пойдёт вперёд -- однозначно не эти, потому что они не добавляют селективность запросу. Плюс должны же быть индексы, так что фактически наоборот запрос обречён на хорошее функционирование при благоприятности остальных условий (что самих транзакций будет не миллион, а 10-100) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.07.2015, 17:22 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
MasterZivФункции в запросах ненужны и вредны.Мой начальник когда-то тоже так считал. Поэтому у него в коде отчетов каждая управленческая цифра (а их много) извлекалась "заново" т.е. запросом. Сотни точек копипаста. Отчеты были огромными sql-мегапростынями. Переделка логики документа (иногда надо) могла потребовать переделки десятка таких простыней. Это если про все вспомнишь, а это крайне непросто. До хрипоты спорили. В итоге ему простыни надоели и он согласился юзать ф-ции. В результате код некот. отчетов сократился в 10 раз, а правильность кода возросла, т.к ф-ция вылизывается и считает идеально точно везде. Отчет лаконичен (зачастую один простой SELECT) и очень просто понимается и переделывается, если нужно. Ф-ции тормозят ? Да. Но далеко не всегда. Главное ими аккуратно пользоваться. Там где торможение было критичным - переделывали на обычные запросы. Но это 5% случаев. Используя ф-ции никто не запрещает пользоваться обычными запросами. зы: по сабжу ф-ции проблему решат. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 09:40 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
LSV, LSV, Как вы думаете, а возможно ли какое-то решение на уровне СУБД, что бы при добавлении новых таблиц завязанных с субконто, не приходилось бы править код хранимых процедур и функций? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 10:55 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
unimilk а возможно ли какое-то решение на уровне СУБД, что бы при добавлении новых таблиц завязанных с субконто, не приходилось бы править код хранимых процедур и функций ? Можно править код View. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 11:01 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
Mikle83Как вы определяете условие "ЕСЛИ". Где у вас хранится признак что именно для конкретной записи "субконто"? Mikle83, нужную таблицу, связанную с субконто, могу получить через такой запрос: Код: sql 1. 2. 3. в ob.ViewName - имя искомой таблицы которую нужно цеплять. Проблема в том , что заранее неизвестно какое количество субконто может быть у счета, их количество может изменяться от 1 до .. N. Соответственно, неизвестно сколько и какие таблицы нужно join -ить в запросе получения данных. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 11:03 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
Кот МатроскинНет - только при добавлении нового типа субконто. Например, решаем "теперь у нас в системе могут быть субконто Контрагенты" - тогда да, надо будет переписывать запрос, чтобы добавить приведенную мной строчку. В том-то все и дело, что хочется уйти от постоянной правки запросов, при добавлении новых субконто (типов субконто). Возможно ли это ? Использовать функции (но в них получается тоже необходимо будет использовать динамические запросы ?) Либо как-то изменить структуру данных ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 11:07 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
так зашёлЕсли типов субконто не очень много(не более 10ти), то можно обойтись набором left join'ов Точное количество субконто не известно, вряд ли оно, конечно, будет больше 10, но полагаться на это мне кажется тоже не совсем правильно. Ищется решение возможно даже , связанное с изменением структуры данных таблиц, которое позволит уйти от постоянных правок, хранимых процедур /функций при добавлении этих самых субконто. авторА вот если таблиц очень много. Тогда действительно стоит выбрать динамический запрос. Не надо его сильно пугаться. Таблиц уже достаточно много в системе и в них уже есть данные. Опасение внушает не сам факт использования динамических запросов, а то, что была допущена ошибка при проектировании базы (теперь я уже в этом уверен), и что эта ошибка в дальнейшем наложит свои ограничения на работу с данными. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 11:19 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
MasterZivТы совершил кардинальную ошибку при проектировании твоей БД (нарушение доменной целостности), теперь нужны кардинальные усилия для её преодоления, всё логично. Да, теперь я это понимаю. Как ее можно исправить? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 11:20 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
Кот МатроскинМожно править код View извиняюсь за неточную формулировку, да, я имел виду что бы не приходилось править sql -ный код ни во view, ни в функциях, ни в хранимых процедурах, ни в триггерах ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 11:25 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
unimilkв ob.ViewName - имя искомой таблицы которую нужно цеплять. Проблема в том , что заранее неизвестно какое количество субконто может быть у счета, их количество может изменяться от 1 до .. N. Соответственно, неизвестно сколько и какие таблицы нужно join -ить в запросе получения данных. Количество субконто у счета неважно, прибавление еще одного субконто из заранее определенного списка на счет не влечет правки кода ("Вот теперь на счете 322223 у нас будет еще и субконто контрагенты"). Правку влечет добавление нового типа субконто в систему ("теперь у нас в качестве субконто могут быть еще и контрагенты").За ~7 лет сопровождения учетных систем, в которых было понятие "субконто", я видел такой кейс 2 раза - когда предопределенного списка типов субконто не хватило и его пришлось расширять. unimilkчто хочется уйти от постоянной правки запросов, при добавлении новых субконто (типов субконто). Возможно ли это ? Использовать функции (но в них получается тоже необходимо будет использовать динамические запросы ?) Либо как-то изменить структуру данных ? В принципе - возможно (например, при создании/изменении любого обьекта в системе заранее писать его "копию" в таблицу "значение субконто". ). Но это варианты с большими накладными расходами, и имхо правки кода или динамический sql выглядят предпочтительнее. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 12:09 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
unimilkизвиняюсь за неточную формулировку, да, я имел виду что бы не приходилось править sql -ный код ни во view, ни в функциях, ни в хранимых процедурах, ни в триггерахМожно. Поручить это делать другому специалисту. :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 12:26 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
Почему нельзя в значения субконто писать не только ID справочников/документов и т.п., но и их "наименование"? Чтобы не извлекать это джоинами. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 14:12 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
unimilkMikle83Как вы определяете условие "ЕСЛИ". Где у вас хранится признак что именно для конкретной записи "субконто"? Mikle83, нужную таблицу, связанную с субконто, могу получить через такой запрос: Код: sql 1. 2. 3. в ob.ViewName - имя искомой таблицы которую нужно цеплять. Проблема в том , что заранее неизвестно какое количество субконто может быть у счета, их количество может изменяться от 1 до .. N. Соответственно, неизвестно сколько и какие таблицы нужно join -ить в запросе получения данных. Следующий шаг - что конкретно по каждому субконто вытаскивается? Список полей, выбираемых в итоговый датасет, по всем субконто - единый? Или можно его привести к единому виду? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 14:33 |
|
||
|
Проектирование базы для последующей работы с ней без использования динамических запросов
|
|||
|---|---|---|---|
|
#18+
Mikle83Следующий шаг - что конкретно по каждому субконто вытаскивается? Список полей, выбираемых в итоговый датасет, по всем субконто - единый? Или можно его привести к единому виду? По субконто вытаскивается его значение так: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. соответственно, список полей в итоговом датасете может быть разный , в зависимости от того с каким субконто имеем дело (con.ContragentName или dog.Dogovor, или g.good и т.д.) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2015, 14:54 |
|
||
|
|

start [/forum/topic.php?fid=32&msg=39002138&tid=1540518]: |
0ms |
get settings: |
9ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
171ms |
get topic data: |
10ms |
get forum data: |
3ms |
get page messages: |
56ms |
get tp. blocked users: |
1ms |
| others: | 240ms |
| total: | 512ms |

| 0 / 0 |

Извините, этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
... ля, ля, ля ...