За последние 24 часа нас посетили 17774 программиста и 1650 роботов. Сейчас ищут 819 программистов ...

использование пользовательских переменных в запросе

Тема в разделе "MSSQL", создана пользователем deadka, 2 май 2011.

  1. deadka

    deadka Активный пользователь

    С нами с:
    2 май 2011
    Сообщения:
    3
    Симпатии:
    0
    Здравствуйте!

    В mysql есть возможность использовать пользовательские переменные в запросах, что позволяет оптимизировать определенные вычисления.

    Простой пример - есть таблица pogoda с двумя полями - t и d, t - это временная метка, а d - это результат измерения погоды. Требуется найти максимальный перепад.

    Срабатывает следующая конструкция:

    Код (Text):
    1. SET @data=NULL, @next_data=NULL, @max_value=0;
    2.  
    3. SELECT @next_data:=`d` `nextdata`,IF (@next_data - @data>@max_value, @max_value:=@next_data-@data, @max_value),  @data:=d FROM `pogoda`;
    4.  
    5. SELECT @max_value;

    Соль в том, что на n-й строке мы знаем значение d на (n-1)-й строке, и можем вычислить разницу.

    Собственно, вопрос в чем: можно ли такую же конструкцию выполнить на mssql? Без хранимых процедур, именно вот так, по ходу выполнения запроса. Если реально, то приведите пожалуйста текст запроса.

    Заранее большое спасибо!
     
  2. uri

    uri Активный пользователь

    С нами с:
    3 сен 2009
    Сообщения:
    43
    Симпатии:
    1
    Коротко говоря, можно.

    Подробнее, начну вот с чего.
    Во-первых, в вашем коде 2 запроса и 1 инструкция. Т.е. никакой речи о "ходе выполнения запроса" не идет. А идет выполнение пакета sql-команд. Т.е. на сервер Вам надо будет передавать хороший такой кусок кода.
    Во-вторых, небезопасно отправлять куски sql-кода (например, из-за явного указания метаданных (таблиц, представлений) и их структуры (набор полей), ну и про sql-инъекции не забываем).
    В-третьих, и по-моему самое главное, SQL-сервер предназначен для работы с множествами (записей) и навороченная логика не должна мешать работе SQL-сервера. Т.е. для производительности полезно разделять чистые SQL-запросы и логику (различные проверки, промежуточные вычисления, последовательные переборы и т.п.).

    Лучшее решение - использование хранимых процедур:
    1) сокрытие реализации
    2) безопасность (проверка типов и допустимых значений передаваемых параметров в коде процедуры)
    3) реализация логики практически любой сложности, например, проверка по правам доступа
    4) размер PHP-кода вызова процедуры и самого запроса минимален, трафик минимален
    5) проще отлаживать процедуру и менять ее код, чем запросы в PHP-коде

    Минусы:
    1) возвращает чаще всего (если не предусмотрено в коде процедуры) фиксированный набор полей, т.е. даже если нам надо 3 из 5 полей, мы получим все 5.
    2) ограничено использование вложенных временных таблиц, можно обойти использованием табличных переменных

    Можно, конечно, реализовать решение Вашей задачи путем формирования запроса. Скорее всего, это будет вложенный запрос.
    Например, так (если я правильно понял задачу)


    Код (Text):
    1. if object_id('tempdb..#pogoda') is not null drop table #pogoda
    2.  
    3.  
    4. create table #pogoda(
    5.             TID int identity(1,1)
    6.             , DT    datetime    // дата
    7.             , DVal  int    // значение
    8.             )
    9.  
    10. // ..
    11. // добавляем данные
    12. // ..
    13.  
    14.  
    15. select
    16.     max(ww.DiffVal)
    17. from (
    18. select p1.DVal as P1_Val, p2.DVal as P2_Val, abs(p1.DVal - p2.DVal) as DiffVal
    19. from #pogoda p1
    20. inner join #pogoda p2 on (dateadd(dd, 1, p1.DT) = p2.DT)
    21. ) as ww
    Здесь предполагается, что дата - уникальна и имеет дискретность 1 день.
    Если это не так, изменения в коде минимальны
    1) отсортировать данные перед вставкой во временную табличку, тогда поле TID типа IDENTITY будет последовательно нумеровать записи исходных данных
    2) смотреть соседние значения TID

    Если нужно готовое решение - уточните.