Есть некая таблица.
Пусть отобранные из нее по условию записи выглядят в result set вот так:
x x - - x - -
- y y - - - y
z z - z z - -
прочерк — это null
x, y, z — это поля разных записей
Можно ли составить изначально такой SQL запрос, чтобы null значения заменялись non-null значениями из следующей записи?
В итоге нужно получить всего одну запись, которая была бы максимально заполнена non-null значениями.
То есть применительно к примеру — результат должен быть такой:
x x y z x - y
Количество записей здесь произвольное:
— если ничего не отобрано — пустой результат и возвращать
— если отобрана 1 запись — ее и возвращать
— если найдено больше одной — то "мержить" поля записей между собой, приоритет имеют поля верхних записей (выборка по дате будет)
PS: предполагается, что таблица будет разреженная, то есть основная ее часть будет заполнена null-ами.
PPS: На момент генерации запроса структура таблицы будет известна наверняка (пусть будет Table1 с колонками Column1,..,ColumnN)
Здравствуйте, ika, Вы писали:
ika>Можно ли составить изначально такой SQL запрос, чтобы null значения заменялись non-null значениями из следующей записи?
В sql нет понятия "следующая запись". Я бы не мучился, а сделал бы
SELECT column1 FROM table WHERE column1 IS NOT NULL ORDER BY чего_нибудь LIMIT 1;
SELECT column2 FROM table WHERE column2 IS NOT NULL ORDER BY чего_нибудь LIMIT 1;
...
SELECT columnN FROM table WHERE columnN IS NOT NULL ORDER BY чего_нибудь LIMIT 1;
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
.>SELECT column1 FROM table WHERE column1 IS NOT NULL ORDER BY чего_нибудь LIMIT 1;
Выбирать все поля по очереди отдельными селектами будет не очень эффективно мне кажется.. дело в том, что каждая колонка — это одно поле документа. Загружать документ через выборку каждого поля — не очень.. Я думал вдруг какая-нить агрегатная функция хитрая существует.. ну раз нет — все равно спасибо.
Как альтертанивный способ я думал про вычитывание набора записей в 1 селект, а потом просто проитерироваться по резалтсету внешним кодом на яве и уже там выбрать верхнию ненуловую ячейку по каждому полю.
Здравствуйте, ika, Вы писали:
.>>SELECT column1 FROM table WHERE column1 IS NOT NULL ORDER BY чего_нибудь LIMIT 1; ika>Выбирать все поля по очереди отдельными селектами будет не очень эффективно мне кажется.. дело в том, что каждая колонка — это одно поле документа. Загружать документ через выборку каждого поля — не очень..
"SELECT column1" не загружает весь документ, а только значение одной колонки.
ika>Я думал вдруг какая-нить агрегатная функция хитрая существует.. ну раз нет — все равно спасибо. ika>Как альтертанивный способ я думал про вычитывание набора записей в 1 селект, а потом просто проитерироваться по резалтсету внешним кодом на яве и уже там выбрать верхнию ненуловую ячейку по каждому полю.
Если у тебя 1000000 документов и 10 полей, то явно будет хуже, т.к. сделать 10 запросов, которые возвратят 1 запись гораздо быстрее, чем 1 запрос, возвращающий миллион записей.
Короче, зависит от того, какие данные у тебя.
Кстати, если у документа больше 10 свойств, да ещё и большинство не установлено, то надо переделать структуру данных: табличка документов Document(id, name...), табличка свойств Property(id, name...), табличка значений свойств документа DocumentProperties(documentId. propertyId, propertyValue).
На такой структуре данных легко делается запрос, который ты хочешь.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ika, Вы писали:
ika>Можно ли составить изначально такой SQL запрос, чтобы null значения заменялись non-null значениями из следующей записи? ika>В итоге нужно получить всего одну запись, которая была бы максимально заполнена non-null значениями.
Идея простая. Вот для MS SQL —
create table #t
(
dt integer not null primary key,
c1 integer,
c2 integer,
c3 integer,
c4 integer
);
insert into #t values (1, null, null, null, null);
insert into #t values (2, 1, null, null, null);
insert into #t values (3, null, 2, null, null);
insert into #t values (4, 11, 22, 3, null);
select
c1 = (select top 1 c1 from #t where c1 is not null order by dt),
c2 = (select top 1 c2 from #t where c2 is not null order by dt),
c3 = (select top 1 c3 from #t where c3 is not null order by dt),
c4 = (select top 1 c4 from #t where c4 is not null order by dt)
drop table #t;
Для других серверов будет чуть другой ситаксис, но та же идея.
Подойдет?
Здравствуйте, ika, Вы писали:
ika>Есть некая таблица. ika>Пусть отобранные из нее по условию записи выглядят в result set вот так:
ika>
ika>x x - - x - -
ika>- y y - - - y
ika>z z - z z - -
ika>
ika>прочерк — это null ika>x, y, z — это поля разных записей
ika>Можно ли составить изначально такой SQL запрос, чтобы null значения заменялись non-null значениями из следующей записи?
Запрос-то любой можно составить, пусть даже самый извёрнутый. Только хочется отметить один момент: Таблица в РСУБД — это совсем не то же самое, что таблица в Excel, с ними по-другому надо работать.
Если вам надо такое сделать, то у вас что-то очень неправильно, либо в голове, либо в ТЗ, которое вам дали.
В обоих случаях нужно хорошенько подумать, как можно сделать по-другому.
Здравствуйте, Docker, Вы писали:
D>В SQL Server 2005 думаю можно попробовать через CLR User-Defined Aggregates
не советую. В User-Defined Aggregates нет никакого способа гарантировать порядок скармливания аргументов в агрегат:
IsInvariantToOrder | Reserved for future use. This property is not currently used by the query processor: order is currently not guaranteed.