Использование Microsoft Query и ODBC для SQL Server, сложный запрос - PullRequest
0 голосов
/ 19 ноября 2010

У меня есть представление в SQL Server, которое несколько похоже на следующий пример.

         SELECT * 
           FROM PEOPLE
LEFT OUTER JOIN (SELECT ID 
                   FROM OTHER_TABLE 
                  WHERE SOME_FIELD = 'x' 
                     OR SOME_FIELD = 'y' 
                     OR SOME_FIELD = 'z') AS PEOPLE_TO_EXCLUDE ON PEOPLE.ID = PEOPLE_TO_EXCLUDE.ID
          WHERE PEOPLE_TO_EXCLUDE.ID IS null

хлопот:

Я вполне способен добавлять и изменять "OR SOME_FIELD = 'w'" бесчисленное количество раз. Тем не менее, я делаю это представление для пользователя, чтобы подтянуть в Excel через ODBC. Пользователь должен иметь возможность изменять внутренний выбор по своему вкусу, чтобы соответствовать тому, что он ограничивает в это время дня / недели / месяца / года / и т. Д. Мне нужно сделать это таким образом, чтобы она могла легко ограничить SOME_FIELD.

У кого-нибудь есть предложения, как этого добиться? В идеале я мог бы дать ей представление, которое она могла бы поместить в список значений, разделенных запятыми, которых SOME_FIELD не может быть. Поскольку в OTHER_TABLE у людей может быть несколько строк, я не могу просто ограничить ее ограничение этой таблицей. Например, кто-то может иметь SOME_FIELD = 'x', но также может иметь строку в таблице, где SOME_FIELD = 's'. Этот человек должен быть исключен, потому что у него есть «х», хотя у них также есть «х». Вот почему необходим внутренний отбор.

Спасибо за вашу помощь.

1 Ответ

2 голосов
/ 19 ноября 2010

Не создавайте запросы для пользователей EXCEL, они всегда их нарушают, и тогда вам нужно их отлаживать. Вместо этого создайте хранимую процедуру, передайте в CSV. В хранимой процедуре разбейте CSV с помощью функции split и присоединитесь к ней. У пользователя будет только EXCEL-запрос, такой как:

EXEC YourProcedure 'x,y,z'

В результате они не прервут запрос.

Чтобы помочь с функцией разделения, см .: "Массивы и списки в SQL Server 2008 с использованием табличных параметров" Эрланда Соммарского , тогда есть много способов разделения строки в SQL Server. В этой статье рассматриваются плюсы и минусы практически каждого метода:

Вам необходимо создать функцию разделения. Вот как можно использовать функцию разделения:

SELECT
    *
    FROM YourTable                               y
    INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value

Я предпочитаю подход с использованием таблиц чисел для разделения строки в TSQL , но существует множество способов разделения строк в SQL Server, см. Предыдущую ссылку, в которой объясняются преимущества и недостатки каждого из них.

Чтобы метод таблицы чисел сработал, вам необходимо выполнить однократную настройку таблицы, которая создаст таблицу Numbers, содержащую строки от 1 до 10000:

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Numbers
    FROM sys.objects s1
    CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)

После настройки таблицы чисел создайте эту функцию разделения:

CREATE FUNCTION [dbo].[FN_ListToTable]
(
     @SplitOn  char(1)      --REQUIRED, the character to split the @List string on
    ,@List     varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN 
(
    SELECT
        ListValue
        FROM (SELECT
                  LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue
                  FROM (
                           SELECT @SplitOn + @List + @SplitOn AS List2
                       ) AS dt
                      INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
                  WHERE SUBSTRING(List2, number, 1) = @SplitOn
             ) dt2
        WHERE ListValue IS NOT NULL AND ListValue!=''
);
GO 

Теперь вы можете легко разбить строку CSV на таблицу и присоединиться к ней:

Create Procedure YourProcedure
@Filter VARCHAR(1000)
AS
SELECT 
    p.* 
    FROM PEOPLE  p
        LEFT OUTER JOIN (SELECT 
                             o.ID 
                             FROM OTHER_TABLE o
                                 INNER JOIN (SELECT 
                                                 ListValue 
                                                 FROM dbo.FN_ListToTable(',',@Filter )
                                            ) f ON o.SOME_FIELD=f.ListValue
                        ) x ON p.ID=x.ID
    WHERE x.ID IS null
GO
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...