Глобальные переменные в SQL - PullRequest
4 голосов
/ 27 января 2010

Допустим, я хотел создать сценарий sql и сделать что-то вроде этого:

DECLARE @SomeVariable int
SET @SomeVariable = 'VALUE'
  FROM someTable
--do stuff with @SomeVariable
GO

CREATE PROCEDURE myProcedure
(
  @MyParameter
)
AS
SET NOCOUNT ON

--Do something
--Do something using @SomeVariable
SET NOCOUNT OFF
RETURN 0
GO

Не могу, потому что @SomeVariable умирает вместе с партией, которой он принадлежит, а myProcedure требует свою собственную партию. Очевидно, я мог бы создать таблицу #temp и добавить туда любые нужные мне значения, но тогда мне пришлось бы выбирать из нее - добавлять код, который, хотя и тривиален, ухудшает читабельность и выглядит глупо, когда все, что мне нужно, - это глобальная переменная. Есть ли лучший способ?

Быть до боли ясным. Я ЗНАЮ, что в SQL Server есть «глобальные переменные», называемые «таблицами» - я упоминал в предыдущем абзаце, что использование #table является возможным решением, так же как и использование реальной постоянной таблицы. То, что я ищу здесь, - это, скорее, глобальная константа, которую я могу использовать в любом месте данного скрипта, а не глобальная переменная - так что мы все можем перестать намочить наши штаны о пороках глобальных переменных.

Ответы [ 6 ]

5 голосов
/ 27 января 2010

Оператор GO, который не является частью спецификации языка SQL, является разделителем пакетов. Ваши локальные переменные относятся к пакету. Таким образом, они выходят за рамки заявления GO. Я думаю, что ваша единственная альтернатива - это то, что вы описали.

4 голосов
/ 27 января 2010

Непонятно, почему хранимый процесс зависит от вашего глобала в вашем примере набора из двух пакетов.Я вижу две основные возможности: либо SP имеет зависимость от глобального в момент создания (т. Е. Генерация кода - вариант 1), либо SP имеет зависимость во время выполнения от глобального (то есть вы должны выбирать между параметризацией - случай 2) илиСамоконфигурирование - Case3).

В случае зависимости во время выполнения, то, получено ли это из какого-либо места за пределами SP и передано в качестве параметра или внутри SP непосредственно, является основным проектным решением.Выбор того, когда передавать данные в качестве параметра, а когда извлекать данные из таблиц, не совсем точен, все зависит от всех реальных случаев использования в системе.

Случай 1 - Генерация кода:

DECLARE @SomeVariable int 
SET @SomeVariable = 'VALUE' 
  FROM someTable 
--do stuff with @SomeVariable 
GO 

DECLARE @sp as varchar(MAX)

SET @sp = '
CREATE PROCEDURE myProcedure -- I would actually name this myProcedure_ + CONVERT(varchar, @SomeVariable), since each proc generated might function differently
( 
  @MyParameter 
) 
AS 
SET NOCOUNT ON 
DECLARE @SomeVariable AS int -- This is going to be an initialized local copy of the global at time of SP creation
SET @SomeVariable = ' + CONVERT(varchar, @SomeVariable) + '

--Do something 
--Do something using @SomeVariable 
SET NOCOUNT OFF 
RETURN 0 
'
EXEC(@sp) -- create the procedure dynamically

Executing the producedure normally as EXEC myProcedure or EXEC myProcedure_1, etc.

Случай 2 - Параметризация:

DECLARE @SomeVariable int 
SET @SomeVariable = 'VALUE' 
  FROM someTable 
--do stuff with @SomeVariable 
GO 

CREATE PROCEDURE myProcedure 
( 
  @MyParameter 
  ,@SomeVariable int
) 
AS 
SET NOCOUNT ON 

--Do something 
--Do something using @SomeVariable 
SET NOCOUNT OFF 
RETURN 0 
GO 

Теперь, когда вызывается myProcedure, ему всегда должен передаваться параметр @SomeVariable.Это рекомендуется, когда вы регулярно вызываете одного и того же SP с другой параметризацией

Случай 3 - Конфигурация:

DECLARE @SomeVariable int 
SET @SomeVariable = 'VALUE' 
  FROM someTable 
--do stuff with @SomeVariable 
GO 

CREATE PROCEDURE myProcedure 
( 
  @MyParameter 
) 
AS 
SET NOCOUNT ON 

--Do something 
DECLARE @SomeVariable int 
SET @SomeVariable = 'VALUE' 
  FROM someTable 

SET NOCOUNT OFF 
RETURN 0 
GO 

Теперь, когда вы выполняете EXEC myProcedure, вам нужно убедиться, что конфигурация былаустановить в таблице.Этот сценарий рекомендуется для медленно меняющихся вариантов конфигурации.В этом случае вы можете обернуть инициализацию @SomeVariable в UDF со скалярным значением, чтобы каждый раз, когда одна и та же конфигурация использовалась в разных SP, все они вызывали один и тот же UDF, что освобождает вас от необходимости изменять соглашения в таблице конфигурации.(в любом случае, вы не предоставляете своим пользователям разрешение SELECT для своих таблиц, верно?), и если UDF необходимо начать варьироваться в зависимости от пользователя или аналогичного, у вас теперь есть контрольная точка, которая обеспечивает согласованность, разрешения и соглашения о вызовах интерфейса:

DECLARE @SomeVariable int 
SET @SomeVariable = dbo.udf_Global(username, session, etc.)
--do stuff with @SomeVariable 
GO 

CREATE PROCEDURE myProcedure 
( 
  @MyParameter 
) 
AS 
SET NOCOUNT ON 

--Do something 
DECLARE @SomeVariable int 
SET @SomeVariable = dbo.udf_Global(username, session, etc.)

SET NOCOUNT OFF 
RETURN 0 
GO 
1 голос
/ 27 января 2010

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

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

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

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

1 голос
/ 27 января 2010

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

Если вам просто нужна переменная, которую вы используете в одной процедуре несколько раз, вы включаете ее в определение процедуры.

CREATE PROCEDURE myProcedure 
( 
  @MyParameter 
) 
AS 
SET NOCOUNT ON 

DECLARE @SomeVariable int 
SET @SomeVariable = 'VALUE' 
  FROM someTable 
--do stuff with @SomeVariable 

--Do something 
--Do something using @SomeVariable 
SET NOCOUNT OFF 
RETURN 0 
GO 

И если вам нужна хорошая инкапсуляция логики, на которую вы можете ссылаться удобным способом, тогда вам может потребоваться скалярная пользовательская функция (UDF).

0 голосов
/ 27 января 2010

Как насчет создания таблицы, называемой чем-то вроде dbo.Configuration, в которой вы можете хранить кучу значений, извлекая их, когда вам нужно? Это будет не более одной или двух страниц, поэтому такой быстрый доступ, вероятно, все время будет храниться в оперативной памяти, и вы сможете погрузиться в него из любого места.

0 голосов
/ 27 января 2010

Глобальная переменная - плохая практика на любом языке программирования. Почему бы просто не передать переменную в качестве параметра в хранимой процедуре.

CREATE PROCEDURE myProcedure
(
  @MyParameter,
  @SomeVariable  -- the global variable
)
AS
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...