Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Как "захлопнуть" лишние строки с NULL-полями, чтобы получить одну строку?  [new]
Kuanysh_T
Member

Откуда:
Сообщений: 6
Предыстория:
Я устроился программистом БД в одну компанию, в которой мне необходимо оптимизировать некий отчет и вот что имеется ввиду... предыдущий прогер написал select, который отбирает из БД MS SQL Server 2012 нужные поля с нужными значениями. Проблема в том, что этот селект выполняется более 2 часов, а начальнику хочется получать результат за 30-40 минут или еще быстрее.
Я проанализировал БД и... как бы сказать по мягче... я удивился! Почти все таблицы без первичного ключа! Внешних ключей вообще нигде нет! Есть одно текстовое поле (DocNum), которое есть почти во всех таблицах и именно это поле используется в sql-запросах как ключ, хотя ключом не является. Ну и ладно, базу я переделаю наверное... Но сейчас используя этот ужас нужно как-то оптимизировать запрос, потому что таблица Trans имеет более 100 миллиона строк записей (есть индексы по важным полям), а таблица Doc имеет полтора миллиона строк (тоже есть индексы). Поскольку для отчета нужно выводить не только нужные поля из таблицы, но также нужно выводить 12 вычислимых полей, предыдущий программист использовал таблицу Trans 12 раз связав с таблицей Doc. Это значит, что для каждой строки таблицы Doc просматривается почти вся таблица Trans, в промежуточном результате получаем количество строк = полтора миллиона умноженная на 12 и еще раз умноженная на 100 миллионов (я утрирую). Поэтому уходит много времени на выборку. Думаю, достаточно один раз использовать эти таблицы и полученный результат просто анализировать. Ниже я привел структуру этих таблиц, затем указал селект, из-за которой пишу данный пост - не могу найти оптимальный способ получения нужного результата и прошу знатоков дать подсказку.


СУТЬ ВОПРОСА:
Идея моя такова - для начала, связав нужные таблицы получить все нужные строки для дальнейшего рассмотрения. Затем проанализировать значения каждого поля и в зависимости от этих значений использовать их в вычисляемых полях для вывода конечного результата. Чтобы проанализировать значения полей я думаю удобнее использовать case... when... then... else... end, и здесь же использовать функцию Sum. Но для некоторых вычислимых полей условие вывода значения таково - "если поле такое-то равно такому-то значению, то выводить такой-то текст, иначе выводить другой текст". Вот тут я натолкнулся к проблеме...

ВОПРОС:
Как "захлопнуть" NULL-евые значения полей, чтобы из нескольких строк получить лишь одну? Дело в том, что результат запроса select ... case...when...then... получается таким, что в каждой строке только у одного вычисляемого поля есть значение, но нет значений в других вычисляемых полях. Примерно вот так:
ABCD
Группа131
Группа1АБВГД
Группа101.01.2014
Группа2783
Группа2ФЫВАИ
Группа229.05.2014


Здесь в полях A, C выводятся текстовые значения, в поле B выводится цифровое значение (вычисленное функцией SUM), в поле D выводится дата (сконвертированное из текстового значения).
Результат был бы правильным, если бы не NULL. Желаемый результат должен быть таким:
ABCD
Группа131АБВГД01.01.2014
Группа2783ФЫВАИ29.05.2014


Как добиться такого результата?


Если нужно, вот структура таблиц с моими комментариями:
Таблица DOC
DocNum varchar(20) not null unique
... (есть прочие поля, но они для данной задачи не столь важны)

Таблица Trans
DocNum varchar(20) not null
Acc varchar(27) not null
Amount decimal(10,2) not null
enddate char(8) not null


Вот мой селект, который привел меня к лишним NULL:
select
d.DocNum,
...
case when t.acc like '1234%' then sum(t.amount) over(partition by d.docnum, t.acc) end as calcfield1,
case when t.acc like '5432%' then 'НекийТекст' else 'ДругойТекст' end as calcfield2,
case when t.acc like '6534%' then max(t.enddate) over(partition by d.docnum, t.acc) end as calcfield3,
...
from Doc d
left outer join Trans t on d.DocNum = t.DocNum and ...

where ...



PS. Реальные названия таблиц и их полей изменены, но сохранена основная структура. В постановке вопроса исключены детали, которые на мой взгляд не важны для задачи.
2 апр 14, 13:48    [15821231]     Ответить | Цитировать Сообщить модератору
 Re: Как "захлопнуть" лишние строки с NULL-полями, чтобы получить одну строку?  [new]
Ennor Tiegael
Member

Откуда:
Сообщений: 3348
select A, max(B), max(C), max(D)
from (
...
) sq
group by A;
2 апр 14, 13:50    [15821251]     Ответить | Цитировать Сообщить модератору
 Re: Как "захлопнуть" лишние строки с NULL-полями, чтобы получить одну строку?  [new]
Kuanysh_T
Member

Откуда:
Сообщений: 6
Ennor Tiegael
select A, max(B), max(C), max(D)
from (
...
) sq
group by A;

Спасибо! Помогло! :)
4 апр 14, 08:18    [15831011]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить