Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > MS SQL Server > Нужна помощь в составлении запроса


Автор: insider92 23.11.2009, 21:20
Собственно, сабж.

В таблице есть поле примерно такого содержания:
Код
0,2537,15,0,0;1,3849,27,0,0;2,1113,0,0;
Знак ";" разделяет значение данного поля на элементы. Количество параметров в элементе может варьироваться.

Допустим, мне надо выбрать только те записи, у которых в этом поле есть элемент со вторым параметром равным 3849 и отсортировать их по значению третьего параметра этого элемента.

Возможно ли такое?

Автор: Akina 23.11.2009, 23:33
Пишите хранимую процедуру - такое вполне возможно. 
А вот в рамках запроса, когда количество групп не ограничено, такое сделать затруднительно.
PS. Может, лучше подумать об изменении структуры? Уж больно криво сделано...

Автор: insider92 24.11.2009, 03:57
Структура, конечно, кривая. Но софт уже разработан, большем им никто не занимается, исходников нет.
А с процедурой не подскажете?

Автор: ТоляМБА 24.11.2009, 07:13
insider92, почитай про составление процедур. Для твоей задачи изучи ещё LIKE, PATINDEX, SUBSTRING, LEN

Автор: DimW 24.11.2009, 10:28
Цитата(insider92 @  23.11.2009,  21:20 Найти цитируемый пост)
параметров в элементе может варьироваться


Цитата(insider92 @  23.11.2009,  21:20 Найти цитируемый пост)
со вторым параметром равным 3849 и отсортировать их по значению третьего параметра 

а если нет второго или третьего параметра, то ни чего не найдет или не отсотирует?
поясните.

Добавлено через 5 минут и 3 секунды
Цитата(insider92 @  23.11.2009,  21:20 Найти цитируемый пост)
Количество параметров в элементе может варьироваться.

а максимальное колличество параметров известно?

Автор: insider92 24.11.2009, 15:02
Цитата
а если нет второго или третьего параметра, то ни чего не найдет или не отсотирует?
поясните.
Три есть всегда
Цитата
а максимальное колличество параметров известно?
Количество зависит от значения второго параметра, для 3849 - их всегда 21.

Автор: DimW 24.11.2009, 15:48
Цитата(insider92 @  24.11.2009,  03:57 Найти цитируемый пост)
А с процедурой не подскажете? 

в вашем случае функция т.к. есть потребность использовать ее в звпросе, причем не одна, а несколько:
1) (is_exist_param) функция которая возвращает true или false(0 или 1) в зависимости от того есть нужное значение в этом поле или нет
параметры:
а) значение поля
б) значение которое ищите
в) № параметра

2) (get_element) функция которая возвращает № элемента по значению которое в него входит
параметры:
а) значение поля
б) значение которое ищите
в) № параметра

3) (get_value) функция которая возвращает параметр элемента по № элемента и № параметра в этом элементе
параметры:
а) исходное значение
б) № элемента
в) № параметра

для ваших требований запрос будет выглядеть примерно так:
Код

select * from table
 where is_exist_param(field, '3849', 2) = 1 -- true
order by get_value(field, get_element(field, '3849', 2), 3)


Автор: Akina 24.11.2009, 15:55
Функции 2 и 3 вполне можно собрать в одну... А если ещё заставить её при отсутствии искомого значения возвращать пустую строку или там -1, то и одной функции достаточно.

Автор: DimW 24.11.2009, 16:28
Цитата(Akina @  24.11.2009,  15:55 Найти цитируемый пост)
Функции 2 и 3 вполне можно собрать в одну...

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

Автор: insider92 24.11.2009, 19:16
DimW
Спасибо, с запросом разобрались. Но в таком случае самая сложная-то часть здесь - функции. С ними не поможете?

Автор: insider92 24.11.2009, 21:28
В общем, посидел, подумал и пришел к следующему:

Запрос
Код
SELECT c.cha_name, c.degree, dbo.chaos_points(content) as chaos_points 
FROM Resource AS r 
LEFT JOIN character AS c 
  ON (r.cha_id = c.cha_id) 
WHERE type_id = 1 AND dbo.chaos_points(content) != 0 
ORDER BY chaos_points DESC, c.degree DESC

Функция
Код
CREATE FUNCTION [dbo].[chaos_points]
(    
    @content char(3500)
)
RETURNS integer
AS
BEGIN
    DECLARE @offset integer
    DECLARE @length integer
    DECLARE @i integer
    DECLARE @j integer
    DECLARE @id char(4)
    DECLARE @element char(255)

    SET @offset = PATINDEX('%;%', @content)
    SET @content = SUBSTRING(@content, @offset + 1, 3500)

    SET @j = 1
    WHILE @offset != 0
    BEGIN
        SET @offset = PATINDEX('%;%', @content)
        IF @offset != 0
        BEGIN
            SET @content = SUBSTRING(@content, @offset + 1, 3500)
            SET @length = PATINDEX('%;%', @content)
            IF @length != 0
            BEGIN
                SET @element = SUBSTRING(@content, 0, @length)
                SET @id = SUBSTRING(@element, PATINDEX('%,%', @element) + 1, 255)
                SET @length = PATINDEX('%,%', @id)
                IF @length != 0
                BEGIN
                    SET @id = SUBSTRING(@id, 0, @length)
                END
                IF @id = '3849'
                BEGIN
                    --RETURN 1
                    SET @i = 0
                    WHILE @i < 6
                    BEGIN
                        SET @element = SUBSTRING(@element, PATINDEX('%,%', @element) + 1, 255)
                        SET @i = @i + 1
                    END
                    SET @length = PATINDEX('%,%', @element)
                    RETURN CONVERT(INT, SUBSTRING(@element, 0, @length))
                END
            END
            SET @j = @j + 1
        END
    END

    RETURN 0
END

Работать - работает, но может можно еще как-то упростить и/или оптимизировать?

UPD: Забыл, вот тестовый набор данных поля content:
Код
24@113#1;13;0,636,1,10000,10000,900,900,0,0,0,0;


M
Zloxa
Отредактировал форматирование
урезал тест данные, оригинальные вложил в файл

Автор: DimW 25.11.2009, 09:39
Цитата(insider92 @  24.11.2009,  21:28 Найти цитируемый пост)
В общем, посидел, подумал и пришел к следующему:

ну и как используя вашу функцию можно реализовать это:
Цитата(insider92 @  23.11.2009,  21:20 Найти цитируемый пост)
надо выбрать только те записи, у которых в этом поле есть элемент со вторым параметром равным 3849 и отсортировать их по значению третьего параметра этого элемента


Добавлено через 3 минуты и 22 секунды
ааа, понятно:
Цитата(insider92 @  24.11.2009,  21:28 Найти цитируемый пост)
IF @id = '3849'
  smile 
а если потребуется искать не по 3849 второго параметра, а по 1001 первого, еще одну функцию писать будете?

Автор: insider92 25.11.2009, 11:11
Цитата
а если потребуется искать не по 3849 второго параметра, а по 1001 первого, еще одну функцию писать будете?
А не потребуется smile Нужно найти элемент с 3849 во втором параметре и вернуть 7ой параметр этого же элемента. Если такого элемента нет - вернуть 0.
Меня еще беспокоит, что в запросе эта функция 2 раза указана, надеюсь она не будет дважды выполнятся для одного значения аргумента?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)