Выгрузка данных из БД по сложному условию

saveliev_a

Всем привет.
Есть такая вот задача. Нужно вытащить данные из БД по следующему условию
(field1 in set1) and (field2 in set2)

set1 и set2 могут быть очень большими множествами, поэтому, если решать в лоб, то SQL-запрос получается слишком длинным и запрос вылетает с ошибкой
com.jnetdirect.jsql.u: The server encountered a stack overflow during compile time.

Первое решение, которое приходит в голову, следующее: разбить отдельно set1 и set2 на n1 и n2 подмножеств, выгрузить отдельно данные, а потом в памяти построить пересечение.
Может быть, будут идеи получше?
СУБД MSSQL.
UPD. Прямого доступа к БД нет, работа идет через функции API, в которых используется псевдо-SQL.

vovaV09

Для каждого множества создать временную таблицу с одним столбцом и данными из его элементов. В запросе вместо set1/set2 использовать вложенный select из врем. таблицы.

saveliev_a

Спасибо за ответ, обновил первый пост. Прямого доступа к БД нет, работа идет через функции API, в которых используется псевдо-SQL.

vall

а потом в памяти построить пересечение.
а не лучше объединение строить?
вытащить for x in set1 do (field1 == x) and (field2 in set2) или вообще for x in set1 for y in set2 ?

saveliev_a

ИМХО, нет, так как будет слишком много обращений к БД.

klyv

Первое решение, которое приходит в голову, следующее: разбить отдельно set1 и set2 на n1 и n2 подмножеств, выгрузить отдельно данные, а потом в памяти построить пересечение.
а не пробовали сделать типа (x in set1_1 or x in set1_2 or ...) and (x in set2_1 or ...)?
подмножества раскидать по разным кускам, чтоб парсер не захлёбывался, а в итоге всё равно один запрос.

mbolik1

Варианты решения:
1. Пересмотреть архитектуру системы. Раз приходится передавать большие выборки то скорее всего в какой-то момент функции БД переложили на приложение.
2. Сделать двойной цикл но не по одной записи а по подмножеству (определить на скольких записях ломается и бить множества set1 и set2 на подмножества заданного размера)
3. Точно не уверен но может прокатить:
select * from table where 
field1 in
(select item1_1
union all
select item1_2
...здесь все элементы из set1
)
and
field2 in
(select item2_1
union all
select item2_2
...здесь все элементы из set2
)

rosali

разбить множество set1 на два, set2 тоже, забрать все возможных 4 варианта по очереди. при необходимости увеличить "два".
мне кажется лучше объединять чем пересекать. пересекать самому может не получиться, пересечение может быть маленьким, а множества до пересечения могут оказаться огромными.

Maurog

com.jnetdirect.jsql.u: The server encountered a stack overflow during compile time.
странная ошибка для режима выполнения
ты уверен, что с запросом все в порядке? (синтаксические ошибки или алгоритмические)

saveliev_a

Всем спасибо за ответы!
, нет не пробовали, но похоже, что захлебывается парсер скуля, поэтому описанный способ не поможет. Ниже я приведу ссылку на аналогичную проблему, там возникает такая же ошибка, при другом запросе.
, архитектуру пересмотреть нельзя, работа с БД идет через функции API. Большие выборки приходится делать, потому что необходимо получить много данных. Про двойной цикл уже писали. Мне кажется, что работать будет дольше, потому что будет слишком много запросов к БД.
, если множества разбить на m и n частей, то для объединения надо будет делать m x n запросов, а для пересечения — m + n.
, в гугле по первой ссылке находится точно такая же ошибка, возникающая при выполнении длинного запроса, поэтому, думаю, проблема точно в длине запроса.

Maurog

я просто неправильно понял фразу
set1 и set2 могут быть очень большими множествами, поэтому, если решать в лоб, то SQL-запрос получается слишком длинным и запрос вылетает с ошибкой
думал, что set1 описывает большой рекордсет, а оказалось, что set1 - это подзапрос из большого числа буковок :shocked:

klyv

, нет не пробовали, но похоже, что захлебывается парсер скуля, поэтому описанный способ не поможет. Ниже я приведу ссылку на аналогичную проблему, там возникает такая же ошибка, при другом запросе.
именно потому что захлёбывается парсер скуля (или кто-нибудь ещё описанный способ сработает. Имо, выражения типа (<element>{,<element>}) разбираются рекурсией, которая и заходит слишком глубоко. Если было N элементов, то выражение x in (set1) закопает парсер на глубину N+1, а выражение x in (set1_1) or x in (set1_2 где оба множества - половинки исходного, даст глубину N/2 + 2 - явно меньше исходного.

saveliev_a

Спасибо за объяснение, теперь понял, почему может помочь разбиение на подмножества при одном запросе. Ну что же, проведу небольшой эксперимент, когда появится время, и соощу о результате.

saveliev_a

Кстати, ведь по первой ссылке там простое условие
SELECT * FROM Drug
WHERE ([DrugKey] = 1 AND Year = 1995)
OR ([DrugKey] = 1 AND Year = 1996)
OR ([DrugKey] = 1 AND Year = 1997)
OR ([DrugKey] = 1 AND Year = 1998)
OR ([DrugKey] = 1 AND Year = 1999)
OR ([DrugKey] = 1 AND Year = 2000)
OR ([DrugKey] = 1 AND Year = 2001)
OR ([DrugKey] = 1 AND Year = 2002)
OR ([DrugKey] = 10017 AND Year = 1995)
OR ([DrugKey] = 10018 AND Year = 1997)
...

На нем парсер не должен захлебнуться в рекурсии.
Оставить комментарий
Имя или ник:
Комментарий: