Мне нужен «нечеткий» запрос, чтобы получить продукты выше и ниже заданного измерения - PullRequest
0 голосов
/ 15 ноября 2009

Вот моя проблема: пользователь ищет товары по размеру. В результате должны быть показаны все продукты желаемого размера (если они есть), а также продукты, которые постепенно увеличиваются и уменьшаются, пока не будет отображено, по меньшей мере, 50 продуктов меньшего размера и 50 продуктов большого размера в дополнение к продуктам правильного размера.

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

Пример. Представьте себе, что существует 25 различных размеров с 20 продуктами каждого размера. Пользователь запрашивает размер 12. Нам нужно пойти на три размера вниз и на три размера, чтобы получить как минимум 50 в каждом направлении. Запрос должен возвращать все продукты размера 12, а также продукты размером 9, 10, 11, 13, 14 и 15. Запрос вернул бы всего 140 товаров (20 размер-12 плюс 60 выше и 60 ниже.) К сожалению, размеры не являются хорошими целыми числами, как в моем примере. Это произвольные десятичные значения.

Запрос Linq to SQL для этого был бы очень полезен, но приветствуется и простой SQL или C #. (Моя среда - C #, SQL Server 2005) Спасибо

Ответы [ 2 ]

1 голос
/ 15 ноября 2009

Вот пример оператора SQL (для mysql), который должен делать то, что вы хотите. Но в зависимости от того, что еще делает ваша процедура, вы можете быстрее выполнить некоторую обработку в коде C #:

SELECT 
    *
FROM
    products
WHERE 
    size = [[desired_size]] OR 
    size IN (
         SELECT DISTINCT 
             size 
         FROM 
             products
         WHERE
             size > [[desired_size]]
         ORDER BY 
             size
         LIMIT 50
    )
    OR
    size IN (
         SELECT DISTINCT 
             size 
         FROM 
             products
         WHERE
             size < [[desired_size]]
         ORDER BY 
             size DESC
         LIMIT 50
    )

Я объясню, начав с начала (и использую ваш пример для значений) ...

Сначала нам нужно сгенерировать список следующих 50 больших (или меньших) предметов. Следующий запрос должен сделать это:

SELECT * FROM products WHERE size > 12 ORDER BY size LIMIT 50

Итак, прямо сейчас мы берем все из таблицы продуктов, которая больше, чем желаемый размер. Мы заказываем его по размеру, а затем ограничиваем его только первыми 50. Таким образом, в этом случае он должен вернуть (в этом порядке) 20 товаров размером 13, 20 товаров размера 14 и 10 товаров размера 15. Вы можете попробовать это в редакторе Visual Studio SQL и посмотреть, какие строки он возвращает.

Но для наших целей нам нужен только список размеров, поэтому мы можем еще больше ограничить запрос, изменив предложение SELECT на:

SELECT DISTINCT size...

Итак, теперь мы смотрим только на столбец «size» и используем ключевое слово DISTINCT, чтобы избежать повторяющихся значений

так что теперь запрос возвращает только список: (13, 14, 15)

Мы делаем аналогичный запрос, чтобы получить следующие 50 более мелких предметов:

SELECT DISTINCT size FROM products WHERE size < 12 ORDER BY size DESC LIMIT 50

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

в этом случае этот запрос вернет список (11, 10, 9)

Если мы соберем все это во внешнем запросе, используя эти два списка, мы получим:

SELECT
  *
FROM
  products
WHERE
  size = 12 OR
  size IN (13, 14, 15) OR
  size IN (11, 10, 9)

Итак, мы вытаскиваем все продукты размером от 9 до 15

.

Надеюсь, это имеет смысл: -)

0 голосов
/ 12 августа 2010

Немного поздно, так что вы, возможно, уже решили это ...

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

Вы, очевидно, можете легко сделать:

Get me everything of size X
Get me 50 of size >X
Get me 50 of size <X

Однако, поскольку размер является линейным, а не дискретным, и мы не можем предсказать, сколько существует каждого размера, мы не можем сгруппировать / подсчитать размеры, что затрудняет определение того, какой размер будет снаружи +/- 50 записей - следовательно, нам нужно прочитать эти значения, прежде чем мы сможем получить окончательный набор записей. может быть в состоянии свернуть это в один с подзапросами, но меня не удивит, если LINQ будет выполнен в нескольких запросах ,,,,

Что-то вроде:

Dim ExactSize = 1.1

Dim MaxSizeRecord = MyRepository.Get(function(x) x.Size > ExactSize).OrderBy(function(y) y.Size).Skip(50).First
Dim MinSizeRecord = MyRepository.Get(function(x) x.Size < ExactSize).OrderByDescending(function(y) y.Size).Skip(50).First

Dim FinalResults = MyRepository.Get(function(x) x.Size >= MinSizeRecord.Size and X.Size <= MaxSizeRecord.Size)

Я не поигрался с внутренностями LINQ достаточно, чтобы знать, если ...

Dim MaxSize = MyRepository.Get(function(x) x.Size > ExactSize).OrderBy(function(y) y.Size).Skip(50).First.Size
Dim MinSize = MyRepository.Get(function(x) x.Size < ExactSize).OrderByDescending(function(y) y.Size).Skip(50).First.Size

Dim FinalResults = MyRepository.Get(function(x) x.Size >= MinSize and X.Size <= MaxSize)

(то есть получение точного размера границ, а не записи, размер которой оказывается на границе)

... генерирует тот же SQL - он, безусловно, более читабелен, но LINQ может потенциально выполнить запросы Min / Max немедленно, так как значение сохраняется в Double - возможно, что путем определения типа MinSize / MaxSize неявно он будет обрабатывать его как IQueryable (типа double).

Использование записей вместо двойных, хотя и немного менее читабельное, должно гарантировать, что он рассматривается как запрос, а не значение.

...