T-SQL Global / Shared Data - PullRequest
       27

T-SQL Global / Shared Data

0 голосов
/ 05 марта 2009

При написании хранимых процедур TSQL мне хочется централизовать / нормализовать некоторые части кода. Например, если у меня есть запрос, подобный этому:

SELECT * FROM SomeTable WHERE SomeColumn IN (2, 4, 8)

В таких случаях я хотел бы поместить (2,4,8) в какое-то место вне процедуры, которое я мог бы использовать в другом запросе позже - чтобы избежать повторения. Есть ли встроенный способ сделать это? Что было бы действительно здорово, так это если бы я мог разбить на части целые куски кода SQL, например части предложения WHERE, и использовать их в других запросах, но я сомневаюсь, что это возможно.

Спасибо.

Ответы [ 4 ]

2 голосов
/ 05 марта 2009

Я часто хотел подобную вещь, но она специально не существует. Вот несколько вещей, которые вы можете делать.

Вариант 1

То, что мы сделали, - это использование пользовательских функций (UDF) для сбора того, что вы могли бы назвать глобальными переменными.

Вы можете вызывать UDF-строку внутри запроса, что делает его действительно полезным.

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

select * from clientNodes where serverName = dbo.SOME_SERVER_NAME()

Вариант 2

Это более очевидно, но стоит отметить. Сохраняйте свои значения в таблице поиска и ссылайтесь на них по идентификатору. Идентификатор не изменится, но значение, к которому он относится, может. Используя пример, как указано выше, но для этой опции:

Table: Servers
Columns: ServerID, ServerName

declare @serverName varchar(50)
select @serverName = ServerName from Servers where ServerID = 1

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

Надеюсь, это поможет! Ian

0 голосов
/ 05 марта 2009

Да - использовать таблицу или представление. SomeColumn, являющийся IN (2, 4, 8), должен как-то иметь значение для ваших данных, поэтому смоделируйте его таким образом. Дайте ему осмысленное имя, и вы сможете использовать его самостоятельно или присоединиться к другим запросам. Зачем хоронить его в UDF или что-то подобное?

Например, если SomeColumn был State, а значения ('FL', 'GA', 'SC') были вашими юго-восточными территориями, то вместо распространения:

 SELECT * FROM SomeTable WHERE State IN ('FL', 'GA', 'SC')

повсюду, просто создайте столбец Territory и покончите с этим.

Повторное использование статического предложения WHERE - это еще одна таблица или атрибут (ака понятие), только начинающий выходить.

0 голосов
/ 05 марта 2009

Обычно вы создаете ПРОСМОТР для того, что вы пытаетесь достичь.

Сначала создайте функцию, которая возвращает значения SomeColumn 2, 4, 8

create function fnSomeTableFilters()
returns @Result table ( ID int not null )
as

begin
    insert  @Result(ID)
    select 2
    union select 4
    union select 8

    return
end
GO

Теперь создайте представление, которое фильтрует 2,4,8

create view vwFilteredSomeTable
as
select * from SomeTable where SomeColumn in (select ID from dbo.fnSomeTableFilters())

Наконец, ваш запрос становится

SELECT * FROM vwFilteredSomeTable

Обязательно дайте вашему представлению осмысленное имя

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

create view vwActiveSites
as
    select  ...
    from    Sites S
    where   S.Active = 1

Прелесть здесь в том, что все ваши запросы, использующие vwFilteredSomeTable , не нуждаются в изменении. Если вам нужно фильтровать с другим значением, нужно изменить только fnSomeTableFilters

0 голосов
/ 05 марта 2009

В SQL Server 2005 вы можете использовать табличную функцию.

например:.

SELECT ... FROM SomeTable INNER JOIN SomeFunction() F ON SomeTable.SomeColumn = F.Id

...

CREATE FUNCTION SomeFunction()
RETURNS @IdTable TABLE (Id INT)
AS
RETURN
(
    SELECT 2 Id
    UNION ALL
    SELECT 4 
    UNION ALL
    SELECT 8
)

Чаще всего вы можете передать значения в качестве аргумента хранимой процедуре. Вы можете сделать это в виде строки через запятую. Например.

EXEC MyProcedure('2,4,8')

...

CREATE PROCEDURE MyProcedure
(
   @IdString AS VARCHAR(MAX)
)
AS
BEGIN
    SELECT ... FROM SomeTable INNER JOIN SomeFunction(@IdString) F ON SomeTable.SomeColumn = F.Id
END

...

CREATE FUNCTION dbo.SomeFunction
(
  @IdString VARCHAR(MAX)
)
RETURNS @IdTable TABLE (Id INT)
AS
BEGIN
    DECLARE @CommaIndex INT, @TotalLength INT, @StartIndex INT, @Id VARCHAR(10)
    SET @TotalLength=LEN(@IdString)
    SET @StartIndex = 1

    WHILE @StartIndex <= @TotalLength
    BEGIN
        SET @CommaIndex = CHARINDEX(',', @IdString, @StartIndex)
        IF @CommaIndex > 0
        BEGIN
            SET @Id = SUBSTRING(@IdString, @StartIndex, @CommaIndex-@StartIndex)
            SET @StartIndex = @CommaIndex + 1
        END
        ELSE
        BEGIN
            Set @Id = SUBSTRING(@IdString, @StartIndex, @TotalLength-@StartIndex+1)
            SET @StartIndex = @TotalLength+1
        END
        INSERT INTO @IdTable
        (Id)
        VALUES
        (CAST(@Id AS INT))
    END

    RETURN
END
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...